I am working on a python class that has declared properties, and in which I want to add extra attributes at object instanciation (passed in the init method). I want them to be read and written. Finally, I don't want the user to be able to declare custom attributes; it should raise an Error.
class Person:
__slots__ = ["_name", "__dict__"]
def __init__(self, name, extra_arg):
self.__dict__[extra_arg] = None
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
def __getattr__(self, item):
if item in self.__dict__:
return self.__dict__[item]
raise AttributeError(item)
person = Person("gribouille", "hello")
person.custom_attribute = value # I want to prevent this
In this example, I can't manage to prevent new attributes to be declared. When I override setattr method, it seems to collide with my property and I can't manage to retrieve my "name" attribute.
CodePudding user response:
How about checking for existing attributes via hasattr
and __slots__
?
class Person:
__slots__ = ["_name", "__dict__"]
def __init__(self, name, extra_arg):
self.__dict__[extra_arg] = None
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
def __getattr__(self, item):
if item in self.__dict__:
return self.__dict__[item]
raise AttributeError(item)
def __setattr__(self, attr_name, attr_value):
if not (hasattr(self, attr_name) or attr_name in self.__slots__):
raise AttributeError(attr_name)
super().__setattr__(attr_name, attr_value)
person = Person("gribouille", "hello")
person.name = "test"
person.custom_attribute = None # Now: AttributeError: custom_attribute
CodePudding user response:
person.custom_attribute = value # I want to prevent this
To achieve this your class should do NOT have __dict__
attribute, that is __slots__
must not contain __dict__
. Consider following simple example
class C1:
__slots__ = ["__dict__"]
class C2:
__slots__ = ["x","y"]
c1 = C1()
c1.custom = "hello"
print(c1.custom) # hello
c2 = C2()
c2.x = 10
c2.y = 30
print(c2.x,c2.y) # 10 30
c2.z = 100 # cause AttributeError: 'C2' object has no attribute 'z'