Python関数引数に関する考察

どうしても訳が分からないことがありました 要するに Pythonでの関数の名前空間が分かっていなかったのです 特にリストを引数で渡す場合です ここには、「リストの場合関数内部でグローバル変数を変化させれば、関数から出てもその変化は引き継がれる」というように記載されています

ところがこのテストプログラムではそのようにならないのです

from bitstring import ConstBitStream
from defTag import jpegTag

DHTs = []
print("DHTs: {}".format(id(DHTs))) #A

def searchTags(DHTs):
    xa = ConstBitStream(filename='xa1.dcm') #B
    print("DHTs: {}".format(id(DHTs)))
    DHTs = list(xa.findall(jpegTag['DHT'], bytealigned=True))
    print("DHTs: {}".format(id(DHTs))) #C


if __name__ == '__main__':
    searchTags(DHTs)
    print("DHTs = {0}".format(DHTs))

この場合、出力はA, B, Cの値(アドレス)が出力され、最後に゜カラリスト[]が出力されます そして興味深いことには A == Bであるにもかかわらず B != Cなのです つまり関数内で新たに変数が作成された訳です これは意図する動作ではありません そこで調べるとここに詳細に記載がありました これによれば、関数内で変数に変更を行えば、関数内の変数とグローバル空間の変数は同じアドレスを参照するようです そこで以下のテストを書きました

from bitstring import ConstBitStream
from defTag import jpegTag

DHTs = []
print("#A: {}".format(id(DHTs))) #A

def searchTags(DHTs):
    xa = ConstBitStream(filename='xa1.dcm')
    print("#B: {}".format(id(DHTs))) #B
    DHTs.extend(list(xa.findall(jpegTag['DHT'], bytealigned=True)))
    print("#C: {}".format(id(DHTs))) #C


if __name__ == '__main__':
    searchTags(DHTs)
    print("DHTs = {0}".format(DHTs))

これで走らせてみると当方での出力は以下の通りでした

#A: 4441990408
#B: 4441990408
#C: 4441990408
DHTs = [10352, 5398688, 6469600, 11807904, 17146912, 22482576, 27843824, 33224096, 38652544, 44104704, 49597104, 55103072, 60640800, 66181296, 71753056, 77315744, 82880880, 88431792, 93978432, 99509264, 105038752, 110572944, 116110208, 121646512, 127184304, 132726336, 138267056, 143811248]

これで意図した通りとなりました 要するに関数内で値を受け渡したいリストに変更を加えることにより関数内変数とグローバル変数が同じアドレスを参照したことにより参照渡しが実現された訳です

投稿者: (KAMAKURA & SAPPORO)Dr_Radialist

Expert Interventional Cardiologist and Amateur Computer Programmer

「Python関数引数に関する考察」への2件のフィードバック

  1. お疲れ様です。

    記事を見て、
    pythonのスコープの情報を見たのですが、
    なかなか他の言語同様、難しいですね。
    むかしBASICのようにすべてグローバルでなければ、
    コピー渡しが良い気がします。
    明示的にglobalとして扱うのでなければ、
    コピーが良いと思います。
    辞書とかは、深いコピーとか、浅いコピーとか、面倒くさいですしね。

    1. そうなんです 未だまだ理解したとは言い難いのです とにかく Pythonでは Global変数の扱いが他の言語と少し異なるような印象です
      具体的には、XA fileをまず読み込んで、メモリー上のそれを各関数で使いまわしたいのですが、どのようにこのXA objectを効率よく受け渡すべきか悩んでいます 本当は C/C++にような参照渡しが効率的だと思うのですが、どうやらPythonでは標準的に値渡しのようです 何かヒント下さい

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です