Python 为什么方法可以';t访问类变量?
我试图理解Python中的变量作用域,除了我不明白为什么类变量不能从其方法访问之外,大多数事情我都很清楚。Python 为什么方法可以';t访问类变量?,python,Python,我试图理解Python中的变量作用域,除了我不明白为什么类变量不能从其方法访问之外,大多数事情我都很清楚。 在下面的示例中,mydef1()无法访问a,但如果a在全局范围(类定义之外)中声明,则可以访问 输出 Traceback (most recent call last): File "E:\dev\Python\scope_test2.py", line 6, in <module> ins1.mydef1() File "E:\dev\Python\scope
在下面的示例中,
mydef1()
无法访问a
,但如果a
在全局范围(类定义之外)中声明,则可以访问
输出
Traceback (most recent call last):
File "E:\dev\Python\scope_test2.py", line 6, in <module>
ins1.mydef1()
File "E:\dev\Python\scope_test2.py", line 4, in mydef1
print(a)
NameError: name 'a' is not defined
回溯(最近一次呼叫最后一次):
文件“E:\dev\Python\scope\u test2.py”,第6行,在
ins1.mydef1()
文件“E:\dev\Python\scope\u test2.py”,第4行,在mydef1中
印刷品(a)
NameError:未定义名称“a”
您需要self.a
。没有隐式类作用域。您需要self.a
。没有隐式的类作用域。重要的是要理解其中一些注释是不等价的MyClass.a
是类本身的成员,self.a
是类实例的成员
使用self.a
时,它将从类返回a
,因为实例上没有a
。如果还有一个a
,它是实例的成员,它将返回该实例。通常,使用\uuuu init\uuu
构造函数设置实例a。这两者可以同时存在
class MyClass1:
a = 25
def __init__(self):
self.a = 100
def instance_a(self):
print(self.a)
def change_instance_a(self):
self.a = 5
def class_a(self):
print(MyClass1.a)
def change_class_a(self):
MyClass1.a = 10
# Create two instances
ins1 = MyClass1()
ins2 = MyClass1()
# Both instances have the same Class member a, and the same instance member a
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
# Now lets change instance a on one of our instances
ins1.change_instance_a()
# Print again, see that class a values remain the same, but instance a has
# changed on one instance only
print()
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
# Lets change the class member a on just one instance
ins1.change_class_a()
# Both instances now report that new value for the class member a
print()
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
self.a = 100
def instance_a(self):
print(self.a)
def change_instance_a(self):
self.a = 5
def class_a(self):
print(MyClass1.a)
def change_class_a(self):
MyClass1.a = 10
重要的是要理解这些评论中的一些并不等同
MyClass.a
是类本身的成员,self.a
是类实例的成员
使用self.a
时,它将从类返回a
,因为实例上没有a
。如果还有一个a
,它是实例的成员,它将返回该实例。通常,使用\uuuu init\uuu
构造函数设置实例a。这两者可以同时存在
class MyClass1:
a = 25
def __init__(self):
self.a = 100
def instance_a(self):
print(self.a)
def change_instance_a(self):
self.a = 5
def class_a(self):
print(MyClass1.a)
def change_class_a(self):
MyClass1.a = 10
# Create two instances
ins1 = MyClass1()
ins2 = MyClass1()
# Both instances have the same Class member a, and the same instance member a
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
# Now lets change instance a on one of our instances
ins1.change_instance_a()
# Print again, see that class a values remain the same, but instance a has
# changed on one instance only
print()
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
# Lets change the class member a on just one instance
ins1.change_class_a()
# Both instances now report that new value for the class member a
print()
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
self.a = 100
def instance_a(self):
print(self.a)
def change_instance_a(self):
self.a = 5
def class_a(self):
print(MyClass1.a)
def change_class_a(self):
MyClass1.a = 10
考虑以下类别:
class ScopeTest(object):
classvariable = 0
number_of_objects_created = 0
def __init__(self, value=1):
self.instancevariable = value
ScopeTest.number_of_objects_created += 1
def number_of_brothers(self):
print(ScopeTest.number_of_objects_created)
def confusion(self, value=2):
self.classvariable = value
print (f"class: {ScopeTest.classvariable}, self:{self.classvariable}")
让我们看看当你玩它时会发生什么:
>>> a = ScopeTest()
>>> a.instancevariable
1
>>> a.classvariable
0
>>> ScopeTest.classvariable
0
到目前为止还不错,但当您为a
指定一个新属性时:
>>> a.classvariable = 2
>>> a.classvariable
2
>>> ScopeTest.classvariable
0
如果将属性添加到类的方法中,情况也是如此:
>>> a.confusion(4)
class: 0, self:4
这些类属性有助于保持所有对象的公共性,因为创建的对象的数量如下所示:
>>> b = ScopeTest()
>>> b.number_of_brothers()
2
>>> a.number_of_brothers()
2
通过向类中添加另一个方法,您可以从中获得更多:
class ScopeTest(object):
...
def other_function(self, classvariable=3):
print(f"class: {ScopeTest.classvariable}\t"
f"instance: {self.classvariable}\t"
f"argument:{classvariable}")
并调用它(在使用第一个“混淆”方法设置self.classvariable
之后):
考虑以下类别:
class ScopeTest(object):
classvariable = 0
number_of_objects_created = 0
def __init__(self, value=1):
self.instancevariable = value
ScopeTest.number_of_objects_created += 1
def number_of_brothers(self):
print(ScopeTest.number_of_objects_created)
def confusion(self, value=2):
self.classvariable = value
print (f"class: {ScopeTest.classvariable}, self:{self.classvariable}")
让我们看看当你玩它时会发生什么:
>>> a = ScopeTest()
>>> a.instancevariable
1
>>> a.classvariable
0
>>> ScopeTest.classvariable
0
到目前为止还不错,但当您为a
指定一个新属性时:
>>> a.classvariable = 2
>>> a.classvariable
2
>>> ScopeTest.classvariable
0
如果将属性添加到类的方法中,情况也是如此:
>>> a.confusion(4)
class: 0, self:4
这些类属性有助于保持所有对象的公共性,因为创建的对象的数量如下所示:
>>> b = ScopeTest()
>>> b.number_of_brothers()
2
>>> a.number_of_brothers()
2
通过向类中添加另一个方法,您可以从中获得更多:
class ScopeTest(object):
...
def other_function(self, classvariable=3):
print(f"class: {ScopeTest.classvariable}\t"
f"instance: {self.classvariable}\t"
f"argument:{classvariable}")
并调用它(在使用第一个“混淆”方法设置self.classvariable
之后):
通过在mydef1
中调用print(a)
,python正在寻找一个本地(或全局,如您所发现的)变量“a
”。也就是说,一个与MyClass1
没有任何直接关系的变量,但这种变量尚未定义
如果您试图访问类变量“a
”(即a
是类本身的成员,而不是它的任何实例),则必须使用MyClass1.a
。或者,由于没有名为“a
”的实例变量,因此也可以使用self.a
来达到相同的效果。但是,一旦明确定义了self.a,self.a==MyClass1.a
,则可能不是真的。例如:
>>>class MyClass1:
... a = 25
...
>>>my_obj = MyClass1()
>>>MyClass1.a
25
>>>my_obj.a
25
>>>MyClass1.a += 1
>>>MyClass1.a
26
>>>my_obj.a
26
>>>my_obj.a = 5 # explicitly define "a" for this instance; my_obj.a not longer synonymous with MyClass1.a
>>>MyClass1.a += 1
>>>MyClass1.a
27
>>>my_obj.a
5
通过在mydef1
中调用print(a)
,python正在寻找一个本地(或全局,如您所发现的)变量“a
”。也就是说,一个与MyClass1
没有任何直接关系的变量,但这种变量尚未定义
如果您试图访问类变量“a
”(即a
是类本身的成员,而不是它的任何实例),则必须使用MyClass1.a
。或者,由于没有名为“a
”的实例变量,因此也可以使用self.a
来达到相同的效果。但是,一旦明确定义了self.a,self.a==MyClass1.a
,则可能不是真的。例如:
>>>class MyClass1:
... a = 25
...
>>>my_obj = MyClass1()
>>>MyClass1.a
25
>>>my_obj.a
25
>>>MyClass1.a += 1
>>>MyClass1.a
26
>>>my_obj.a
26
>>>my_obj.a = 5 # explicitly define "a" for this instance; my_obj.a not longer synonymous with MyClass1.a
>>>MyClass1.a += 1
>>>MyClass1.a
27
>>>my_obj.a
5
简短回答:这就是Python的作用域规则。Python中的嵌套函数是词汇范围的,但这不适用于类中嵌套的东西
class Foo:
a = 25
print(a)
class Bar:
print(a)
第一个打印,但第二个是namererror
详细回答: 类级变量有一个函数闭包,但它都包装在
\uuuuu class\uuuu
中。(这主要用于super()
magic,这就是为什么它不再需要Python 3中的参数。)
通常,您可以通过self
参数访问这些内容,以允许子类重写它们,但是\uuuuu类\uuuuuuu
甚至可以用于既没有self
也没有cls
的staticmethod
class MyClass1:
a = 25
@staticmethod
def mydef1():
print(__class__.a)
ins1 = MyClass1()
ins1.mydef1() # 25
从技术上讲,类对象甚至在类声明完成执行之前都不存在,这就是为什么不能这样做
class Foo:
a = 25
class Bar:
# NameError: free variable '__class__' referenced before assignment
print(__class__.a)
甚至
class Foo:
a = 25
def bar():
print(__class__.a)
# NameError: free variable '__class__' referenced before assignment in enclosing scope
bar()
但是,在此之前,您可以访问locals()
dict
class Foo:
a = 21
locals()['a'] *= 2
Foo.a # 42
所以这是可行的
class Foo:
a = 25
global foolocals
foolocals = locals()
def bar():
print(foolocals['a'])
bar() # 25
简短回答:这就是Python的作用域规则。Python中的嵌套函数是词汇范围的,但这不适用于类中嵌套的东西
class Foo:
a = 25
print(a)
class Bar:
print(a)
第一个打印,但第二个是namererror
详细回答: 类级变量有一个函数闭包,但它都包装在
\uuuuu class\uuuu
中。(这主要用于super()
magic,这就是为什么它不再需要Python 3中的参数。)
通常情况下,您可以通过