真的很困惑,它颠覆了我对Python中OOP的理解。 我不明白最新情况。
问题。我为一些ViewSets创建了一个Parent类:
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...
所以我不明白为什么创建继承的类实例会影响父类属性。
当一个bindings_update
的ViewSet影响了另一个继承的ViewSets时,我真的得到了有趣的错误。
请帮帮我。
非常感谢大家,感谢您的帮助。
当然我忘了,我的bindings
是类属性,所以当我在子类的__init__
中更改它时,它在所有继承的实例中都发生了变化。
所以,解决方案,我曾经解决过我的问题:
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
答案 0 :(得分:1)
bindings
是一个静态变量。这意味着如果您在一个类中修改它,则需要为所有类修改它。
您应该将批次移动到__init__
或创建一个新的字典,复制第一类中的值,以便您修改该类自己的绑定。这样,当您更新字典时,您将为该实例执行 。
答案 1 :(得分:0)
bindings
是类的属性,而不是对象。
这就是为什么bindings
词典的更改似乎会影响班级的原因---因为他们 会影响班级。
如果您想将数据分配给单个对象,那就是__init__
方法的用途:
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
,因为它不再是类属性。
您必须确保没有其他代码尝试使用该属性。