PythonでJavascriptの様な分割代入

概要

javascriptでよく用いられる、分割代入によって好きな引数をオブジェクトから取得する方法をpythonでも実装する。
こんな感じのやつ。

const f = ({ a }) => console.log(a)
const d = { a: 1, b: 2 }

f(d)
// => 1

動機

pythonも一応関数型をサポートしている。
関数型チックに書こうとすると、一つのglobalなstateのようなdictionaryを中心に組み立てると便利な場面があり、この実装をやりたくなった。

書くこと

  1. pythonの引数における分割代入のやり方
  2. 分割代入において、好きなkeyのデータだけをdictionaryから取得する方法

書かないこと

  1. 変数代入時の分割代入(引数への分割代入のときとほぼ同じ)

必要な知識

  1. pythonの分割代入についての簡単な知識
  2. pythonのキーワード引数についての知識

javascriptの分割代入における引数渡しとそのメリット

reactというフレームワークを例にjavascriptの分割代入について説明する。
reactはUIのパーツをコンポーネントという関数orクラスに分割し、その中で親となるコンポーネントから子にデータを伝達していくことで、画面遷移などを実現していくフレームワークである。
例えば、親がuserがログインしているかどうかの情報とそれ以外のデータを保持しているとする。

{ login: true, other: "other", ... }

また、子はログインしているかだけを見て、表示を変える(例えば、”ログイン”という文字を表示するか”サインアウト”という文字を表示するか)という状況だとする。
つまり必要なデータはこれだけ。

{ login: true }

その時、親は自分の保持するデータをそのまま子に渡して、子はそこから好きなデータだけを取得するようにすると、親と子の結合度が下がり好ましい。
このように親から子に渡るデータのことをpropsなどと呼ぶ。

teset.png

これを実現するために使用されるテクニックが分割代入である。

pythonでの分割代入の基本

pythonでの分割代入は*を用いて行う。

配列の分割代入

*を使う。

def ar_print(*args):
    print(args)

a = [1, 2, 3]

ar_print(*a)
# => (1, 2, 3)

配列など(厳密にはiteratableなオブジェクト)の前に*をつけて、上のような関数に渡すとargsにタプルとなって渡る。

辞書の分割代入

**を使う。

def dic_print(**kwargs):
    print(kwargs)

d = {a: 1, b: 2}

dic_print(**d)
# => {a: 1, b: 2}

kwargsに辞書が渡る。

分割代入を用いた引数の選択

辞書の分割代入とキーワード引数を併用して実現する。

def print_a_value(*, a, **rest):
    print(a)

    return rest

d = {a: 1, b: 2}

rest = print_a_value(**a)
# => 1

print(rest)
# => {b: 2}

*後ろの引数はキーワード引数になる。
また、restは可変長引数であるため、余った辞書の要素(ここでいうと{b: 2})の受け皿となる。

このように引数を渡される関数側からデータを選択することが可能になる。

まとめ

javascriptは関数型+すべてがオブジェクト(辞書みたいなやつ)なせいでこのテクニックは頻繁に使用する。
pythonのようなオブジェクト指向言語ではあまり辞書ベースのデータ保持オブジェクトを使用しない(というか使用しないほうがいい)なため、このテクニックを使用することはあまりない。
まあ関数型チックな構成にするときは使うとハッピーになることがあるかもしれない。

PySpark on AWS Glue PythonのEllipsis(…)とtype hints PythonとNewType
View Comments
There are currently no comments.