解释是当我们写self.aliases = set([])
我们实际上是creating a new实例属性,隐藏类属性.
所以,如果我们让我们的__init__
函数如下,我们得到预期的输出。
def __init__(self,name):
self.name = name
A.aliases = set([name]) #using the class attribute directly
另请考虑以下代码片段:
class A:
aliases = set([])
name = None
def __init__(self,name):
self.name = name
self.aliases.add(name) # using the class attribute indirectly.
def add_aliases(self,a):
self.aliases.add(a)
def __repr__(self):
return str(self.name) + str(self.aliases)
因为在这种情况下,我们not创建一个实例属性,没有阴影。问题中的测试代码将产生以下输出:
0set([0, 1, 2, 3])
1set([0, 1, 2, 3])
2set([0, 1, 2, 3])
0set([])
1set([])
2set([])
这是预期的,因为类属性在所有实例之间共享。
Here A.alias
也可以称为self.alias
inside init
或任何其他功能。由于它没有隐藏静态属性,所以给出了预期的输出——所有对象共享一个公共属性的情况。
不了解这个概念的人在使用不可变数据结构(例如string
等等。但是对于像这样的数据结构list
and dictionary
这可能会令人惊讶。
还请考虑以下定义init
.
def __init__(self,name):
self.name = name
self.aliases.add(name) # referring to class attribute
self.aliases = set([]) # creating a instance attribute
这个案例也最终导致了instance attribute
测试代码产生的输出是:
0set([1])
1set([2])
2set([3])
0set([1])
1set([2])
2set([3])
从这一切中我学到的是:
始终使用类名称引用类属性,使用对象名称引用实例属性,即写A.aliases
当你指的是类属性时aliases
,不写self.aliases
间接提及self.aliases