Defining __setattr__
overrides all setter methods / properties I define in a class. I want to use the defined setter methods in the property, if a property exists for a field and use self.__dict__[name] = value
otherwise.
Help! I found one solution that used __setitem__
, but this does not work for me
Where are properties stored in a python class? How do I access them?
How do I define __setattr__
so that it uses the properties for fields with setter methods defined?
class test(object):
def _get_gx(self):
print "get!"
return self.__dict__['gx']
def _set_gx(self, gx):
print "set!"
self.__dict__['gx'] = gx
gx = property(_get_gx, _set_gx)
def __setattr__(self, name, value):
self.__dict__[name] = value
def __init__(self):
pass
also,
Why is "get!" printed twice when I do,
x = test()
x.gx = 4
x.gx
prints:
"gets!"
"gets!"
4
You can create a property by calling property() with an appropriate set of arguments and assigning its return value to a class attribute. All the arguments to property() are optional. However, you typically provide at least a setter function.
The @property is a built-in decorator for the property() function in Python. It is used to give "special" functionality to certain methods to make them act as getters, setters, or deleters when we define properties in a class.
Python property() function returns the object of the property class and it is used to create property of a class. Parameters: fget() – used to get the value of attribute. fset() – used to set the value of attribute.
Attributes of a class can also be accessed using the following built-in methods and functions : getattr() – This function is used to access the attribute of object. hasattr() – This function is used to check if an attribute exist or not. setattr() – This function is used to set an attribute.
You need to rewrite your __setattr__
function. As per the docs, new style classes should use baseclass.__setattr__(self, attr, value)
instead of self.__dict__[attr] = value
. The former will lookup any descriptors whereas the latter will assign directly to the dict.
So rewrite your method as
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
or
def __setattr__(self, name, value):
super(Test, self).__setattr__(name, value)
and you'll be fine. The code
class Test(object):
@property
def gx(self):
print "getting gx"
return self.__dict__['gx']
@gx.setter
def gx(self, value):
print "setting gx"
self.__dict__['gx'] = value
def __setattr__(self, attr, value):
print "using setattr"
object.__setattr__(self, attr, value)
t = Test()
t.gx = 4
t.dummy = 5
print t.gx
print t.dummy
print dir(Test)
outputs
using setattr
setting gx
getting gx
using setattr
4
5
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gx']
I don't know why your version is calling the getter twice. This one doesn't. Also, to answer your question about where descriptors live, you can plainly see it as the last entry in the class dict.
It's worth noting that you don't need __setattr__
to do what you want in your example. Python will always write an assignment foo.bar = x
to foo.__dict__['bar'] = x
regardless of if there's an entry in foo.__dict__
or not. __setattr__
is for when you want to transform the value or log the assignment or something like that.
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