I love Python's @property
decorate system. I love that you can run custom code when you call aClassObect.attribute
. Especially for validating data when you're setting an attribute. However, one thing that I want, but I can't find, is a way to run custom code when trying to set an attribute that doesn't exist. For example, say I've got the following class:
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
Now, if I have myObj
, which is an instance of class C
, and I call myObject.x = 42
, it will run the appropriate setter, which is great for validating data. But this doesn't stop someone from calling myOjbect.b = 47
, and it will happily create a new attribute called b
. Is there some way to run special code when setting a new attribute? I'd the ability to raise errors to say something like "error, this attribute doesn't exist".
To elaborate a bit on Elazar's answer, you'll want to override the __setattr__
magic method and do a check in it to see if the attribute already exists. If not, raise an exception. Here's what that could look like for your class:
def __setattr__(self, name, value):
if not hasattr(self, name): # would this create a new attribute?
raise AttributeError("Creating new attributes is not allowed!")
super(C, self).__setattr__(name, value)
It's also possible to override __getattr__
or __getattribute__
if you want to deal with requests for non-existent attributes, but for the specific issue you have described this is probably not necessary.
Note that the __setattr__
method I show above won't entirely play nicely with your current property, due to the deleter. If you delete myObj.x
, afterwards getter will raise an exception if you try to access x
later. This means that hasattr
will return False
when checking if x
is an existing attribute, and so my __getattr__
won't let you recreate it. If you really need to be able to delete (and recreate) specific attributes, you'll need a more sophisticated __setattr__
implementation (it could check in the class for a property with the desired name, rather than just relying on hasattr
).
override __getattr__
and __setattr__
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With