如何在__init__处将新的特殊方法附加到实例?

时间:2019-01-25 20:44:23

标签: python

我希望下面的代码会引发AttributeError。我在做什么错了?

class CrazyClass:
    def __init__(self, a):
        self.a = a
        self.b = 'b'

        def difficult_set_attribute(key, value):
            if key not in self.__dict__:
                raise AttributeError('You may not set a new attribute, unless you do it in the secret way!')

        self.__setattr__ = difficult_set_attribute


test = CrazyClass('a')
test.c = 'c'  # why doesn't this raise AttributeError?

2 个答案:

答案 0 :(得分:1)

已解决,因为@kindall说了什么:

class CrazyClass:
    def __init__(self, a):
        self.a = a
        self.b = 'b'

        # the assignment is only done at the first instantiation
        if CrazyClass.__setattr__ is object.__setattr__:
            def difficult_set_attribute(cls, key, value):
                if key not in cls.__dict__:
                    raise AttributeError('You may not set a new attribute, unless you do it in the secret way!')

            CrazyClass.__setattr__ = difficult_set_attribute


test = CrazyClass('a')
test.c = 'this raises AttributeError'

此解决方案的缺点是创建的第二个实例将引发AttributeError。

示例:

test = CrazyClass('a')
test_2 = CrazyClass('2')

可能有一个不太复杂的解决方案。我现在正在寻找。

编辑:这是我的解决方案,但是在此答案下阅读@kindal的新评论后,我也将实现他的解决方案:

class CrazyClass:
    __temporary_allow_setattr = False

    def __init__(self, a):
        self.__temporary_allow_setattr = True
        self.a = a
        self.b = 'b'
        self.__temporary_allow_setattr = False

        if CrazyClass.__setattr__ is object.__setattr__:
            def difficult_set_attribute(cls, key, value):
                if key == '_CrazyClass__temporary_allow_setattr' or cls.__temporary_allow_setattr:
                    cls.__dict__[key] = value
                else:
                    raise AttributeError('You may not set a new attribute, unless you do it in the secret way!')

            CrazyClass.__setattr__ = difficult_set_attribute


test = CrazyClass('a')
test._CrazyClass__temporary_allow_setattr = True
test.c = 'this will succeed'
test_2 = CrazyClass('b')
test_2.c = 'this will fail'

答案 1 :(得分:0)

如果您仅定义__setattr__来引发错误,那么它将起作用。

class CrazyClass:
    def __init__(self, a):
        self.a = a
        self.b = 'b'

    def __setattr__(self, key, value):
        if key not in self.__dict__:
            raise AttributeError('You may not set a new attribute, unless you do it in the secret way!')

test = CrazyClass('a')
test.c = 'c'
相关问题