调试实例/类属性

2024-05-15 23:54:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图让下面的代码按照下面评论中的预期工作。例如,我将使用下面的命令创建三个Dog实例(dogs:buddy、pascal和kimber)。但是,当运行buddy.teach('sit')时,它会向buddy和pascal实例添加“sit”技巧。您能操纵代码,以便为实例对象而不是类对象定义属性吗

请仅编辑代码(不要更改下面注释中的命令)

class Dog:
    def __init__(self, name, tricks=set()):
        self.name = name
        self.tricks = tricks
    def teach(self, trick):
        self.tricks.add(trick)
# Change the broken code above so that the following lines work:
# 
# buddy = Dog('Buddy')
# pascal = Dog('Pascal')
# kimber = Dog('Kimber', tricks={'lie down', 'shake'})
# buddy.teach('sit')
# pascal.teach('fetch')
# buddy.teach('roll over')
# kimber.teach('fetch')
# print(buddy.tricks)  # {'sit', 'roll over'}
# print(pascal.tricks)  # {'fetch'}
# print(kimber.tricks)  # {'lie down', 'shake', 'fetch'}

Tags: 对象实例代码name命令selffetchpascal
2条回答

您的__init()__具有以下定义:

def __init__(self, name, tricks=set()):

set()是和对象,它为类定义实例化一次,并在每个实例中共享。因此,每个使用默认tricks的实例共享相同的技巧集(!)

为了防止这种情况,常见的模式是:

class Dog:
    def __init__(self, name, tricks=None):
        self.name = name
        self.tricks = set()
        if tricks:
            self.tricks = tricks
    def teach(self, trick):
        self.tricks.add(trick)

问题来自__init__中的默认参数tricks=set()

在定义函数/方法时,默认参数只计算一次。因此,将创建一个空的set,当调用__init__而不指定tricks时,它将用作默认参数

当您执行buddy = Dog('Buddy')时,这个空集被用作tricks,并且在self.tricks = tricks中,您使buddytricks属性引用它

稍后,再次执行pascal = Dog('Pascal'),而不指定trick,因此将使用与默认参数创建的相同集合,pascaltrick属性也将引用它

因此,两个实例共享相同的技巧集

如果在创建实例时为tricks传递一个值,则不会有问题:它将是一个独立集。 如果这个默认值是不可变的,也不会有任何问题(请参见“Least Astonishment” and the Mutable Default Argument

为了避免使用可变的默认参数,经典的解决方案如下:

 class Dog:
    def __init__(self, name, tricks=None):
        if tricks is None:
            tricks = set()
        self.name = name
        self.tricks = tricks
        
    def teach(self, trick):
        self.tricks.add(trick)
        
buddy = Dog('Buddy')
pascal = Dog('Pascal')
kimber = Dog('Kimber', tricks={'lie down', 'shake'})
buddy.teach('sit')
pascal.teach('fetch')
buddy.teach('roll over')
kimber.teach('fetch')
print(buddy.tricks)  # {'sit', 'roll over'}
print(pascal.tricks)  # {'fetch'}
print(kimber.tricks)  # {'lie down', 'shake', 'fetch'}

输出:

{'roll over', 'sit'}
{'fetch'}
{'lie down', 'fetch', 'shake'}

相关问题 更多 >