I'm using functools.partial
to create a closure, and using setattr
to make is callable from a class instance. The idea here is to create a set of methods at runtime.
#!/usr/bin/python
from functools import partial
class MyClass(object):
def __init__(self, val):
self.val = val
@classmethod
def generateMethods(self):
def dummy(conf1, self):
print "conf1:", conf1
print "self.val:", self.val
print
for s in ('dynamic_1', 'dynamic_2'):
closed = partial(dummy, s)
setattr(self, "test_{0}".format(s), closed)
It seems to me that partial
would bind the current value of s
to dummy
's first arg, which would free up self
to be passed when this is called from an instance.
It's not working how I'd expect
if __name__ == '__main__':
# Dynamically create some methods
MyClass.generateMethods()
# Create an instance
x = MyClass('FOO')
# The dynamically created methods aren't callable from the instance :(
#x.test_dynamic_1()
# TypeError: dummy() takes exactly 2 arguments (1 given)
# .. but these work just fine
MyClass.test_dynamic_1(x)
MyClass.test_dynamic_2(x)
Is it possible to dynamically create methods which are closures, but callable from instances of the class?
I think the new functools.partialmethod
is for this exact use case.
Straight from the docs:
>>> class Cell(object):
... def __init__(self):
... self._alive = False
... @property
... def alive(self):
... return self._alive
... def set_state(self, state):
... self._alive = bool(state)
... set_alive = partialmethod(set_state, True)
... set_dead = partialmethod(set_state, False)
...
>>> c = Cell()
>>> c.alive
False
>>> c.set_alive()
>>> c.alive
True
The issue is that when you're calling them using the instances they are actually not bound methods, i.e they have no knowledge about the instance. Bound methods insert the self
to the arguments of the underlying function automatically when called, it is stored in the __self__
attribute of bound method.
So, override __getattribute__
and see if the object being fetched is an instance of partial
type or not, if yes, convert it to a bound method using types.MethodType
.
Code:
#!/usr/bin/python
from functools import partial
import types
class MyClass(object):
def __init__(self, val):
self.val = val
@classmethod
def generateMethods(self):
def dummy(conf1, self):
print "conf1:", conf1
print "self.val:", self.val
print
for s in ('dynamic_1', 'dynamic_2'):
closed = partial(dummy, s)
setattr(self, "test_{0}".format(s), closed)
def __getattribute__(self, attr):
# Here we do have access to the much need instance(self)
obj = object.__getattribute__(self, attr)
if isinstance(obj, partial):
return types.MethodType(obj, self, type(self))
else:
return obj
if __name__ == '__main__':
MyClass.generateMethods()
x = MyClass('FOO')
x.test_dynamic_1()
x.test_dynamic_2()
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