タイトルのまんまの記事ですが、NukeなどでPythonを書くときの注意メモ。Pythonのグローバル変数は関数内からでも簡単にアクセスできちゃうのですが、ちょっといい加減なコード書くとすぐに変数のスコープのせいで意図しない結果になったりするので注意。
まずすごく簡単なコードを例にあげてみます。
thisval = 1
def getval():
onval = thisval
print onval
getval()
Nukeでこれを実行すると、当たり前ですが「# Result: 1」を返します。
thisval = 1
def getval():
thisval = 100
retuen thisval
print getval() + thisval
これの結果は「# Result: 101」。関数内でのthisvalはローカルスコープなので、そこで代入してもグローバル変数のthisvalには影響しません。これを以下のように変更するとエラーが出ます。
thisval = 1
def getval():
onval = thisval
thisval = 100
return thisval
print getval() + thisval
# Result: Traceback (most recent call last):
File "<string>", line 6, in <module>
File "<string>", line 3, in getval
UnboundLocalError: local variable 'thisval' referenced before assignment
これは関数内で「thisval = 100」の前に「onval」がグローバルのthisvalを参照しているために、その後の「thisval」代入時に、関数内でローカル変数の宣言を使用として失敗してます。以下のようにglobal変数として関数内で宣言してやれば関数内からグローバル変数に代入できます。
thisval = 1
def getval():
global thisval
onval = thisval
thisval = 100
return thisval
print getval() + thisval
# Result: 200
最後のprintで参照する順を逆にすると、関数内で代入されるタイミングも変わります。当たり前ですが...
thisval = 1
def getval():
global thisval
onval = thisval
thisval = 100
return thisval
print thisval + getval()
#Result: 101
いかにもトラブルの原因になりそうですよね...ええ、なるんですよ、実際。
というわけでグローバル変数を直接関数内から参照したり代入したりするのは極力避けたいところです。グローバル変数はread onlyくらいに考えておくか、何か接頭文字を付けるとかして管理しておくくらいの方がいいかと思ってます。
最初の例にもどって見ると、このコードはグローバル変数に関数内からアクセスするのではなく引数として渡してやるのがトラブル回避の意味では正解かと...
thisval = 1
def getval(val):
onval = val
print onval
getval(thisval)
これはPythonに限ったことではなくてAEのJavaScriptなんかでも同じことが言えるんだけど、Pythonの場合は「ここで宣言した」っていうのが文字から見えて来ないだけに注意が必要かなと思います。
エキスパートPythonプログラミング
posted with amazlet at 11.04.24
Tarek Ziade
アスキー・メディアワークス
売り上げランキング: 18775
アスキー・メディアワークス
売り上げランキング: 18775