I'm trying to bind a function to an object instance. For example, I have an object and I'm trying to bind a function to the condition attribute. The thing is that I want to do that using a decorator:
class Transition(object):
def __init__(self, enter, exit, condition=None):
if not isinstance(enter, State) or not isinstance(exit, State):
raise TypeError("Parameters should be an instance of the State class")
self.enter = enter
self.exit = exit
self.condition = None
self.effect = None
def __repr__(self):
print("Going from {} to {} with condition {} and effect {}".format(self.enter, self.exit, self.condition.__name__, self.effect.__name__))
def __eq__(self, other):
return self.enter == other.enter and self.exit == other.exit
def is_enpoint(self, endpoints):
"""
:parameter --> 'endpoints' is a tuple indicating where the transition flows(from, to)
:return --> boolean
:description --> check if the given endpoints are valid
"""
return self.enter == endpoints[0] and self.exit == endpoints[1]
Then I bind a function to the object's instance.
@bind
my_condition():
return True
After this, we should have a reference to the given function if we look at the object's instance condition attribute
f = Transition()
f1 = Transition()
@bind(f)
def condition1():
return True
@bind(f1)
def condition2():
return False
The f instance should have a reference to the condition1 function and the f2 instance should have a reference to the condition2 for the condition attribute
The decorator, of course, must get as a parameter the instance it is to make the bind to - and, the code will be much cleaner, if the decorated function itself have one parameter to be passed as the instance it is bound too: the equivalent to self if it were defined as a method. Python won't insert it automatically, but it may be called self so it is easily readable;
class Transition:
...
f = Transition
def bind(instance):
def decorator(func):
def wrapper (*args, **kwargs):
return func(instance, *args, **kwargs)
setattr(instance, func.__name__, wrapper)
return wrapper
return decorator
@bind(f)
def condition(self, ...):
...
If you want a flatter decorator, you can use functools.partial - and then I also use functools.wraps, as nice decorators should use it anyway:
import functools
...
def bind(func, instance=None):
if instance is None:
return functools.partial(bind, instance=func)
@functools.wraps(func)
def wrapper(*args, **kw):
return func(instance, *args, **kw)
setattr(instance, func.__name__, wrapper)
return wrapper
This works because in Python, when a function is attributed directly to an instance, it behaves exactly like any ordinary attribute: Python will retrieve the function, and then call it, with no modifications - not changing it to method, neither inserting a self argument). We do that by holding the instance as a nonlocal variable inside the decorator code.
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