Python の名前バインディング
Python では、オブジェクトは名前を通じて関連付けられ、参照されます。 Python は、名前バインディング操作を通じて名前を導入します。
Pythonのいわゆるコードブロックは、実行単位として機能するプログラムです。例: モジュール、関数、クラス定義。対話型環境で入力されたコマンドもコード ブロックの一種です。 Python スクリプト ファイルもコードのブロックです。また、コマンド ラインで -c オプションを使用すると、指定されたコマンドもコード ブロックになります。組み込み関数 eval() および exec() に渡される文字列パラメータもコード ブロックの一種です。
コード ブロックは実行フレームの形式で実行され、実行フレームにはいくつかの管理情報が含まれており、デバッグに使用できます。実行フレームは、現在のコード ブロックが実行された後に次のコードを実行する場所と方法も指定します。
Python のスコープは、コード ブロック内の名前の可視性を定義します。ローカル変数がコード ブロック内で定義されている場合、ローカル変数のスコープは、ローカル変数が配置されているコード ブロックになります。この定義が関数本体内で行われる場合、この変数のスコープは、この関数に含まれるコード ブロック内に拡張されます。ただし、この関数に含まれるコード ブロック内で同じ名前が別のオブジェクトにバインドされている場合、外部の名前はバインドされます。このコード ブロックに展開しないでください。
def out_func(): #a的作用域在out_func这个函数中 a = 0 b = 0 def in_func(): #a的作用域从out_func扩展到了in_func中,因为in_func这个代码块包含在out_func中 print(a) #out_func函数中的b不能扩展到in_func中,因为在in_func中,b重新绑定到了不同的对象上,所以在out_func中的b的作用域不能扩展到in_func中。 b = 1
Python では、クラス コード ブロックで定義された名前はクラス内でのみ表示でき、クラス内の名前のスコープをクラス内のメソッドに拡張することはできません。ジェネレーター式とリスト展開がクラス定義にある場合、リスト展開とジェネレーター式は関数スコープを使用して実装されるため、クラス内の名前をこれらの式に展開することはできません。
class C: a = 0 # 在列表表达式中,a会因为未定义而抛出NameError异常 b = list(a + i for i in range(10)) def method(self): #由于定义在类中的名字不能扩展到方法中,所以下面的语句是错误的,会抛出a未定义的NameError异常 print(a)
コード ブロックで名前が使用される場合、最も近い囲みスコープが解析されて名前が検索されます。現在のコード ブロックで表示されるこれらすべてのスコープのセットは、現在のコード ブロックの環境と呼ばれます。
名前バインディングとスコープの関係
名前が非ローカルとして宣言されていない限り、名前がコードブロックにバインドされている場合(非ローカル宣言の機能は、グローバルスコープが解析される前に、外部スコープに変数を作成することです) )、それ以外の場合、この名前はこのコード ブロックのローカル変数です。名前がモジュール レベルにバインドされている場合、名前のスコープはグローバルであり、変数はグローバル変数です (モジュール内の変数はモジュールのローカル変数であり、モジュール内のコード ブロックの場合はグローバル変数です)。 。名前がコード ブロック内で使用されているが、コード ブロック内で定義されていない場合、その変数は自由変数です。
名前のバインドに関連する例外
名前の検索中に名前が見つからない場合、名前がローカル変数を参照しているが、名前がこのローカル変数にバインドされていない場合は、UnboundLocalError 例外がスローされます。がスローされます (UnboundLocalError は NameError のサブクラスです)。
名前バインディング動作が発生する状況
名前バインディングが発生する主な動作は次のとおりです:
通常、パラメータを関数に渡すとき、パラメータ名は渡されたオブジェクトにバインドされます
インポートステートメントを使用してインポートする場合, from...import * ステートメントは、インポートされたモジュールにインポートできるすべての名前をバインドします
クラスが定義されたとき
関数が定義されたとき
代入操作が実行されたとき
for ステートメントfor ループの
with ステートメントのような後
Expect ステートメントのような後
Python での名前バインディングの落とし穴
Python では、名前バインディングのいくつかのルールにより、名前を使用すると、特に理解できないエラーが発生します。 C、C++、Java の経験があるユーザー向け。
Python では、現在のブロック内のどこで名前バインディング操作が発生しても、このコード ブロック内の名前への参照には、現在のブロック内にバインドされたオブジェクトが使用されます。ここで問題が発生します。名前バインディング操作が発生する前に名前を参照すると、エラーが発生し、UnboundLocalError 例外がスローされます。
>>> a = 10 >>> def function(): print(a) a = 20# a的绑定操作发生在print之前 >>> function() Traceback (most recent call last): File "<pyshell#5>", line 1, in <module> function() File "<pyshell#4>", line 2, in function print(a) UnboundLocalError: local variable 'a' referenced before assignment
Python では、コード ブロック内のローカル変数はコード ブロック全体をスキャンすることでバインドされた名前を取得できるため、上記のコードでは、スキャンの実行時に名前 a がコード ブロックに渡されます。は見つかりましたが、名前 a のバインド操作がまだ行われていないため、エラーが発生しました。
上記のコードでは、外部で定義されたグローバル変数が必要な場合は、global ステートメントを使用してそれを宣言できます。
>>> a = 10 >>> def function(): global a print(a) a = 20#这里并不引入新的名字,而是将全局变量a绑定到20上 >>> function() 10 >>> a 20
global global ステートメントの機能は、このステートメントで宣言されたオブジェクトへの後続の参照で、トップレベルの名前空間の名前を使用することです。最上位の名前空間には、グローバル名前空間と組み込み名前空間が含まれます。見つからない場合は、組み込み名前空間が検索されます。 global ステートメントは、名前を使用する前に指定する必要があります。
外側のスコープの自由変数にグローバル宣言が含まれている場合、その自由変数はグローバルとみなされます。
組み込み名前空間
組み込み名前空間を検索する場合、現在のコード ブロックのグローバル名前空間の __builtins__ 名にアクセスします。この名前は、名前辞書またはモジュールを参照します。 __main__ モジュールでは、__builtins__ は組み込みモジュールの buildins を指しますが、他のモジュールにある場合は、__builtins__ は組み込みモジュールの名前辞書を指します。
注:
CPython の実装では、__builtins__ 変数を手動で変更することはできません。この組み込み名前空間の名前を上書きする必要がある場合は、builtins モジュールをインポートしてから、対応する属性を変更する必要があります。このモジュール。