我有一个包含许多属性的类。有人可以澄清设置属性如下面的a,b,c和x,y,z之间的区别。我明白,如果你提出要求,他们显然必须在 init 中,只是为了设置一个数字默认变量,这是首选的,有什么优缺点。
class Foo(object):
a = 'Hello'
b = 1
c = False
def __init__(self):
self.x = 'World'
self.y = 2
self.z = True
答案 0 :(得分:7)
变量a
,b
和c
是类变量。首次创建类时,它们会被评估并设置一次。变量x
,y
和z
是实例变量,只要实例化该类的对象,就会对其进行求值和设置。
通常,如果类的每个实例都使用相同的值,则使用类变量,并且只需要计算一次。您可以将实例变量用于对于该类的每个实例将会有所不同的变量。
您可以通过实例变量语法self.a
访问类变量,但有问题的对象在类的所有实例之间共享。当使用不可变数据类型(如整数或字符串)时,这不会产生太大影响,但是当使用可变数据类型(如列表)时,附加到self.a
会导致所有实例都看到新附加的值。
IDLE的一些例子可能有助于理解这一点:
>>> class Foo(object):
a = 'Hello'
b = []
def __init__(self):
self.y = []
>>> instance_1 = Foo()
>>> instance_2 = Foo()
>>> instance_1.a
'Hello'
>>> instance_2.a
'Hello'
>>> instance_1.a = 'Goodbye'
>>> instance_1.a
'Goodbye'
>>> instance_2.a
'Hello'
>>> instance_1.b
[]
>>> instance_2.b.append('12345')
>>> instance_1.b
['12345']
>>> instance_2.y
[]
>>> instance_2.y.append('abcde')
>>> instance_2.y
['abcde']
>>> instance_1.y
[]
答案 1 :(得分:5)
使用类属性为您打算作为特定于实例的数据提供默认值的主要因素是默认值将在类的所有实例之间共享,直到值更改为止。 E.g:
class Foo(object):
a = []
foo1 = Foo()
foo2 = Foo()
foo1.a.append(123)
foo1.a # [123]
foo2.a # [123]
但是,以下内容可以正常运行:
class Bar(object):
a = 123
bar1 = Bar()
bar2 = Bar()
bar1.a = 456
bar2.a # 123
要在使用此技术时避免此问题,您应该只使用它来设置不可变值的默认值。 (例如数字,字符串,元组......)
Python以这种方式运行的原因是当您使用以下内容访问属性时
foo.bar
然后首先在对象bar
中查找foo
。如果在对象中找不到名称(即在foo.__dict__
中),则在该对象的类型中查找名称。例如,此机制是方法查找工作方式的一部分。 (如果你看一个对象的__dict__
,你会注意到它的方法不存在。)
其他一些小问题是,当它们打算是特定于实例时,它会通过类型对象公开默认值;如果您有任何默认值,它会混合特定于类的属性(如常量)的定义。前者的推论是,这将允许您稍后通过分配给class属性为尚未更改值的所有对象重新定义默认值。 (这可能是有用的,或者令人困惑;对可变“全局”变量采取相同的预防措施。)
答案 2 :(得分:2)
当你宣布它们时,a,b和c将在不创建Foo实例的情况下可用 例如,您可以说:
Foo.a = "Goodbye"
相反,在创建Foo实例之前,不会创建x,y和z,并且它们特定于该实例:
bar = Foo()
bar.x = 42
答案 3 :(得分:1)
这无数次被问过......
a,b,c
是在所有实例之间共享的类变量,一个很好的用法是计算所有已创建的类的出现次数的计数器,x,y,z
是属于该单个实例的实例变量因此使用self
设置它们......
请注意,您实际上可以影响像self.a = 3
这样的类变量,这不会改变a
,而是会影响它......并且让一些人感到意外。
演示:
>>> class Foo(object):
... a = 3
... def __init__(self):
... self.x = 6
...
>>> Foo.a
3
>>> b = Foo()
>>> b.a = 5
>>> b.a
5
>>> Foo.a
3
>>> b.a
5
>>> Foo.a = 9
>>> Foo.a
9
>>> b.a
5
>>> c = Foo()
>>> c.a
9