在python中,如何处理可变类属性

在python中,如何处理可变类属性,python,Python,我正在执行以下Python代码: class Pet : kind = 'dog' # class variable shared by all instances tricks = [] def __init__(self, name) : self.name = name # instance variable unique to each instance def changePet(self, newPet) : s

我正在执行以下Python代码:

class Pet :
    kind = 'dog'    # class variable shared by all instances
    tricks = []

    def __init__(self, name) :
        self.name = name # instance variable unique to each instance
    def changePet(self, newPet) :
        self.kind = newPet
    def addTricks(self, tricks) :
        self.tricks.append(tricks)

pet1 = Pet('mypet')
pet2 = Pet('yourpet')
print 'pet1 kind ::: ', pet1.kind;print 'pet2 kind ::: ', pet2.kind
print 'pet1 name ::: ', pet1.name;print 'pet2 name ::: ', pet2.name

Pet.kind = 'cat'
print 'changed Pet.kind to cat'
print 'pet1 kind ::: ', pet1.kind;print 'pet2 kind ::: ', pet2.kind

#changing pet#1 kind does not change pet#2 kind
pet1.changePet('parrot')
print 'changed pet1.kind to parrot'
print 'pet1 kind ::: ', pet1.kind;print 'pet2 kind ::: ', pet2.kind

pet1.addTricks('imitate')
pet2.addTricks('roll over')
print 'pet1 tricks ::: ', pet1.tricks;print 'pet2 tricks ::: ', pet2.tricks

print Pet.__dict__
print pet1.__dict__
print pet2.__dict__
输出结果与我在互联网上找到的解释一致。结果如下

pet1 kind :::  dog
pet2 kind :::  dog
pet1 name :::  mypet
pet2 name :::  yourpet
changed Pet.kind to cat
pet1 kind :::  cat
pet2 kind :::  cat
changed pet1.kind to parrot
pet1 kind :::  parrot
pet2 kind :::  cat
pet1 tricks :::  ['imitate', 'roll over']
pet2 tricks :::  ['imitate', 'roll over']
{'__module__': '__main__', 'tricks': ['imitate', 'roll over'], 'kind': 'cat', 'addTricks': <function addTricks at 0xb71fa6bc>, 'changePet': <function changePet at 0xb71fa33c>, '__doc__': None, '__init__': <function __init__ at 0xb71fa144>}
{'kind': 'parrot', 'name': 'mypet'}
{'name': 'yourpet'}
宠物1种类:狗 宠物2种类:狗 pet1名称:::mypet 宠物2名字:::你的宠物 把宠物变成猫 宠物1种类:猫 宠物2种类:猫 把宠物变成了鹦鹉 宠物1种类:鹦鹉 宠物2种类:猫 pet1技巧::[“模仿”,“翻滚”] pet2技巧::[“模仿”,“翻滚”] {uuuuu模块{uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu {'kind':'parrot','name':'mypet'} {'name':'yourpet'}
现在我的问题是,为什么可变类对象与不可变类对象的处理方式不同,我不确定它们的处理方式是否不同。您只是在对它们执行不同的操作

changePet
的情况下,将先前未定义的
self.kind
赋值。现在,当python试图查找
pet1.kind
时,它会立即找到它。当查找pet2.kind时,它没有找到它。但是,它确实会查找
Pet.kind
,所以它会返回它

addTricks
的情况下,您试图变异
self.tricks
。因为它不存在,所以会给您一个对
Pet.tricks
的引用。因此,当您在
self.tricks
上调用
append()
时,您有效地调用了
Pet.tricks.append()
,而不是
self.tricks.append()

要澄清问题,请执行以下操作:

def changePet(self, newPet) :
    self.kind = newPet
def addTricks(self, tricks) :
    self.tricks.append(tricks)
实际上相当于:

def changePet(self, newPet) :
    self.kind = newPet
def addTricks(self, tricks) :
    Pet.tricks.append(tricks)
为了证明python对待可变项的方式与对待非可变项的方式不同,我们需要更改您的方法,以便它们执行类似的操作:

def changePet(self, newPet) :
    self.kind = newPet

def addTricks(self, tricks):
    # assign self.tricks to a new value where we previously only mutated it!
    # note: list(self.tricks) returns a copy
    self.tricks = list(self.tricks)
    self.tricks.append(tricks)
现在,当我们再次运行代码时,我们得到以下输出:

pet1 kind :::  dog
pet2 kind :::  dog
pet1 name :::  mypet
pet2 name :::  yourpet
changed Pet.kind to cat
pet1 kind :::  cat
pet2 kind :::  cat
changed pet1.kind to parrot
pet1 kind :::  parrot
pet2 kind :::  cat
pet1 tricks :::  ['imitate']
pet2 tricks :::  ['roll over']
{'__module__': '__main__', 'tricks': [], 'kind': 'cat', 'addTricks': <function addTricks at 0x02A33C30>, 'changePet': <function changePet at 0x02A33BF0>, '__doc__': None, '__init__': <function __init__ at 0x02A33BB0>}
{'tricks': ['imitate'], 'kind': 'parrot', 'name': 'mypet'}
{'tricks': ['roll over'], 'name': 'yourpet'}
宠物1种类:狗 宠物2种类:狗 pet1名称:::mypet 宠物2名字:::你的宠物 把宠物变成猫 宠物1种类:猫 宠物2种类:猫 把宠物变成了鹦鹉 宠物1种类:鹦鹉 宠物2种类:猫 pet1技巧::[“模仿”] pet2技巧::[“翻滚”] {“模块”:“主要”、“技巧”:[]、“种类”:“猫”、“添加技巧”:、“变更宠物”:、“\uuuuuu文档”:无、\uuuuuuu初始化”: {'tricks':['mike'],'kind':'parrot','name':'mypet'} {'tricks':['roll over'],'name':'yourpet'}
Python不会对它们进行不同的处理。您在一个位置分配,但在另一个位置使用列表方法,对它们进行了不同的处理。请尝试使用
self.tricks=self.tricks+[tricks]
查看差异。相关和相关:另外,看起来您对术语有点困惑。在您的示例中没有涉及不可变变量(字符串除外,但本质上是不相关的)。正确的术语应该是实例(
name
)和共享(
kind
tricks
)属性。实例属性对于个人对象(类的实例)是唯一的,而共享属性则在类的所有实例之间共享。
+=
是增强的赋值,使对象有机会就地更新;对于使用
list.extend()
的列表对象。非常感谢@averes的回复。