14

関数の引数を渡すオブジェクトスタイルによるPythonの呼び出しの概念を理解しているかどうかはわかりません(ここで説明されていますhttp://effbot.org/zone/call-by-object.htm)。この概念を明確にするのに十分な例がないようです(または私のgoogle-fuはおそらく弱いです!:D)

この概念を理解するために、この少し工夫されたPythonプログラムを作成しました

def foo( itnumber, ittuple,  itlist, itdict   ):
    itnumber +=1 
    print id(itnumber) , itnumber 

    print id(ittuple)  , ittuple

    itlist.append(3.4)
    print id(itlist)   , itlist

    itdict['mary']  = 2.3
    print id(itdict),    itdict



# Initialize a number, a tuple, a list and a dictionary
tnumber = 1
print id( tnumber ), tnumber 

ttuple  = (1, 2, 3)
print id( ttuple ) , ttuple

tlist   = [1, 2, 3]
print id( tlist ) , tlist

tdict = tel = {'jack': 4098, 'sape': 4139}
print '-------'
# Invoke a function and test it
foo(tnumber, ttuple, tlist , tdict)

print '-------'
#Test behaviour after the function call is over
print id(tnumber) , tnumber 
print id(ttuple)  , ttuple
print id(tlist)   , tlist
print id(tdict),  tdict

プログラムの出力は次のとおりです。

146739376 1
3075201660 (1, 2, 3)
3075103916 [1, 2, 3]
3075193004 {'sape': 4139, 'jack': 4098}

---------

146739364 2
3075201660 (1, 2, 3)
3075103916 [1, 2, 3, 3.4]
3075193004 {'sape': 4139, 'jack': 4098, 'mary': 2.3}

---------

146739376 1
3075201660 (1, 2, 3)
3075103916 [1, 2, 3, 3.4]
3075193004 {'sape': 4139, 'jack': 4098, 'mary': 2.3}

ご覧のとおり、渡された整数を除いて、オブジェクトID(私が理解しているようにメモリの場所を参照しています)は変更されません。

したがって、整数の場合、それは(効果的に)値によって渡され、他のデータ構造は(効果的に)参照によって渡されました。リスト、番号、辞書を変更して、データ構造が変更されたかどうかをテストしてみました。数はリストではなく、辞書はありました。

上記のコードで渡されたデータ構造に応じて、引数の受け渡しの「オブジェクトによる呼び出し」スタイルは双方向で動作するように見えるため、上記の単語を効果的に使用します

より複雑なデータ構造(たとえば、numpy配列など)の場合、参照によって渡される引数と値によって渡される引数を認識するための簡単な経験則はありますか?

4

3 に答える 3

14

主な違いは、Cスタイルの言語では、変数はメモリ内のボックスであり、そこにデータを入れることです。Pythonでは、変数は名前です。

Pythonは、参照による呼び出しでも値による呼び出しでもありません。それはもっと賢明なことです!(実際、私はより一般的な言語を学ぶ前にPythonを学んだので、値による呼び出しと参照による呼び出しは私には非常に奇妙に思えます。)

Pythonには、物事名前があります。リスト、整数、文字列、およびカスタムオブジェクトはすべてのものです。x、、、yz名前です。書き込み

x = []

「新しいもの[]を作り、それに名前を付ける」という意味xです。書き込み

x = []
foo = lambda x: x.append(None)
foo(x)

「名前で新しいもの[]を構築し、名前xで新しい関数(別のもの)を構築し、名前で物fooを呼び出す」fooという意味xです。fooこれで、受け取ったものに追加するだけなので、これは「空のリストにNone追加する」になります。None書き込み

x = 0
def foo(x):
    x += 1
foo(x)

0「名前で新しいものをx構築し、新しい関数を構築し、foo呼び出す」という意味です。内部では、割り当ては「1に名前を変更し、以前の名前に変更する」とだけ言っていますが、それは0のことを変更しません。fooxfoox

于 2012-04-21T20:57:42.770 に答える
10

他の人はすでに良い答えを投稿しています。私が役立つと思うもう1つのこと:

 x = expr

結果を評価exprしてバインドxします。一方で:

 x.operate()

何か x実行するため、それを変更できます(同じ基になるオブジェクトの値が異なります)。

面白いケースには、次のようなものがあります。

 x += expr

これは、 (再バインド)または(変更)のいずれか に変換され、場合によっては非常に特殊な方法で変換されます。x = x + exprx.__iadd__(expr)

>>> x = 1
>>> x += 2
>>> x
3

x整数は不変であるため、リバウンドされました)

>>> x = ([1], 2)
>>> x
([1], 2)
>>> x[0] += [3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> x
([1, 3], 2)

ここx[0]では、それ自体が変更可能であり、インプレースで変更されました。xしかし、Pythonは(のように)それ自体を変更しようとしx.__iadd__ましたが、タプルは不変であるためエラーになりました。しかし、その時までx[0]にすでに変異していた!

于 2012-04-21T21:06:26.113 に答える
7

Pythonの数値、文字列、およびタプルは不変です。拡張割り当てを使用すると、名前が再バインドされます。

他のタイプは単に変更され、同じオブジェクトのままです。

于 2012-04-21T20:58:58.387 に答える