I am trying to override the __setattr__ method of a Python class, since I want to call another function each time an instance attribute changes its value. However, I don't want this behaviour in the __init__ method, because during this initialization I set some attributes which are going to be used later:
So far I have this solution, without overriding __setattr__ at runtime:
class Foo(object):
def __init__(self, a, host):
object.__setattr__(self, 'a', a)
object.__setattr__(self, 'b', b)
result = self.process(a)
for key, value in result.items():
object.__setattr__(self, key, value)
def __setattr__(self, name, value):
print(self.b) # Call to a function using self.b
object.__setattr__(self, name, value)
However, I would like to avoid these object.__setattr__(...) and override __setattr__ at the end of the __init__ method:
class Foo(object):
def __init__(self, a, b):
self.a = a
self.b = b
result = self.process(a)
for key, value in result.items():
setattr(self, key, value)
# override self.__setattr__ here
def aux(self, name, value):
print(self.b)
object.__setattr__(self, name, value)
I have tried with self.__dict__['__setitem__'] = self.aux and object.__setitem__['__setitem__'] = self.aux, but none of these attemps has effect. I have read this section of the data model reference, but it looks like the assignment of the own __setattr__ is a bit tricky.
How could be possible to override __setattr__ at the end of __init__, or at least have a pythonic solution where __setattr__ is called in the normal way only in the constructor?
Unfortunately, there's no way to "override, after init" python special methods; as a side effect of how that lookup works. The crux of the problem is that python doesn't actually look at the instance; except to get its class; before it starts looking up the special method; so there's no way to get the object's state to affect which method is looked up.
If you don't like the special behavior in __init__, you could refactor your code to put the special knowledge in __setattr__ instead. Something like:
class Foo(object):
__initialized = False
def __init__(self, a, b):
try:
self.a = a
self.b = b
# ...
finally:
self.__initialized = True
def __setattr__(self, attr, value):
if self.__initialzed:
print(self.b)
super(Foo, self).__setattr__(attr, value)
Edit: Actually, there is a way to change which special method is looked up, so long as you change its class after it has been initialized. This approach will send you far into the weeds of metaclasses, so without further explanation, here's how that looks:
class AssignableSetattr(type):
def __new__(mcls, name, bases, attrs):
def __setattr__(self, attr, value):
object.__setattr__(self, attr, value)
init_attrs = dict(attrs)
init_attrs['__setattr__'] = __setattr__
init_cls = super(AssignableSetattr, mcls).__new__(mcls, name, bases, init_attrs)
real_cls = super(AssignableSetattr, mcls).__new__(mcls, name, (init_cls,), attrs)
init_cls.__real_cls = real_cls
return init_cls
def __call__(cls, *args, **kwargs):
self = super(AssignableSetattr, cls).__call__(*args, **kwargs)
print "Created", self
real_cls = cls.__real_cls
self.__class__ = real_cls
return self
class Foo(object):
__metaclass__ = AssignableSetattr
def __init__(self, a, b):
self.a = a
self.b = b
for key, value in process(a).items():
setattr(self, key, value)
def __setattr__(self, attr, value):
frob(self.b)
super(Foo, self).__setattr__(attr, value)
def process(a):
print "processing"
return {'c': 3 * a}
def frob(x):
print "frobbing", x
myfoo = Foo(1, 2)
myfoo.d = myfoo.c + 1
#SingleNegationElimination's answer is great, but it cannot work with inheritence, since the child class's __mro__ store's the original class of super class. Inspired by his answer, with little change,
The idea is simple, switch __setattr__ before __init__, and restore it back after __init__ completed.
class CleanSetAttrMeta(type):
def __call__(cls, *args, **kwargs):
real_setattr = cls.__setattr__
cls.__setattr__ = object.__setattr__
self = super(CleanSetAttrMeta, cls).__call__(*args, **kwargs)
cls.__setattr__ = real_setattr
return self
class Foo(object):
__metaclass__ = CleanSetAttrMeta
def __init__(self):
super(Foo, self).__init__()
self.a = 1
self.b = 2
def __setattr__(self, key, value):
print 'after __init__', self.b
super(Foo, self).__setattr__(key, value)
class Bar(Foo):
def __init__(self):
super(Bar, self).__init__()
self.c = 3
>>> f = Foo()
>>> f.a = 10
after __init__ 2
>>>
>>> b = Bar()
>>> b.c = 30
after __init__ 2
Related
I have a class which has fields that would all be properties with pass through getters and setters that are validated in a certain way, such that it would satisfy the following pattern:
import numpy as np
import typing
def validate_field(value, dtype: typing.Type):
limits = np.iinfo(dtype)
assert limits.min < value < limits.max, \
"value shoule be in range: {} < {} < {}".format(limits.min, value,
limits.max)
return value
class Foo:
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
#property
def a(self):
return self._a
#property
def b(self):
return self._b
#property
def c(self):
return self._c
#a.setter
def a(self, value):
self._a = validate_field(value, self._a.dtype)
#b.setter
def b(self, value):
self._b = validate_field(value, self._b.dtype)
#c.setter
def c(self, value):
self._c = validate_field(value, self._c.dtype)
I want to eliminate having to type a separate property and setter decorator for each method.
I thought about using properties manually via
self._a = a
def set_a(self, value):
self._a = validate_field(value, self._a.dtype)
self.a = property(lambda self: self._a, set_a)
...
However, it seemed I would still have to manually define a function that accessed the required member for both setter and getter, so I wasn't really saving much work.
If there was a way to automatically generate such functions via naming the parameter e.g.:
def generate_function(self, parameter)
def temp(self, value):
self.parameter = validate_field(value, self.parameter.dtype)
return temp
then I wouldn't have any issues, but right now I don't see how to accomplish this.
Is there a way for me to generate these functions with a single decorator per field or automated function based property generation in __init__?
You can use getattr() and setattr(), or direct dictionary access via self.__dict__, to parametrize the attribute name:
def validated_property(name):
def getter(self):
return getattr(self, name)
def setter(self, value):
dtype = getter(self).dtype
setattr(self, name, validate_field(value, dtype))
return property(getter, setter)
then use this as
class Foo:
# ...
a = validated_property('_a')
b = validated_property('_b')
c = validated_property('_c')
etc.
If you are using Python 3.6 or newer, you can avoid having to repeat the attribute name and generate one from the name for the property (by prefixing it with _, for example), by implementing your own descriptor object, which is passed the name under which it is being assigned to a class via the descriptor.__set_name__() method:
class ValidatedProperty:
_name = None
def __set_name__(self, owner, name):
self._name = '_' + name
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self._name)
def __set__(self, instance, value):
dtype = self.__get__(instance, type(instance)).dtype
setattr(instance, self._name, validate_field(value, dtype))
then use this like this:
class Foo:
# ...
a = ValidatedProperty()
b = ValidatedProperty()
c = ValidatedProperty()
I am using a class (MainClass) over which I have no control. I want to base my class on MainClass but to add extra functionality. I have added an attribute (index) to my class (SuperClass), but when I try convert index to a property, the #.setter seems to be ignored. What is wrong here?
class MainClass(object):
def __init__(self):
self.name = 'abc'
class SuperClass(object):
def __init__(self, main, *args, **kwargs):
super(SuperClass, self).__init__(*args, **kwargs)
self.__main = main
self._index = 0
def __getattr__(self, attr):
return getattr(self.__main, attr)
def __setattr__(self, attr, val):
if attr == '_SuperClass__main':
object.__setattr__(self, attr, val)
return setattr(self.__main, attr, val)
#property
def index(self):
return self._index
#index.setter
def index(self, value):
self._index = value
main_object = MainClass()
super_object = SuperClass(main_object)
print('x', super_object.index, super_object.name)
super_object.index = 3
print('y', super_object.index)
super_object.index += 2
print('z', super_object.index)
__getattr__ is only used when the normal lookup mechanism fails.
__setattr__, however, is called for all attempts to set an attribute. This means your current definition creates an attribute named index on the
MainClass instance, rather than accessing the property's setter.
>>> super_object._SuperClass__main.index
2
Because __setattr__ always calls setattr(self.__main, attr, val), += is effectively treated as =.
__setattr__ has to handle three cases:
The attribute _SuperClass__main itself, for when you assign to self.__main in __init__.
Assignments to attributes that exist on self.__main
Assignments to attributes specific to SuperClass.
With that in mind, try
def __setattr__(self, attr, val):
if attr == '_SuperClass__main':
super().__setattr__(attr, val)
elif hasattr(self.__main, attr):
setattr(self.__main, attr, val)
else:
super().__setattr__(attr, val)
The __setattr__ method you have defined is taking precedence over the #index.setter
Simplify the code and it should work:
class MainClass(object):
def __init__(self):
self.name = 'abc'
class SuperClass(object):
def __init__(self, main, *args, **kwargs):
super(SuperClass, self).__init__(*args, **kwargs)
self.__main = main
self._index = 0
#property
def name(self):
return self.__main.name
#name.setter
def name(self):
return self.__main.name
#property
def index(self):
return self._index
#index.setter
def index(self, value):
self._index = value
main_object = MainClass()
super_object = SuperClass(main_object)
print('x', super_object.index, super_object.name)
super_object.index = 3
print('y', super_object.index)
super_object.index += 2
print('z', super_object.index)
Output:
x 0 abc
y 3
z 5
I would also suggest the simpler option of just inheriting from MainClass instead of using composition and delegation:
class SuperClass(MainClass):
def __init__(self):
super().__init__()
self._index = 0
#property
def index(self):
return self._index
#index.setter
def index(self, value):
self._index = value
I have a class as follows:
class A:
def __init__(self):
pass
def add_attr(self, name):
setattr(self, name, 'something')
How do I define custom setter, getter for self.name? I cannot use __setattr__, __getattribute__ because that will change the behaviour of add_attr too.
EDIT: the users of this class will add arbitrary number of attributes with arbitrary names:
a = A()
a.add_attr('attr1')
a.add_attr('attr2')
I want custom behavior for only these user added attributes.
Building off #Devesh Kumar Singh’s answer, I would implement it in some way like this:
class A:
def __init__(self):
self.attrs = {}
def __setattr__(self, key, value):
if key in self.attrs:
self.set_attr(key, value)
else:
object.__setattr__(self, key, value)
def __getattribute__(self, key):
if key in self.__dict__.get(attrs, {}):
return self.__dict__['get_attr'](self, key)
return object.__getattribute__(self, key)
def get_attr(self, key):
r = self.attrs[key]
# logic
return r
def set_attr(self, key, value):
# logic
self.attrs[key] = value
def add_attr(self, key, value=None):
self.attrs[key] = value
add_attr is only used to initialise the variable the first time. You could also edit __setattr__ to set all new attributes in the self.attrs rather than self.__dict__
Custom getter and setter logic? That's what a property is made for. Usually these are used to magically mask function calls and make them look like attribute access
class MyDoubler(object):
def __init__(self, x):
self._x = x
#property
def x(self):
return x * 2
#x.setter
def x(self, value):
self._x = value
>>> md = MyDoubler(10)
>>> md.x
20
>>> md.x = 20
>>> md.x
40
>>> md._x
20
But there's no rule saying you can't abuse that power to add custom behavior to your getters and setters.
class A(object):
def __init__(self):
pass
#staticmethod
def default_getter_factory(name):
def default_getter(self):
return self.name
return default_getter
#staticmethod
def default_setter_factory(name):
def default_setter(self, value):
setattr(self, name, value)
return default_setter
def add_attr(self, name, getterfactory=None, setterfactory=None):
private_name = f"_{name}"
if getterfactory is None:
getterfactory = self.__class__.default_getter_factory
if setterfactory is None:
setterfactory = self.__class__.default_setter_factory
getter, setter = getterfactory(private_name), setterfactory(private_name)
getter = property(getter)
setattr(self.__class__, name, getter)
setattr(self.__class__, name, getter.setter(setter))
That said this is all a bit silly, and chances are that whatever it is you're trying to do is a thing that shouldn't be done. Dynamic programming is all well and good, but if I were to review code that did this, I would think very long and hard about alternative solutions before approving it. This reeks of technical debt to me.
One possibility I could think of is to have a dictionary of dynamic attributes, and set and get the dynamic attributes using the dictionary
class A:
def __init__(self):
#Dictionary of attributes
self.attrs = {}
#Set attribute
def set_attr(self, name):
self.attrs[name] = 'something'
#Get attribute
def get_attr(self, name):
return self.attrs.get(name)
a = A()
a.set_attr('var')
print(a.get_attr('var'))
The output will be something
Or an alternate is to use property decorator to add arguments explicitly outside the class, as described here
class A:
def __init__(self):
pass
a = A()
#Add attributes via property decorator
a.attr_1 = property(lambda self: self.attr_1)
a.attr_2 = property(lambda self: self.attr_2)
#Assign them values and print them
a.attr_1 = 4
a.attr_2 = 6
print(a.attr_1, a.attr_2)
The output will be 4 6
I am gonna answer my own question just for reference. This is based on others' answers here. The idea is to use default __setattr__ and __getattribute__ on attributes not added through add_attr.
class A:
def __init__(self):
self.attrs = {}
def add_attr(self, name):
self.attrs[name] = 'something'
def __getattribute__(self, name):
try:
object.__getattribute__(self, 'attrs')[name] # valid only if added by user
# custom logic and return
except (KeyError, AttributeError):
return object.__getattribute__(self, name)
def __setattr__(self, name, val):
# similar to __getattribute__
I want to define a class containing read and write methods, which can be called as follows:
instance.read
instance.write
instance.device.read
instance.device.write
To not use interlaced classes, my idea was to overwrite the __getattr__ and __setattr__ methods and to check, if the given name is device to redirect the return to self. But I encountered a problem giving infinite recursions. The example code is as follows:
class MyTest(object):
def __init__(self, x):
self.x = x
def __setattr__(self, name, value):
if name=="device":
print "device test"
else:
setattr(self, name, value)
test = MyTest(1)
As in __init__ the code tried to create a new attribute x, it calls __setattr__, which again calls __setattr__ and so on. How do I need to change this code, that, in this case, a new attribute x of self is created, holding the value 1?
Or is there any better way to handle calls like instance.device.read to be 'mapped' to instance.read?
As there are always questions about the why: I need to create abstractions of xmlrpc calls, for which very easy methods like myxmlrpc.instance,device.read and similar can be created. I need to 'mock' this up to mimic such multi-dot-method calls.
You must call the parent class __setattr__ method:
class MyTest(object):
def __init__(self, x):
self.x = x
def __setattr__(self, name, value):
if name=="device":
print "device test"
else:
super(MyTest, self).__setattr__(name, value)
# in python3+ you can omit the arguments to super:
#super().__setattr__(name, value)
Regarding the best-practice, since you plan to use this via xml-rpc I think this is probably better done inside the _dispatch method.
A quick and dirty way is to simply do:
class My(object):
def __init__(self):
self.device = self
Or you can modify self.__dict__ from inside __setattr__():
class SomeClass(object):
def __setattr__(self, name, value):
print(name, value)
self.__dict__[name] = value
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.attr2 = attr2
sc = SomeClass(attr1=1, attr2=2)
sc.attr1 = 3
You can also use object.
class TestClass:
def __init__(self):
self.data = 'data'
def __setattr__(self, name, value):
print("Attempt to edit the attribute %s" %(name))
object.__setattr__(self, name, value)
or you can just use #property:
class MyTest(object):
def __init__(self, x):
self.x = x
#property
def device(self):
return self
If you don't want to specify which attributes can or cannot be set, you can split the class to delay the get/set hooks until after initialization:
class MyTest(object):
def __init__(self, x):
self.x = x
self.__class__ = _MyTestWithHooks
class _MyTestWithHooks(MyTest):
def __setattr__(self, name, value):
...
def __getattr__(self, name):
...
if __name__ == '__main__':
a = MyTest(12)
...
As noted in the code you'll want to instantiate MyTest, since instantiating _MyTestWithHooks will result in the same infinite recursion problem as before.
TL;DR: Having to define a unique set of getters and setters for each property()'d variable sucks. Can I define generic getters and setters and use them with whatever variable I want?
Let's say I make a class with some nice getters and setters:
class Foo
def getter(self):
return _bar+' sasquatch'
def setter(self, value):
_bar = value+' unicorns'
bar = property(getter, setter)
Pretty great, right?
Now let's say I put in another variable called "baz" and I don't want it to be left out from this sasquatch/unicorn fun. Well, I guess I could make another set of getters and setters:
class Foo
def bar_getter(self):
return _bar+' sasquatch'
def bar_setter(self, value):
_bar = value+' unicorns'
bar = property(bar_getter, bar_setter)
def baz_getter(self):
return _baz+' sasquatch'
def baz_setter(self, value):
_baz = value+' unicorns'
baz = property(baz_getter, baz_setter)
But that's not very DRY and needlessly clutters my code. I guess I could make it a bit DRYer:
class Foo
def unicornify(self, value):
return value+' unicorns'
def sasquatchify(self, value):
return value+' sasquatch'
def bar_getter(self):
return self.sasquatchify(_bar)
def bar_setter(self, value):
_bar = self.unicornify(_bar)
bar = property(bar_getter, bar_setter)
def baz_getter(self):
return self.sasquatchify(_baz)
def baz_setter(self, value):
_baz = self.unicornify(_baz)
baz = property(baz_getter, baz_setter)
Although that might make my code DRYer, it's not ideal. If I wanted to unicornify and sasquatchify two more variables, I would have to add four more functions!
There must be a better way to do this. Can I use a single generic getter and/or setter across multiple variables?
Unicorn-less and sasquatch-less real-world implementation: I'm using SQLAlchemy ORM, and want to transform some of the data when storing and retrieving it from the database. Some of the transformations are applicable to more than one variable, and I don't want to clutter my classes with getters and setters.
How about just:
def sasquatchicorn(name):
return property(lambda self: getattr(self, name) + ' sasquatch',
lambda self, val: setattr(self, name, val + ' unicorns'))
class Foo(object):
bar = sasquatchicorn('_bar')
baz = sasquatchicorn('_baz')
Somewhat more generically:
def sasquatchify(val):
return val + ' sasquatch'
def unicornify(val):
return val + ' unicorns'
def getset(name, getting, setting):
return property(lambda self: getting(getattr(self, name)),
lambda self, val: setattr(self, name, setting(val)))
class Foo(object):
bar = getset('_bar', sasquatchify, unicornify)
baz = getset('_baz', sasquatchify, unicornify)
Or, with barely more work, you can use the full descriptor protocol, as described in agf's answer.
This is what the descriptor protocol property is based on is for:
class Sasicorn(object):
def __init__(self, attr):
self.attr = "_" + attr
def __get__(self, obj, objtype):
return getattr(obj, self.attr) + ' sasquatch'
def __set__(self, obj, value):
setattr(obj, self.attr, value + ' unicorns')
class Foo(object):
def __init__(self, value = "bar"):
self.bar = value
self.baz = "baz"
bar = Sasicorn('bar')
baz = Sasicorn('baz')
foo = Foo()
foo2 = Foo('other')
print foo.bar
# prints bar unicorns sasquatch
print foo.baz
# prints baz unicorns sasquatch
print foo2.bar
# prints other unicorns sasquatch
While property in a factory function may be fine for your toy example, it sounds like maybe you need more control for your real use case.
Using getattribute and setattr you can define this for all attributes past and future.
class Foo(object):
x = 3
def __getattribute__(self, attr):
return str(object.__getattribute__(self, attr)) + ' sasquatch'
def __setattr__(self, attr, value):
object.__setattr__(self, attr, str(value) + ' unicorn')
print Foo.x
f = Foo()
print f.x
f.y = 4
print f.y
This prints:
3
3 sasquatch
4 unicorn sasquatch
A colleague of mine suggested using closures to return getter and setter functions, which is what I've decided to use.
class Foo(object):
def setter(var):
def set(self, value):
setattr(self, var, value+' unicorn')
return set
def getter(var):
def get(self):
return getattr(self, var)+' sasquatch'
return get
bar = property(getter('_bar'), setter('_bar'))
f = Foo()
f.foo = 'hi'
print f.foo
But thank you all for your answers :)
# coding=utf-8
__author__ = 'Ahmed Şeref GÜNEYSU'
class Student(object):
def __init__(self, **kwargs):
for k, v in kwargs.iteritems():
self.__setattr__(k, v)
if __name__ == '__main__':
o = Student(first_name='Ahmed Şeref', last_name='GÜNEYSU')
print "{0} {1}".format(o.first_name, o.last_name)
print o.email
Gives
Ahmed Şeref GÜNEYSU
File "/Users/ahmed/PycharmProjects/sanbox/abstract_classes/object_initializer/__init__.py", line 13, in <module>
print o.email
AttributeError: 'Student' object has no attribute 'email'
Process finished with exit code 137