3

Pythonを使用して、Aレベルの学生に参照による呼び出しと値による呼び出しの違いを説明するプログラムを作成しようとしています。変更可能なオブジェクトを変数として関数に渡すことで成功しましたが、ctypes ライブラリを使用しても同じことができることがわかりました。

byref()ctype ライブラリに関数があるのでよくわかりませんが、私の例ではうまくいきませんでした。しかし、それなしbyref()で関数を呼び出すことでうまくいきました!

私の作業コード:

"""
Program to illustrate call by ref
"""

from  ctypes import *  #allows call by ref

test = c_int(56)  #Python call by reference eg address
t = 67            #Python call by value eg copy


#expects a ctypes argument
def byRefExample(x):
    x.value= x.value + 2
    

#expects a normal Python variable
def byValueExample(x):
    x = x + 2
         

if __name__ == "__main__":

    print "Before call test is",test
    byRefExample(test)                
    print "After call test is",test

    print "Before call t is",t
    byValueExample(t)
    print "After call t is",t

質問

通常の Python 変数を渡すと、byValueExample()期待どおりに機能します。関数の引数のコピーはt変更されますが、ヘッダー内の変数は変更tされません。ただし、ctypes 変数テストを渡すと、ローカル変数とヘッダー変数の両方が変更されるため、C ポインター変数のように動作します。私のプログラムは機能しますが、次のbyref()ように使用すると関数が機能しない方法と理由がわかりません。

byRefExample(byref(test))
4

2 に答える 2

2

Python は、「参照渡し」または「値渡し」ではなく、「オブジェクト呼び出し」を使用します。割り当ては、オブジェクトに名前を付けます。

test = c_int(56)
t = 67

testオブジェクトに割り当てられctypes.c_intた名前を内部的に持つ、オブジェクトに付けられた名前です。valueint

tintオブジェクトに付ける名前です。

を呼び出す場合byRefExample(test)、は、によって参照されるオブジェクトxに付けられる別の名前です。ctypes.c_inttest

x.value = x.value + 2

上記は、ctypes.c_intオブジェクトに保存されている「値」の名前を、異なる値を持つまったく新しいオブジェクトに再割り当てします。 は、とという名前で参照される同じオブジェクトの属性であるintため、 は同じ値を参照しています。value ctypes.c_inttestxx.valuetest.value

を呼び出す場合byValueExample(t)、は、によって参照されるオブジェクトxに付けられる別の名前です。intt

x = x + 2

上記は、異なる値を持つ完全に新しいオブジェクト に名前xを再割り当てします。同じオブジェクトを参照しなくなるため、変更は観察されません。元のオブジェクトを引き続き参照します。 intxttint

これはid()、さまざまな時点でのオブジェクトを出力することで確認できます。

from  ctypes import *

test = c_int(56)
t = 67

print('test id =',id(test))
print('t    id =',id(t))

#expects a ctypes argument
def byRefExample(x):
    print('ByRef x',x,id(x))
    print('ByRef x.value',x.value,id(x.value))
    x.value = x.value + 2
    print('ByRef x.value',x.value,id(x.value))
    print('ByRef x',x,id(x))

#expects a normal Python variable
def byValueExample(x):
    print('ByVal x',x,id(x))
    x = x + 2
    print('ByVal x',x,id(x))

print("Before call test is",test,id(test))
print("Before call test is",test.value,id(test.value))
byRefExample(test)                
print("After call test is",test.value,id(test.value))
print("After call test is",test,id(test))

print("Before call t is",t,id(t))
byValueExample(t)
print("After call t is",t,id(t))

出力 (コメント付き):

test id = 80548680
t    id = 507083328
Before call test is c_long(56) 80548680
Before call test.value is 56 507082976
ByRef x c_long(56) 80548680                 # same id as test
ByRef x.value 56 507082976
ByRef x.value 58 507083040                  # x.value is new object!
ByRef x c_long(58) 80548680                 # but x is still the same.
After call test.value is 58 507083040       # test.value sees new object because...
After call test is c_long(58) 80548680      # test is same object as x.
Before call t is 67 507083328
ByVal x 67 507083328                        # same id as t
ByVal x 69 507083392                        # x is new object!
After call t is 67 507083328                # t id same old object.
于 2013-08-09T20:30:15.817 に答える