Are the attributes in a Python class shared or not?
以下代码使我很麻烦:
1 2 3 4 5 6 7 8 9 10 11 12 | class mytest: name="test1" tricks=list() def __init__(self,name): self.name=name #self.tricks=[name] self.tricks.append(name) t1=mytest("hello world") t2=mytest("bye world") print t1.name,t2.name print t1.tricks,t2.tricks |
输出是:
1 2 | hello world bye world ['hello world', 'bye world'] ['hello world', 'bye world'] |
这意味着列表
但是,如果我执行以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class mytest: name="test1" tricks=list() def __init__(self,name): self.name=name self.tricks=[name] self.tricks.append(name) t1=mytest("hello world") t2=mytest("bye world") x=t1.tricks if type(x) is list: print 'a list' elif type(x) is tuple: print 'a tuple' else: print 'neither a tuple or a list' print t1.name,t2.name print t1.tricks,t2.tricks |
输出如下:
1 2 3 | a list hello world bye world ['hello world', 'hello world'] ['bye world', 'bye world'] |
现在,清单
区别在于,在第二个示例中,您将创建一个新的列表self.tricks,作为对象的属性:
1 2 3 4 | def __init__(self,name): self.name=name self.tricks=[name] # <-- this is creating the new attribute for the object self.tricks.append(name) |
第一个例子是因为python解析名称的方式:如果在对象中找不到self.tricks(因为它没有被创建),那么它会尝试将其作为类的成员来查找。既然有诀窍,那么你就可以使用它。
如果在第二个示例中尝试使用mytest.tricks,您可能会明白:
1 2 3 4 | def __init__(self,name): self.name=name mytest.tricks=[name] # <-- this is accesing the class attribute instead self.tricks.append(name) |
这将输出您实际期望的结果。
在第一个示例中,类
1 2 3 4 5 6 | class mytest: name ="test1" tricks = list() def __init__(self,name): ... self.tricks.append(name) |
然而,在第二个示例中,
1 2 3 4 5 6 7 | class mytest: name ="test1" tricks = list() def __init__(self,name): ... self.tricks = [name] ... |
当调用
因此,第一个示例的实例没有
第一种情况创建类变量,第二种情况创建实例变量。
在引用
在第一种情况下,由于您创建了一个名为
在第二种情况下,除了用相同名称的实例变量隐藏类变量外,其他情况都是相同的,因此从那时起,对
第二个案例说明:
1 2 3 4 5 6 7 8 9 | mytest.__dict__ = { 'name': 'test1', 'tricks': [], # this doesn't get updated } t1.__dict__ = { 'name': 'some_passed_name' 'tricks': ['some_passed_name'], } |
在第一种情况下,您没有在对象范围上创建
要获得更深入的解释,请看一下:python类属性:一个非常全面的指南
在这个问题上有一点需要注意。
当您传入名称并将其附加到现有的共享
但是,当您在第二个示例中执行
这类似于父类和子类;如果子类没有为现有函数提供不同的定义,则调用父类的函数。但是如果你这样做,它会调用孩子的函数。
在这两种情况下,您都将
在第一种情况下,你要改变
在第二种情况下,行
你可以很容易地反省这一点,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class mytest: name ="test1" tricks = list() print("tricks id during class definition is: {}".format(id(tricks))) def __init__(self, name): self.name = name print("self.tricks id at the beginning of __init__ is: {}".format(id(self.tricks))) self.tricks = [name] print("self.tricks id after being replaced is: {}".format(id(self.tricks))) print("but mytest.tricks id is still: {}".format(id(mytest.tricks))) self.tricks.append(name) t1=mytest("hello world") t2=mytest("bye world") |
给:
1 2 3 4 5 6 7 | tricks id during class definition is: 140547174832328 self.tricks id at the beginning of __init__ is: 140547174832328 self.tricks id after being replaced is: 140547174831432 but mytest.tricks id is still: 140547174832328 self.tricks id at the beginning of __init__ is: 140547174832328 self.tricks id after being replaced is: 140547174830600 but mytest.tricks id is still: 140547174832328 |