2016-10-25 7 views
11

私は巨大なlist/tuple*argsを介して機能させるために渡す必要があります。関数呼び出しで* argsの実行モデルとは何ですか?

def f(*args): # defined in foreign module 
    pass 

arguments = tuple(range(10000)) 
f(*arguments) 

そして、関数呼び出しで何が起こるのだろうか。

argumentsはどのような位置変数にも似ています:それを保存し、ボディの実行中にオンデマンドでアクセスできますか?または、体の実行の前であっても、位置引数を拡張しても、argumentsまで繰り返しますか?それとも別のことですか?

+1

'arguments'はリストですが、' args'はタプルです。はい、iteration *には*があります。ここで '引数'をタプルとすることは役に立ちません。 –

+0

あなたはそれが反復されているかどうかを知らせるカスタムオブジェクトを書くことによってそれをテストすることができます。 – jonrsharpe

+1

したがって、 'arguments'がタプルであっても、この繰り返しはとにかく起こりますか? – Ormazd

答えて

8

はい、*arguments呼び出し構文は、2つの理由のために、反復可能なargumentsを反復するがあります

  • をあなたがリストに渡しているが、関数内*args可変サイズ引数がありますタプル。要素はここでコピーする必要があります。

  • 呼び出し構文はあなたの代わりに、実際の位置引数を持っている、または*varargs変数に加えて、可能性のある機能、のために使用可能でなければなりません。

    たとえば、関数の署名がdef f(foo, *args):の場合、最初の要素は別々に渡されなければなりません。原則

    、CPythonのは、タプルのすべての値が*varargs引数にfunction(*tupleargs)端を上にしてコールに使用される場合のために最適化し、そのタプルを再使用することができます。しかし、これは実際にはすべてであり、それはと共通であり、誰もこれを行っていません。

**kwargs呼び出し構文のために、可変性の追加の課題は、オブジェクトを共有することは本当に悪いアイデアを使用しますことに注意してください。 にはがあります。そうでないと、関数またはが呼び出され、他の参照に反映された変更でその辞書が変更される可能性があります。

13

発電機を使用して簡単なテスト:

def gen(): 
    print('Yielding 1') 
    yield 1 
    print('Yielding 2') 
    yield 2 
    print('Yielding 3') 
    yield 3 


arguments = gen() 
def f(*args): 
    pass 

f(*arguments) 
# Yielding 1 
# Yielding 2 
# Yielding 3 

あなたは出力から見ることができるように、技術的に、あなたが使用して、個々の引数としてのiterableを渡すためのPythonを言っているので、*argumentsを渡すと、実際には、全体のiterableを解凍します*argumentsという構文です。関数の定義でも*argsを使用しているため、Pythonは引数を再びタプルにパックします。

だから、ここでもう一度梱包するだけでリストを開梱しています。これを避けるには、リストを直接渡すだけです。

+4

関数内の '* args'変数で値が終わるので、呼び出しで使用されたときに*タプル*を反復しない*可能性*があります(例えば' *(1、2、3) 'など) Pythonはそのような最適化を行いません。 –

関連する問題