Reputation: 584
I would have expected the below code to raise AttributeError. What am I doing wrong?
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?
Upvotes: 0
Views: 61
Reputation: 584
Solved because of what @kindall said:
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'
The disadvantage of this solution is that the second instance created will raise AttributeError.
Example:
test = CrazyClass('a')
test_2 = CrazyClass('2')
There's probably a solution to this that's not too complicated. I'm looking for it now.
EDIT: this is my solution, but after reading @kindal's new comment at this answer, I'll implement his solution as well:
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'
Upvotes: 1
Reputation: 21
If you just define __setattr__
to raise the error, it would work.
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'
Upvotes: 0