调试 instance/class 属性
Debug the instance/class attribute
我正在尝试让以下代码按下面评论中的预期工作。例如,我将使用以下命令创建三个 Dog 实例(狗:buddy、pascal 和 kimber)。但是,当 运行 buddy.teach('sit')
时,它会向 buddy 和 pascal 实例添加 'sit' 技巧。您能否操纵代码,以便为实例对象而不是 class 对象定义属性?
请只编辑代码(不要更改下面评论中的命令)。
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'}
给你:
class Dog:
def __init__(self, name, tricks=set()):
self.name = name
self.tricks = set(tricks)
def teach(self, trick):
self.tricks.add(trick)
您的 __init()__
具有以下定义:
def __init__(self, name, tricks=set()):
set()
是一个对象,它为 class 定义 实例化一次并在每个实例中共享。所以每个使用默认 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()
。
默认参数仅在定义 function/method 时计算一次。因此,创建了一个空的 set
,每当调用 __init__
而不指定 tricks
.
时,它将用作默认参数
当你执行buddy = Dog('Buddy')
时,这个空集被用作tricks
,而在self.tricks = tricks
中,你使buddy
的tricks
属性引用
稍后,您再次执行 pascal = Dog('Pascal')
,但未指定 trick
,因此使用作为默认参数创建的同一集合,以及 pascal
的 trick
属性也会参考。
因此,两个实例共享同一组技巧。
如果在创建实例时为 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'}
我正在尝试让以下代码按下面评论中的预期工作。例如,我将使用以下命令创建三个 Dog 实例(狗:buddy、pascal 和 kimber)。但是,当 运行 buddy.teach('sit')
时,它会向 buddy 和 pascal 实例添加 'sit' 技巧。您能否操纵代码,以便为实例对象而不是 class 对象定义属性?
请只编辑代码(不要更改下面评论中的命令)。
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'}
给你:
class Dog:
def __init__(self, name, tricks=set()):
self.name = name
self.tricks = set(tricks)
def teach(self, trick):
self.tricks.add(trick)
您的 __init()__
具有以下定义:
def __init__(self, name, tricks=set()):
set()
是一个对象,它为 class 定义 实例化一次并在每个实例中共享。所以每个使用默认 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()
。
默认参数仅在定义 function/method 时计算一次。因此,创建了一个空的 set
,每当调用 __init__
而不指定 tricks
.
当你执行buddy = Dog('Buddy')
时,这个空集被用作tricks
,而在self.tricks = tricks
中,你使buddy
的tricks
属性引用
稍后,您再次执行 pascal = Dog('Pascal')
,但未指定 trick
,因此使用作为默认参数创建的同一集合,以及 pascal
的 trick
属性也会参考。
因此,两个实例共享同一组技巧。
如果在创建实例时为 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'}