- 2009/03/13 23:06
- Python
Pythonでは可変長の引数はこうやって受けます
def hoge(*args, **kwargs):
pass
argsというlist tuple型の変数に、キーワード無しの引数が、kwargsというdict型の変数にキーワード付きの引数が入ります。
※*argsはlist型だと思ってました、表示見たら違いますね。サーセン。直しときました。
名前は大体args, kwargs、って感じみたいです。他の名前でもOKだと思いますが。
実際にやってみると、こうなります。
>>> def hoge(*args, **kwargs):
... print args
... print kwargs
...
>>> hoge(1, 2, 3, ['a', 'b', 'c'], name='my_name', data='100')
(1, 2, 3, ['a', 'b', 'c'])
{'data': '100', 'name': 'my_name'}
キーワード付き引数はキーワード無し引数の前に書け!!ってエラーで何度か怒られた、って記憶をお持ちの方も多いと思いますが、これとも関係あるのかもと思います。
では突然ですが問題です。
>>> def hoge(*args, **kwargs):
... foo(args, kwargs)
...
>>> def foo(*args, **kwargs):
... print args
... print kwargs
...
こんな感じで関数hogeとfooが宣言されていたとします。
この場合、以下を実行したら、どうなるでしょうか。
>>> hoge(1, 2, 3, ['a', 'b', 'c'], name='my_name', data='100')
結果はこうなります。
>>> hoge(1, 2, 3, ['a', 'b', 'c'], name='my_name', data='100')
((1, 2, 3, ['a', 'b', 'c']), {'data': '100', 'name': 'my_name'})
{}
でーん。
あれ?って思いましたか。
そりゃそうだろ、って思いましたか。
僕はこういうのやる時って、そもそもどうやるんだ?と思ってるだけ思ってて、実際にここで引っかかったことはありませんでした。
というかもっと古典的に必要な引数を全部宣言してそのまま渡してましたwwwwwww
うぇwwwwwwwwwwwwwwwwwwww
これが困るのは、例えばクラスの__init__なんかですかね。
何かのクラスを継承していて、でも親クラスのコンストラクタを呼びたい場合。
でも親クラスでは*args, **kwargsになっている!どうすれば!!
そういう場合はこうします。
>>> def hoge(*args, **kwargs):
... foo(*args, **kwargs)
...
>>> def foo(*args, **kwargs):
... print args
... print kwargs
...
>>> hoge(1, 2, 3, ['a', 'b', 'c'], name='my_name', data='100')
(1, 2, 3, ['a', 'b', 'c'])
{'data': '100', 'name': 'my_name'}
はい期待通りっ。
つまり*と**は、どうなってんのかわかりませんが、
可変長引数を取るだけではなく、list tupleとdictの展開も行えるようになっているようです。
詳しく内部でどうなってるのか知ってる方がいたら逆に教えて欲しいです。
僕はRubyのスクリプトかなんかで、この記述をたまたま見かけて(そもそもRuby自体たまたま目にして)、なんとなく気になって見てみたらこういうことだった、ってことみたいでした。
で、今回これに関して書いたのは、Mayaでスクリプトを書いている際に実際に活躍したからです。
どういう状況だったかというと、
・checkBoxGrpのchangeCommand(-cc)に、それぞれ別の関数を与えたい。
・ただしcheckBoxGrpでは-cc1, -cc2, -cc3…のように、数字を伴う引数を必要とする。
・つまりこういう感じで実行したい
cmds.checkBoxGrp(ctlname, e=True, 'cc%d' % index = func)
わかりづらいですが、cc1とハードコードするのではなく、ループの中でダイナミックに1とか2とかをいれてやりたかったのです。
でも、これは多分OUTなはず。(実際には試してないのでわからない)
実際出来たとしても見た目に美しくないから却下!!!(ぇー
で、どうやったかといいますと、ここで**kwargsなのです。
kwargs = {}
kwargs['e'] = True
kwargs['cc%d' % index] = func
cmds.checkBoxGrp(ctlname, **kwagrs)
これです。
これであとはfuncをループ内で適宜設定してやれば良いと言う訳です。
で、これによっていろいろと物事が嬉しい感じで進んだので、書いてみました。
長々失礼しました&ややこしくてすみません&このブログデザインだとコードが強調表示されないとかでちょっと見づらいですね。
近日中にデザイン変更検討中です。
ソースコードが見やすいやつがいいです。
ちょい調べときます。
長々お付き合いいただいてありがとうございました:P
- Newer: Houdini 10
- Older: [Houdini] Shutter Test
Comments:4
- inagaki 2009/03/15
ディクショナリをそのままキーワード引数にできちゃうわけですね。なんとなく便利そうですね。ただ、引数に何が入ってるかわかりにくくなるので、コメントとかでちゃんとフォローしないと駄目そうですね。
- tai 2009/03/16
>inagakiさん
> ディクショナリをそのままキーワード引数にできちゃうわけですね。なんとなく便利そうですね。
お察しの通り、今回は何となく便利でしたwwwwww> ただ、引数に何が入ってるかわかりにくくなるので、コメントとかでちゃんとフォローしないと駄目そうですね。
そうですね。
その後の処理で受け取るキーワードが決まってるとかならまぁ適当にながしちゃってもいいと思うんですが(意味のないパラメータを許せるなら:P)、プログラム的に読み易くはないと思うし、おそらく大体自分の美意識に引っかかると思うのでwww、その辺はきっちりしといた方がいいのかも、と思います。関数デコレータ(使ったことはないですが)なんかをうまく使おうと思ったら結構便利なのでは?なんて思ったりします。
- hohehohe2 2009/03/17
なるほどねー・・・
気がつきませんでした。>> def f(a=0, b=1, c=2):
… print a, b, c
…
>>> f(**{“b”:100})
0 100 2こんなことができるんですね。
うん、便利だ。- tai 2009/03/18
>hohehohe2さん
使いどころはいろいろあるのかな、と。
パラメータをゴリゴリ渡すよりも見た目もスッキリしますし。
Trackbacks:0
- Trackback URL for this entry
- http://blog.taikomatsu.com/2009/03/13/python-%e5%8f%af%e5%a4%89%e9%95%b7%e5%bc%95%e6%95%b0%e3%81%82%e3%82%8c%e3%81%93%e3%82%8c/trackback/
- Listed below are links to weblogs that reference
- [Python] 可変長引数あれこれ from memlog