SQLArchemyを使ったアプリケーションで↓なコードがあった(詳細は割愛)
(age,) = db_session.query(User.age).filter(User.id == input.id).one()
右辺がUser.age
をラップしたなにかなのはわかるんだけど、左辺がよくわからない
これと似たようなもので、Scalaではdestructuring bindingというのがあって、
scala> case class User(age:Int, name:String) defined class User scala> val user = User(38, "Valentino Rossi") user: User = User(38,Valentino Rossi) scala> val User(age, _) = user age: Int = 38
のように、右辺のタプルを展開して、左辺の変数に代入される
これと同じことなんだろうと思ったんだけど、左辺でage
以外を握り潰しているっぽく見える書き方がよくわからない
(age,)
のカンマで終わってるのが、Scalaでいうval User(age, _)
のワイルドカードのような働きをしている?
でも、これだと
>>> user = (38, "Valentino Rossi") >>> (age,) = user Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: too many values to unpack (expected 1)
となって、握りつぶせていない
よくよく調べてみると、これはunpacking assignmentと呼ばれるもので、右辺がリストなどのコレクションの場合、左辺にカンマ区切りで変数を並べると、左辺の各変数に対応する順で右辺の値が代入されるようだ
そして、今回のケースで混乱の素になったのが、左辺は単要素タプルだということ
Pythonのリファレンスでタプル型を確認すると、
3. データモデル — Python 3.6.3 ドキュメント
タプル型 (tuple)
タプルの要素は任意の Python オブジェクトです。二つ以上の要素からなるタプルは、個々の要素を表現する式をカンマで区切って構成します。単一の要素からなるタプル (単集合 'singleton') を作るには、要素を表現する式の直後にカンマをつけます (単一の式だけではタプルを形成しません。これは、式をグループ化するのに丸括弧を使えるようにしなければならないからです)。要素の全くない丸括弧の対を作ると空のタプルになります。
とあり、今回のケースではage
が単一の要素で、その直後にカンマがつくことでタプルになっている。そして、右辺も単要素のタプルであり、その値がage
に代入されているということ
左辺でage
以外を握り潰すことなんかしていなく、そもそも握り潰す値がなかったんや!
なので、右辺が2要素からなるタプルの場合、ValueError
となった
仕組みは理解できたからいいんだけど、こういうケースがggりずらくてつらくない?おれはつらい