Python Language
可変スコープとバインディング
サーチ…
構文
- グローバルa、b、c
- 非局所的なa、b
- x =何か#はxを束縛する
- (x、y)= something#はxとyを束縛する
- x + = something#はxをバインドします。同様に他のすべての "op ="
- del x#はxを束縛する
- xは何かの中で:#binds x
- 何かをxとする:#binds x
- ExとExを除く:#ブロック内に#をバインドする
グローバル変数
Pythonでは、関数内の変数は、代入文の左側に表示される場合や、他のバインディングオカレンスが表示される場合に限り、ローカルと見なされます。さもなければ、そのようなバインディングは、グローバルスコープまでの囲み関数で検索されます。これは、代入文が決して実行されなくても当てはまります。
x = 'Hi'
def read_x():
print(x) # x is just referenced, therefore assumed global
read_x() # prints Hi
def read_y():
print(y) # here y is just referenced, therefore assumed global
read_y() # NameError: global name 'y' is not defined
def read_y():
y = 'Hey' # y appears in an assignment, therefore it's local
print(y) # will find the local y
read_y() # prints Hey
def read_x_local_fail():
if False:
x = 'Hey' # x appears in an assignment, therefore it's local
print(x) # will look for the _local_ z, which is not assigned, and will not be found
read_x_local_fail() # UnboundLocalError: local variable 'x' referenced before assignment
通常、スコープ内の代入は、同じ名前の外部変数をすべてシャドウします。
x = 'Hi'
def change_local_x():
x = 'Bye'
print(x)
change_local_x() # prints Bye
print(x) # prints Hi
名前をglobal
宣言すると、スコープの残りの部分では、モジュールのトップレベルで名前への割り当てが行われます。
x = 'Hi'
def change_global_x():
global x
x = 'Bye'
print(x)
change_global_x() # prints Bye
print(x) # prints Bye
global
キーワードは、プログラムのトップレベルではなくモジュールのトップレベルで代入が行われることを意味します。他のモジュールでは、モジュール内の変数への通常のドット付きアクセスが必要です。
要約すると、変数x
が関数に対してローカルであるかどうかを知るためには、関数全体を読む必要があります。
-
global x
が見つかった場合、x
はグローバル変数です -
nonlocal x
が見つかった場合、x
は囲み関数に属し、ローカルでもグローバルでもありません -
x = 5
またはfor x in range(3)
またはその他のバインディングを見つけた場合、x
はローカル変数です - それ以外の
x
は、いくつかの囲みスコープ(関数スコープ、グローバルスコープ、または組み込み関数)に属します。
ローカル変数
関数内で名前がバインドされている場合、デフォルトでは関数内でのみアクセスできます。
def foo():
a = 5
print(a) # ok
print(a) # NameError: name 'a' is not defined
制御フロー構造体はスコープに影響を与えません(例外をexcept
)が、まだ割り当てられていない変数へのアクセスはエラーです:
def foo():
if True:
a = 5
print(a) # ok
b = 3
def bar():
if False:
b = 5
print(b) # UnboundLocalError: local variable 'b' referenced before assignment
共通の結合操作が割り当てあるfor
などのループ、および拡張割り当てa += 5
非局所変数
Python 3はnonlocalという新しいキーワードを追加しました。 nonlocalキーワードはスコープオーバーライドを内部スコープに追加します。 PEP 3104でそれに関するすべてを読むことができます。これは、いくつかのコード例で最もよく説明されています。最も一般的な例の1つは、インクリメントできる関数を作成することです。
def counter():
num = 0
def incrementer():
num += 1
return num
return incrementer
このコードを実行しようとすると、 num変数が最も内側の関数に割り当てられる前に参照されるため、 UnboundLocalErrorが返されます。ミックスに非ローカルを追加しましょう:
def counter():
num = 0
def incrementer():
nonlocal num
num += 1
return num
return incrementer
c = counter()
c() # = 1
c() # = 2
c() # = 3
基本的にnonlocal
は、外部スコープの変数に割り当てることができますが、グローバルスコープは割り当てられません。したがって、 counter
関数でnonlocal
を使用することはできません。なぜなら、グローバルスコープに代入しようとするからです。試してみると、すぐにSyntaxError
得られSyntaxError
。代わりに、ネストした関数でnonlocal
を使用する必要があります。
(ここに示す機能は、ジェネレータを使用して実装する方がよいことに注意してください)。
バインディングの発生
x = 5
x += 7
for x in iterable: pass
上記のステートメントはそれぞれバインディングオカレンスです x
5
示されるオブジェクトにバインドされます。このステートメントが関数内にある場合、 x
はデフォルトで関数ローカルになります。バインディングステートメントのリストについては、「構文」を参照してください。
名前を検索するときにクラススコープをスキップする関数
クラスは定義時にローカルスコープを持ちますが、クラス内の関数は名前をルックアップするときにそのスコープを使用しません。ラムダは関数なので、関数スコープを使って理解が実装されているので、これはいくつかの驚くべき動作につながります。
a = 'global'
class Fred:
a = 'class' # class scope
b = (a for i in range(10)) # function scope
c = [a for i in range(10)] # function scope
d = a # class scope
e = lambda: a # function scope
f = lambda a=a: a # default argument uses class scope
@staticmethod # or @classmethod, or regular instance method
def g(): # function scope
return a
print(Fred.a) # class
print(next(Fred.b)) # global
print(Fred.c[0]) # class in Python 2, global in Python 3
print(Fred.d) # class
print(Fred.e()) # global
print(Fred.f()) # class
print(Fred.g()) # global
このスコープの仕組みになじみのないユーザーは、 b
、 c
、およびe
がclass
を印刷することを期待するかもしれません。
PEP 227から:
クラススコープ内の名前にはアクセスできません。名前は最内周の関数スコープで解決されます。ネストされたスコープのチェーン内でクラス定義が発生すると、解決プロセスはクラス定義をスキップします。
命名とバインディングに関するPythonの文書から:
クラスブロックで定義される名前の範囲は、クラスブロックに限定されます。メソッドのコードブロックには拡張されません。これは、関数スコープを使用して実装されるため、これには内包とジェネレータの式が含まれます。これは、以下が失敗することを意味します。
class A: a = 42 b = list(a + i for i in range(10))
この例では、Martijn Pietersによるこの回答の参照を使用しています。 この参照には、この動作の深い分析が含まれています。
delコマンド
このコマンドには、いくつかの関連した別個の形式があります。
del v
v
が変数の場合、コマンドdel v
は変数をスコープから削除します。例えば:
x = 5
print(x) # out: 5
del x
print(x) # NameError: name 'f' is not defined
del
は束縛の発生であることに注意してください。別の方法で明示的に指定しない限り(nonlocal
またはglobal
を使用して)、del v
はv
を現在のスコープにローカルにします。外部スコープでv
を削除する場合は、del v
ステートメントと同じスコープでnonlocal v
またはglobal v
使用します。
以下のすべてにおいて、コマンドの意図はデフォルトの動作ですが、言語によって強制されません。クラスはこの意図を無効にする方法で記述されるかもしれません。
del v.name
このコマンドは、 v.__delattr__(name)
呼び出しをトリガーします。
意図は、属性name
使用不可にすることです。例えば:
class A:
pass
a = A()
a.x = 7
print(a.x) # out: 7
del a.x
print(a.x) # error: AttributeError: 'A' object has no attribute 'x'
del v[item]
このコマンドは、 v.__delitem__(item)
呼び出しをトリガします。
意図は、オブジェクトv
によって実装されたマッピングにitem
が属していないことです。例えば:
x = {'a': 1, 'b': 2}
del x['a']
print(x) # out: {'b': 2}
print(x['a']) # error: KeyError: 'a'
del v[a:b]
これは実際にv.__delslice__(a, b)
呼び出します。
意図は、上記のものと同様ですが、単一の項目の代わりに項目の範囲であるスライスを使用します。例えば:
x = [0, 1, 2, 3, 4]
del x[1:3]
print(x) # out: [0, 3, 4]
ガベージコレクション#delコマンドも参照してください。
ローカルスコープとグローバルスコープ
ローカルおよびグローバルスコープとは何ですか?
コードのある時点でアクセス可能なすべてのPython変数は、 ローカルスコープまたはグローバルスコープのいずれかにあります 。
説明には、ローカルスコープには現在の関数で定義されたすべての変数が含まれ、グローバルスコープには現在の関数の外部で定義された変数が含まれます。
foo = 1 # global
def func():
bar = 2 # local
print(foo) # prints variable foo from global scope
print(bar) # prints variable bar from local scope
どの変数がどのスコープにあるかを調べることができます。組み込み関数locals()
およびglobals()
はスコープ全体を辞書として返します。
foo = 1
def func():
bar = 2
print(globals().keys()) # prints all variable names in global scope
print(locals().keys()) # prints all variable names in local scope
名前の衝突はどうなりますか?
foo = 1
def func():
foo = 2 # creates a new variable foo in local scope, global foo is not affected
print(foo) # prints 2
# global variable foo still exists, unchanged:
print(globals()['foo']) # prints 1
print(locals()['foo']) # prints 2
グローバル変数を変更するには、keyword global
使用します。
foo = 1
def func():
global foo
foo = 2 # this modifies the global foo, rather than creating a local variable
スコープは、関数本体全体に対して定義されています!
それが意味することは、関数の半分は変数を決してグローバルにすることはできず、その後は局所変数を決してグローバルにすることはできません。
foo = 1
def func():
# This function has a local variable foo, because it is defined down below.
# So, foo is local from this point. Global foo is hidden.
print(foo) # raises UnboundLocalError, because local foo is not yet initialized
foo = 7
print(foo)
同様に、オポジト:
foo = 1
def func():
# In this function, foo is a global variable from the begining
foo = 7 # global foo is modified
print(foo) # 7
print(globals()['foo']) # 7
global foo # this could be anywhere within the function
print(foo) # 7
関数内の関数
関数内には多くのレベルの関数がネストされているかもしれませんが、いずれかの関数の中にはその関数とグローバルスコープのローカルスコープが1つしかありません。中間スコープはありません。
foo = 1
def f1():
bar = 1
def f2():
baz = 2
# here, foo is a global variable, baz is a local variable
# bar is not in either scope
print(locals().keys()) # ['baz']
print('bar' in locals()) # False
print('bar' in globals()) # False
def f3():
baz = 3
print(bar) # bar from f1 is referenced so it enters local scope of f3 (closure)
print(locals().keys()) # ['bar', 'baz']
print('bar' in locals()) # True
print('bar' in globals()) # False
def f4():
bar = 4 # a new local bar which hides bar from local scope of f1
baz = 4
print(bar)
print(locals().keys()) # ['bar', 'baz']
print('bar' in locals()) # True
print('bar' in globals()) # False
global
とnonlocal
(Python 3のみ)
両方のキーワードは、現在の関数にローカルではない変数への書き込みアクセスを取得するために使用されます。
global
キーワードは、名前がグローバル変数として扱われるべきであることを宣言します。
foo = 0 # global foo
def f1():
foo = 1 # a new foo local in f1
def f2():
foo = 2 # a new foo local in f2
def f3():
foo = 3 # a new foo local in f3
print(foo) # 3
foo = 30 # modifies local foo in f3 only
def f4():
global foo
print(foo) # 0
foo = 100 # modifies global foo
一方、Python 3で利用可能なnonlocal
( Nonlocal Variables参照)は、ローカルスコープから現在の関数のローカルスコープにローカル変数を取得します。
非ローカルステートメントは、リストされた識別子が、グローバルを除く最も近い囲みスコープ内の以前にバインドされた変数を参照するようにします。
def f1():
def f2():
foo = 2 # a new foo local in f2
def f3():
nonlocal foo # foo from f2, which is the nearest enclosing scope
print(foo) # 2
foo = 20 # modifies foo from f2!