Python __初始化更改父类属性
我真的很困惑,这颠覆了我对Python中OOP的理解。 我不明白发生了什么事 问题。我为某些视图集创建父类:Python __初始化更改父类属性,python,Python,我真的很困惑,这颠覆了我对Python中OOP的理解。 我不明白发生了什么事 问题。我为某些视图集创建父类: class BaseViewSet(object): bindings = {} def __init__(self): # Check that inherited class have updates for bindings if hasattr(self, 'bindings_update') \
class BaseViewSet(object):
bindings = {}
def __init__(self):
# Check that inherited class have updates for bindings
if hasattr(self, 'bindings_update') \
and isinstance(self.bindings_update, dict):
self.bindings.update(self.bindings_update)
继承该类后:
class ClientsViewSet(BaseviewSet):
bindings_update = {
'get': 'get_clients_list',
}
好的,看起来还正常
import BaseViewSet
b = BaseViewSet()
>>> b.bindings
{}
但我不明白接下来会发生什么:
import BaseViewSet
import ClientsViewSet
>>> BaseViewSet.bindings
{}
c = ClientsViewSet()
>>> c.bindings
{'get': 'get_clients_list'}
>>> BaseViewSet.bindings
{'get': 'get_clients_list'} # WTF O_O ???!!!
b = BaseViewSet()
b.bindings
{'get': 'get_clients_list'} # I started cry here...
所以我不明白为什么继承类实例的创建会影响父类属性。
实际上,当一个带有绑定的视图集\u update
影响另一个继承的视图集时,我遇到了一些有趣的错误
请帮帮我
使现代化
非常感谢大家的帮助。
当然我忘了,我的绑定
是类属性,所以当我在子类的\uuu init\uuuu
中更改它时,它在所有继承的实例中都发生了更改
所以,解决方案,我用来解决我的问题:
from copy import deepcopy
class BaseViewSet(object):
bindings = {'get': 'get_instance'}
def __new__(cls, *args, **kwargs)
""" `__new__` called first and create instance of class """
# It is new instance of my class
obj = super().__new__(*args, **kwargs)
# Deepcopy bindings dict from inherited class to avoid override
obj.bindings = deepcopy(cls.bindings)
# Now I have deal with instance's copied `bindings`,
# not with BaseViewSet.bindings
if hasattr(cls, 'binding_updates'):
assert isinstance(cls.bindings_update, dict)
obj.bindings.update(cls.bindings_update)
return obj
class UserViewSet(BaseViewSet):
bindings_update = {'post': 'create_user'}
b = BaseViewSet()
>>> b.bindings
{'get': 'get_instance'}
u = UserViewSet()
>>> u.bindings
{'get': 'get_instance', 'post': 'create_user'}
>>> BaseViewSet.bindings
{'get': 'get_instance'} # Olala, my bindings rescued :D
绑定
是类的属性,而不是对象。
这就是为什么对绑定字典的更改会影响类的原因,因为它们会影响类
如果要将数据分配给单个对象,这就是\uuuuu init\uuuu
方法的作用:
class BaseViewSet(object):
def __init__(self):
self.bindings = {}
if hasattr(self, 'bindings_update') \
and isinstance(self.bindings_update, dict):
self.bindings.update(self.bindings_update)
return
class ClientsViewSet(BaseViewSet):
def __init__(self):
self.bindings_update = {
'get': 'get_clients_list',
}
super(ClientsViewSet, self).__init__()
return
然后,假设您已经适当地导入了所有内容:
>>> b = BaseViewSet()
>>> b.bindings
{}
>>> BaseViewSet.bindings
AttributeError: type object 'BaseViewSet' has no attribute 'bindings'
>>> c = ClientsViewSet()
>>> c.bindings
{'get': 'get_clients_list'}
>>> BaseViewSet.bindings
AttributeError: type object 'BaseViewSet' has no attribute 'bindings'
>>> b = BaseViewSet()
>>> b.bindings
{}
请注意,您不能再访问BaseViewSet.bindings
,因为它不再是类属性。
您必须确保没有其他代码尝试使用该属性。绑定
是一个静态变量。这意味着,如果您在一个类中修改它,那么您就是在为所有类修改它
您应该将批次移动到\uuuu init\uuuu
中,或者创建一个新的字典,从类1复制值,以便您修改类自己的绑定。这样,当您更新字典时,您将仅针对该实例进行更新。绑定
是一个静态变量。这意味着如果您在一个类中修改它,那么您就是在为所有类修改它。您应该将该批代码移到\uuuuu init\uuuuu
中,或者创建一个新的字典,从类1复制值,以便您修改类自己的绑定。是的,我很愚蠢。我将BaseVievSet中的\uuuuu init\uuuuuuuu
更改为\uuuu new\uuuuuuu
,并将deepcopy绑定更改为创建的实例。现在它可以像我等待它一样工作了。另外,您应该能够在\uuuu init\uuuu
中转到self.bindings=deepcopy(self.bindings)
。没有真正的理由使用\uuuuu new\uuuuu
。@shadow,当然,你是对的,但我这里的代码是简化的,我有一些更难的逻辑,所以这是一个原因,为什么我要将它移动到\uuuuuuu new\uuuuuuu
,那就好了。只是确保你知道另一种方式。我根据评论创建了一个答案-如果它解决了您的问题,请随意标记我的答案为正确:)谢谢,凯文。您的建议很有效,但我需要一个解决方案,它允许在每个子视图集中没有\uuuuu init\uuuu
,因为我将有数百个。您可以从更新的问题中查看我的解决方案,我对您的意见非常感兴趣。