Der Namespace von Python ist etwas, das Python-Programmierer verstehen müssen. Wenn wir etwas über den Namespace von Python lernen, können wir im Wesentlichen einige triviale Regeln in Python beherrschen.
Als nächstes werde ich das Wesentliche von Python-Namespaces enthüllen: 1. Die Definition des Namespace; 2. Die Suchreihenfolge des Namespace; 4. Durch locals() und globals() BIF-Zugriffsnamespace
Der Fokus liegt auf dem vierten Teil, in dem wir den Inhalt des Namespace beobachten.
1. Namespace
Python verwendet einen sogenannten Namespace, um den Verlauf von Variablen aufzuzeichnen. Ein Namespace ist ein Wörterbuch, dessen Schlüssel Variablennamen und dessen Werte die Werte dieser Variablen sind.
Ein Namespace ist eine Zuordnung von Namen zu Objekten. Die meisten Namespaces werden derzeit als Python-Wörterbücher implementiert.
Überall in einem Python-Programm gibt es mehrere verfügbare Namespaces.
1. Jede Funktion verfügt über einen eigenen Namensraum, den sogenannten lokalen Namensraum, der die Variablen der Funktion aufzeichnet, einschließlich Funktionsparametern und lokal definierten Variablen.
2. Jedes Modul verfügt über einen eigenen Namensraum, den sogenannten globalen Namensraum, der die Variablen des Moduls aufzeichnet, einschließlich Funktionen, Klassen, andere importierte Module, Variablen und Konstanten auf Modulebene.
3. Es gibt auch einen integrierten Namensraum, auf den jedes Modul zugreifen kann. Er speichert integrierte Funktionen und Ausnahmen.
2. Namespace-Suchreihenfolge
Wenn eine Codezeile den Wert der Variablen x verwendet, sucht Python in allen verfügbaren Namespaces die folgende Reihenfolge:
1. Lokaler Namespace: Bezieht sich speziell auf die Methode der aktuellen Funktion oder Klasse. Wenn die Funktion eine lokale Variable x oder einen Parameter x definiert, verwendet Python diese und beendet dann die Suche.
2. Globaler Namespace: Bezieht sich speziell auf das aktuelle Modul. Wenn das Modul eine Variable, Funktion oder Klasse mit dem Namen x definiert, verwendet Python diese und beendet dann die Suche.
3. Integrierter Namespace: global für jedes Modul. Als letzten Ausweg geht Python davon aus, dass x eine integrierte Funktion oder Variable ist.
4. Wenn Python x in diesen Namespaces nicht finden kann, gibt es die Suche ab und löst eine NameError-Ausnahme aus, z. B. NameError: Name 'aa' ist nicht definiert.
Situation mit verschachtelten Funktionen:
1. Suchen Sie zuerst nach
2. Suchen Sie dann nach im Namensraum der übergeordneten Funktion 3. Suchen Sie dann nach im Modul-Namensraum 4. Suchen Sie schließlich nach
Beispiel:
info = "Adress : " def func_father(country): def func_son(area): city= "Shanghai " #此处的city变量,覆盖了父函数的city变量 print(info + country + city + area) city = " Beijing " #调用内部函数 func_son("ChaoYang "); func_father("China ")
Ausgabe: Adresse: China Shanghai ChaoYang
Im obigen Beispiel befindet sich „Info“ im globalen Namensraum, „Land“ im Namensraum der übergeordneten Funktion und „Stadt“ und „Gebiet“ im Namensraum der eigenen Funktion
3. Namespace-Lebenszyklus
Verschiedene Namespaces werden zu unterschiedlichen Zeiten erstellt und haben unterschiedliche Lebensdauern.
1. Der integrierte Namespace wird beim Start des Python-Interpreters erstellt und bleibt immer erhalten und wird nicht gelöscht.
2. Der globale Namensraum des Moduls wird erstellt, wenn die Moduldefinition eingelesen wird. Normalerweise wird der Modul-Namensraum gespeichert, bis der Interpreter beendet wird.
3. Beim Aufruf der Funktion wird ein lokaler Namespace erstellt und gelöscht, wenn die Funktion ein Ergebnis zurückgibt oder eine Ausnahme auslöst. Jede rekursiv aufgerufene Funktion hat ihren eigenen Namensraum.
Eines der Besonderheiten von Python ist, dass seine Zuweisungsoperationen immer im innersten Bereich erfolgen. Durch die Zuweisung werden die Daten nicht kopiert, sondern lediglich der Name an das Objekt gebunden. Das Gleiche gilt für das Löschen: „del y“ löscht einfach den Namen y aus dem Namensraum des lokalen Bereichs. Tatsächlich werden alle Operationen, die neue Namen einführen, im lokalen Bereich ausgeführt.
Beispiel:
i=1
def func2():
i=i 1
func2();
#Error: UnboundLocalError: Lokale Variable 'i', auf die vor der Zuweisung verwiesen wird
Beim Erstellen eines Namespace überprüft Python den Code und füllt den lokalen Namespace aus. Bevor Python diese Codezeile ausführt, findet es die Zuweisung zu i und fügt sie dem lokalen Namespace hinzu. Wenn die Funktion ausgeführt wird, geht der Python-Interpreter davon aus, dass sich i im lokalen Namespace befindet, aber keinen Wert hat, sodass ein Fehler auftritt.
def func3():
y=123
del y
print(y)
func3()
#Fehler: UnboundLocalError: Auf die lokale Variable 'y' wurde vor der Zuweisung verwiesen
#Nach dem Entfernen der „del y“-Anweisung wird sie normal ausgeführt
4. Namespace-Zugriff
1. Auf lokale Namespaces kann mit locals() BIF zugegriffen werden.
locals gibt ein Wörterbuch mit Name/Wert-Paaren zurück. Die Schlüssel dieses Wörterbuchs sind Variablennamen in Form einer Zeichenfolge, und die Werte des Wörterbuchs sind die tatsächlichen Werte der Variablen.
Beispiel:
def func1(i, str ):
x = 12345
print(locals())
func1(1, „first“)
输出:{'str': 'first', 'x': 12345, 'i': 1}
2、全局 (模块级别)命名空间可以通过 globals() BIF来访问。
示例:
'''Created on 2013-5-26''' import copy from copy import deepcopy gstr = "global string" def func1(i, info): x = 12345 print(locals()) func1(1 , "first") if __name__ == "__main__": print("the current scope's global variables:") dictionary=globals() print(dictionary)
输出:(我自己给人为的换行、更换了顺序,加颜色的语句下面重点说明)
{
'__name__': '__main__',
'__doc__': 'Created on 2013-5-26',
'__package__': None,
'__cached__': None,
'__file__': 'E:\\WorkspaceP\\Test1\\src\\base\\test1.py',
'__loader__': <_frozen_importlib.SourceFileLoader object at 0x01C702D0>,
'copy':
'__builtins__':
'gstr': 'global string',
'dictionary': {...},
'func1':
'deepcopy':
}
总结
1、模块的名字空间不仅仅包含模块级的变量和常量,还包括所有在模块中定义的函数和类。除此以外,它还包括了任何被导入到模块中的东西。
2、我们看到,内置命名也同样被包含在一个模块中,它被称作 __builtin__。
3、回想一下 from module import 和 import module 之间的不同。
使用 import module,模块自身被导入,但是它保持着自已的名字空间,这就是为什么您需要使用模块名来访问它的函数或属性:module.function 的原因。
但是使用 from module import function,实际上是从另一个模块中将指定的函数和属性导入到您自己的名字空间,这就是为什么您可以直接访问它们却不需要引用它们所来源的模块。使用 globals 函数,您会真切地看到这一切的发生,见上面的红色输出语句。
3、 locals 与 globals 之间的一个重要的区别
locals 是只读的,globals 不是
示例:
def func1(i, info): x = 12345 print(locals()) locals()["x"]= 6789 print("x=",x) y=54321 func1(1 , "first") globals()["y"]= 9876 print( "y=",y)
输出:
{'i': 1, 'x': 12345, 'info': 'first'}
x= 12345
y= 9876
解释:
locals 实际上没有返回局部名字空间,它返回的是一个拷贝。所以对它进行改变对局部名字空间中的变量值并无影响。
globals 返回实际的全局名字空间,而不是一个拷贝。所以对 globals 所返回的 dictionary 的任何的改动都会直接影响到全局变量。