__init__更改父类属性

时间:2017-03-15 00:37:40

标签: python

真的很困惑,它颠覆了我对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

2 个答案:

答案 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,因为它不再是类属性。 您必须确保没有其他代码尝试使用该属性。