How to combine functions in a class in Python? - python

I have a code like this. In my original code I would like to call two or more methods when a button is clicked.
class MyApp(object):
#staticmethod
def combine_funcs(*funcs):
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
return combined_func
def __init__(self):
MyApp.combine_funcs(self.my_first_func, self.my_second_func)
def my_first_func(self):
print("First")
def my_second_func(self):
print("Second")
my_app = MyApp()
When I run this nothing is printed. Why?

A method is not much more than a member of a class that happens to be a function. The magic is just that when it is called on an object (a.func(x...)) the object is automatically prepended in the argument list resulting in the actual call A.func(a, x...).
What you want can be obtained that way:
class MyApp(object):
# prepend with _ to "hide" the symbol
def _combine_funcs(*funcs):
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
return combined_func
def my_first_func(self):
print("First")
def my_second_func(self):
print("Second")
# actually declares combined as a method of MyClass
combined = _combine_funcs(my_first_func, my_second_func)
Usage:
>>> a = MyApp()
>>> a.combined()
First
Second
But a much cleaner way would be to use a decorator for that in Python 3:
import inspect
def combine_funcs(*funcs):
def outer(f):
def combined_func(*args, **kwargs): # combine a bunch of functions
for f in funcs:
x = f(*args, *kwargs)
return x # returns return value of last one
combined_func.__doc__ = f.__doc__ # copy docstring and signature
combined_func.__signature__ = inspect.signature(f)
return combined_func
return outer
class MyApp(object):
def my_first_func(self):
print("First")
def my_second_func(self):
print("Second")
#combine_funcs(my_first_func, my_second_func)
def combined(self):
"""Combined function"""
pass
The decorator will replace the body but will keep the docstring and the signature of the original function (in Python 3). You can then use it normally:
>>> a = MyApp()
>>> a.combined()
First
Second
>>> help(a.combined)
Help on method combined_func in module __main__:
combined_func() method of __main__.MyApp instance
Combined function
>>> help(MyApp.combined)
Help on function combined_func in module __main__:
combined_func(self)
Combined function

You're calling combine_funcs, but the function within that, combined_func, is not being called.
Is there a reason not to simplify to:
class MyApp(object):
#staticmethod
def combined_func(*args, **kwargs):
for f in args:
f()
def __init__(self):
MyApp.combined_func(self.my_first_func, self.my_second_func)
def my_first_func(self):
print("First")
def my_second_func(self):
print("Second")
my_app = MyApp()

Related

Python Decorator in Inheritance

I have the following code:
class Foo:
iterations = 3
class Bar(Foo):
#test_decorator(<????>)
def hello(self):
print("Hello world!")
def test_decorator(input):
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Something is happening before the function is called.")
for _ in range(input):
func(*args, **kwargs)
print("Something is happening after the function is called.")
return wrapper
return my_decorator
I would like to pass my iterations variable which is in the parent class to the decorator test_decorator which is in my child class, instead of <????>
I tried the following ways:
self.iteration doesn't work since we don't have access to self
Foo.iterations doesn't work because it will act as a constant, if we change iterations "hello world" will be displayed only 3 times instead of 5 (as in the example below)
Example:
b = Bar()
b.iterations = 5
b.hello()
# "hello world" will be displayed 3 times
Is there a way to do this or is it anti pattern to python ?
I found a solution to your problem.
The idea is to write your own decorator.
Since that decorator is a function wrapping your method, it has access to the class instance using the *args first index. From there, you can access the iterations variable:
def decorator(iterations, source):
def inner_transition(func):
return func
return inner_transition
def custom_transition(source):
def inner_custom_transition(func):
def wrapper(*args, **kwargs):
iterations = args[0].iterations
return decorator(iterations=iterations, source=source)(func)(*args, **kwargs)
return wrapper
return inner_custom_transition
class Foo:
iterations = 3
class Bar(Foo):
#custom_transition(source="my_source")
def hello(self, string_to_show, additional_string = "default"):
print(string_to_show)
print(additional_string)
bar = Bar()
bar.hello("hello", additional_string="++++")
Result:
hello
++++

Change a global variable that is used as default argument in a decorator in python

I have a function that uses a global x variable as default value for its argument. However, in the main() function called in the if __name__ == '__main__': block I would like to allow the user to change this variable in order to modify the behavior of the function. This does not seem to work because when I run the script x in the function is already occupied with 9 in this case and not changed to 10, as I would like to have it.
x = 9
def function(var=x):
print(var)
def main():
global x
x = 10
function()
if __name__ == '__main__':
main()
Simply calling function(var=x) in main() would not work in my case because function() is actually a decorator and it is rather:
from module import decorator
x = 9
#decorator(var1=x, var2=15)
def function():
pass
def main():
global x
x = 10
function()
if __name__ == '__main__':
main()
Also, the decorator is imported from another module so I think the answer posted in Defining a default argument as a global variable might not work either. Even more complicated, the decorator is supposed to take other arguments as well, so using a class as suggested by kederrac below does not work either. However, since this module is made by myself I could copy the necessary code into my new script but I would like to avoid that if possible.
Thank you very much in advance for your help!
you can use a class as a decorator
class my_decorator:
x = 9
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
print(my_decorator.x)
return self.f(*args, **kwargs)
#my_decorator
def function():
pass
def main():
my_decorator.x = 4
function()
main()
# 4
if you want to pass a param to your decorator you may use:
from functools import partial
class my_decorator:
x = 9
def __init__(self, f, param1):
self.f = f
self.param1 = param1
def __call__(self, *args, **kwargs):
print(my_decorator.x)
print(self.param1)
return self.f(*args, **kwargs)
#partial(my_decorator, param1='test_param')
def function():
pass
def main():
my_decorator.x = 4
function()
main()
# 4
# test_param
I have found a solution in the Python Cookbook by Beazley and Jones, chapter 9.5. They introduce accessor functions which are able to change variables by the use of nonlocal. I have attached an example solution.
from functools import wraps, partial
def attach_wrapper(obj, func=None):
if func is None:
return partial(attach_wrapper, obj)
setattr(obj, func.__name__, func)
return func
def decorator(arg1, arg2):
def decorate(func):
#wraps(func)
def wrapper(*args, **kwarg):
...
do_something_with_arg1_and_arg2
...
return func(*args, **kwargs)
#attach_wrapper(wrapper)
def set_arg1(new_arg1):
nonlocal arg1
arg1 = new_arg1
return wrapper
return decorate
So now you can decorate your function() with the decoratorand subsequently change arg1 using set_arg1() as a method of function() like so:
#decorator(arg1=9, arg2=15)
def function():
pass
function.set_arg1(10)
The only thing is, that in this case I need to call this method for all the functions I am applying the decorator on, so also not ideal.

How to decorate an instance method with another instance method? [duplicate]

Can one write something like:
class Test(object):
def _decorator(self, foo):
foo()
#self._decorator
def bar(self):
pass
This fails: self in #self is unknown
I also tried:
#Test._decorator(self)
which also fails: Test unknown
I would like to temporarily change some instance variables
in the decorator and then run the decorated method, before
changing them back.
Would something like this do what you need?
class Test(object):
def _decorator(foo):
def magic( self ) :
print "start magic"
foo( self )
print "end magic"
return magic
#_decorator
def bar( self ) :
print "normal call"
test = Test()
test.bar()
This avoids the call to self to access the decorator and leaves it hidden in the class namespace as a regular method.
>>> import stackoverflow
>>> test = stackoverflow.Test()
>>> test.bar()
start magic
normal call
end magic
>>>
edited to answer question in comments:
How to use the hidden decorator in another class
class Test(object):
def _decorator(foo):
def magic( self ) :
print "start magic"
foo( self )
print "end magic"
return magic
#_decorator
def bar( self ) :
print "normal call"
_decorator = staticmethod( _decorator )
class TestB( Test ):
#Test._decorator
def bar( self ):
print "override bar in"
super( TestB, self ).bar()
print "override bar out"
print "Normal:"
test = Test()
test.bar()
print
print "Inherited:"
b = TestB()
b.bar()
print
Output:
Normal:
start magic
normal call
end magic
Inherited:
start magic
override bar in
start magic
normal call
end magic
override bar out
end magic
What you're wanting to do isn't possible. Take, for instance, whether or not the code below looks valid:
class Test(object):
def _decorator(self, foo):
foo()
def bar(self):
pass
bar = self._decorator(bar)
It, of course, isn't valid since self isn't defined at that point. The same goes for Test as it won't be defined until the class itself is defined (which its in the process of). I'm showing you this code snippet because this is what your decorator snippet transforms into.
So, as you can see, accessing the instance in a decorator like that isn't really possible since decorators are applied during the definition of whatever function/method they are attached to and not during instantiation.
If you need class-level access, try this:
class Test(object):
#classmethod
def _decorator(cls, foo):
foo()
def bar(self):
pass
Test.bar = Test._decorator(Test.bar)
import functools
class Example:
def wrapper(func):
#functools.wraps(func)
def wrap(self, *args, **kwargs):
print("inside wrap")
return func(self, *args, **kwargs)
return wrap
#wrapper
def method(self):
print("METHOD")
wrapper = staticmethod(wrapper)
e = Example()
e.method()
This is one way to access(and have used) self from inside a decorator defined inside the same class:
class Thing(object):
def __init__(self, name):
self.name = name
def debug_name(function):
def debug_wrapper(*args):
self = args[0]
print 'self.name = ' + self.name
print 'running function {}()'.format(function.__name__)
function(*args)
print 'self.name = ' + self.name
return debug_wrapper
#debug_name
def set_name(self, new_name):
self.name = new_name
Output (tested on Python 2.7.10):
>>> a = Thing('A')
>>> a.name
'A'
>>> a.set_name('B')
self.name = A
running function set_name()
self.name = B
>>> a.name
'B'
The example above is silly, but it works.
Here's an expansion on Michael Speer's answer to take it a few steps further:
An instance method decorator which takes arguments and acts on a function with arguments and a return value.
class Test(object):
"Prints if x == y. Throws an error otherwise."
def __init__(self, x):
self.x = x
def _outer_decorator(y):
def _decorator(foo):
def magic(self, *args, **kwargs) :
print("start magic")
if self.x == y:
return foo(self, *args, **kwargs)
else:
raise ValueError("x ({}) != y ({})".format(self.x, y))
print("end magic")
return magic
return _decorator
#_outer_decorator(y=3)
def bar(self, *args, **kwargs) :
print("normal call")
print("args: {}".format(args))
print("kwargs: {}".format(kwargs))
return 27
And then
In [2]:
test = Test(3)
test.bar(
13,
'Test',
q=9,
lollipop=[1,2,3]
)
​
start magic
normal call
args: (13, 'Test')
kwargs: {'q': 9, 'lollipop': [1, 2, 3]}
Out[2]:
27
In [3]:
test = Test(4)
test.bar(
13,
'Test',
q=9,
lollipop=[1,2,3]
)
​
start magic
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-3-576146b3d37e> in <module>()
4 'Test',
5 q=9,
----> 6 lollipop=[1,2,3]
7 )
<ipython-input-1-428f22ac6c9b> in magic(self, *args, **kwargs)
11 return foo(self, *args, **kwargs)
12 else:
---> 13 raise ValueError("x ({}) != y ({})".format(self.x, y))
14 print("end magic")
15 return magic
ValueError: x (4) != y (3)
I found this question while researching a very similar problem. My solution is to split the problem into two parts. First, you need to capture the data that you want to associate with the class methods. In this case, handler_for will associate a Unix command with handler for that command's output.
class OutputAnalysis(object):
"analyze the output of diagnostic commands"
def handler_for(name):
"decorator to associate a function with a command"
def wrapper(func):
func.handler_for = name
return func
return wrapper
# associate mount_p with 'mount_-p.txt'
#handler_for('mount -p')
def mount_p(self, slurped):
pass
Now that we've associated some data with each class method, we need to gather that data and store it in a class attribute.
OutputAnalysis.cmd_handler = {}
for value in OutputAnalysis.__dict__.itervalues():
try:
OutputAnalysis.cmd_handler[value.handler_for] = value
except AttributeError:
pass
I use this type of decorator in some debugging situations, it allows overriding class properties by decorating, without having to find the calling function.
class myclass(object):
def __init__(self):
self.property = "HELLO"
#adecorator(property="GOODBYE")
def method(self):
print self.property
Here is the decorator code
class adecorator (object):
def __init__ (self, *args, **kwargs):
# store arguments passed to the decorator
self.args = args
self.kwargs = kwargs
def __call__(self, func):
def newf(*args, **kwargs):
#the 'self' for a method function is passed as args[0]
slf = args[0]
# replace and store the attributes
saved = {}
for k,v in self.kwargs.items():
if hasattr(slf, k):
saved[k] = getattr(slf,k)
setattr(slf, k, v)
# call the method
ret = func(*args, **kwargs)
#put things back
for k,v in saved.items():
setattr(slf, k, v)
return ret
newf.__doc__ = func.__doc__
return newf
Note: because I've used a class decorator you'll need to use #adecorator() with the brackets on to decorate functions, even if you don't pass any arguments to the decorator class constructor.
The simple way to do it.
All you need is to put the decorator method outside the class.
You can still use it inside.
def my_decorator(func):
#this is the key line. There's the aditional self parameter
def wrap(self, *args, **kwargs):
# you can use self here as if you were inside the class
return func(self, *args, **kwargs)
return wrap
class Test(object):
#my_decorator
def bar(self):
pass
Declare in inner class.
This solution is pretty solid and recommended.
class Test(object):
class Decorators(object):
#staticmethod
def decorator(foo):
def magic(self, *args, **kwargs) :
print("start magic")
foo(self, *args, **kwargs)
print("end magic")
return magic
#Decorators.decorator
def bar( self ) :
print("normal call")
test = Test()
test.bar()
The result:
>>> test = Test()
>>> test.bar()
start magic
normal call
end magic
>>>
Decorators seem better suited to modify the functionality of an entire object (including function objects) versus the functionality of an object method which in general will depend on instance attributes. For example:
def mod_bar(cls):
# returns modified class
def decorate(fcn):
# returns decorated function
def new_fcn(self):
print self.start_str
print fcn(self)
print self.end_str
return new_fcn
cls.bar = decorate(cls.bar)
return cls
#mod_bar
class Test(object):
def __init__(self):
self.start_str = "starting dec"
self.end_str = "ending dec"
def bar(self):
return "bar"
The output is:
>>> import Test
>>> a = Test()
>>> a.bar()
starting dec
bar
ending dec
I have a Implementation of Decorators that Might Help
import functools
import datetime
class Decorator(object):
def __init__(self):
pass
def execution_time(func):
#functools.wraps(func)
def wrap(self, *args, **kwargs):
""" Wrapper Function """
start = datetime.datetime.now()
Tem = func(self, *args, **kwargs)
end = datetime.datetime.now()
print("Exection Time:{}".format(end-start))
return Tem
return wrap
class Test(Decorator):
def __init__(self):
self._MethodName = Test.funca.__name__
#Decorator.execution_time
def funca(self):
print("Running Function : {}".format(self._MethodName))
return True
if __name__ == "__main__":
obj = Test()
data = obj.funca()
print(data)
You can decorate the decorator:
import decorator
class Test(object):
#decorator.decorator
def _decorator(foo, self):
foo(self)
#_decorator
def bar(self):
pass

access to the name of decorator by the decoree

I am decorating a function foo with a_decorator
#a_decorator(params)
def foo(x):
# print('Called',decorator_name)
# other magic
Is there a way to access the name a_decorator inside foo so that I can print
'Called a_decorator'
def a_decorator(some_function):
def wrapper():
some_function()
return some_val
return wrapper
It can be done by attaching decorator name to wrapper function:
from functools import wraps
def a_decorator(fn):
#wraps(fn)
def wrapper(*args, **kwargs):
val = fn(*args, **kwargs)
# some action
return val
wrapper.decorated_by = a_decorator
return wrapper
#a_decorator
def foo(x):
print(x, foo.decorated_by.__name__)
foo('test') # prints: test a_decorator
Function in python are first class and you can treat them as an object, attach attributes, etc.

Python class method decorator

I write a decorator for class method
def decor(method):
def wrapped(self, *args, **kwargs):
return method(self, *args, **kwargs)
# [*]
return wrapped
I would like use this like:
class A(metaclass=mymetaclass):
#decor
def meth(self):
pass
How I can in decorator add method/variable to class which has decorated method? I need it do near [*].
Inside wrapped I could write self.__class__, but what to do here?
I cannot imagine a way to meet such a requirement, because decor function only receives a function object that knows nothing about a containing class.
The only workaround that I can imagine is to use a parameterized decorator and pass it the class being decorated
def decor(cls):
def wrapper(method):
def wrapped(self, *args, **kwargs):
return self.method(*args, **kwargs)
print method # only a function object here
return wrapped
print cls # here we get the class and can manipulate it
return wrapper
class A
#decor(A)
def method(self):
pass
Alternatively, you could decorate the class itself:
def cdecor(cls):
print 'Decorating', cls # here we get the class and can manipulate it
return cls
#cdecor
class B:
def meth(self):
pass
gives:
Decorating __main__.B
It looks like you just wanted to decorate one of a classes functions, not specifically an #classmethod. Here's a simple way that I did it when I wanted to call a classes save function when the function returned a successful result:
def save_on_success(func):
""" A decorator that calls a class object's save method when successful """
def inner(self, *args, **kwargs):
result = func(self, *args, **kwargs)
if result:
self.save()
return result
return inner
Here is an example of how it was used:
class Test:
def save(self):
print('saving')
#save_on_success
def test(self, var, result=True):
print('testing, var={}'.format(var))
return result
Testing to make sure it works as expected:
>>> x = Test()
>>> print(x.test('test True (should save)', result=True))
testing, var=test True (should save)
saving
True
>>> print(x.test('test False (should not save)', result=False))
testing, var=test False (should not save)
False
It looks like it is not directly possible, according to this response :
Get Python function's owning class from decorator
What you could do instead is providing a decorator for your class, something like that :
class InsertMethod(object):
def __init__(self, methodToInsert):
self.methodToInsert = methodToInsert
def __call__(self, classObject):
def wrapper(*args, **kwargs):
setattr(classObject, self.methodToInsert.__name__, self.methodToInsert)
return classObject(*args, **kwargs)
return wrapper
def IWillBeInserted(self):
print "Success"
#InsertMethod(IWillBeInserted)
class Something(object):
def __init__(self):
pass
def action(self):
self.IWillBeInserted()
a = Something()
a.action()
Actually, you may decorate the class itself:
def class_decorator(class_):
class_.attribute = 'value'
class_.method = decorate(class_.method)
return class_
#class_decorator
class MyClass:
def method(self):
pass
I'm a little late to the party, but late is better than never eh? :)
We can do this by decorating our class method with a decorator which is itself a class object, say B, and then hook into the moment when Python calls B.__get__ so to fetch the method. In that __get__ call, which will be passed both the owner class and the newly generated instance of that class, you can elect to either insert your method/variable into the original owner class, or into the newly defined instance.
class B(object):
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
return self.f(*args, **kwargs)
def __get__(self, instance, owner):
instance.inserted = True
# owner.inserted = True
def wrapper(*args, **kwargs):
return self(instance, *args, **kwargs)
return wrapper
class A:
#B
def method(self):
pass
if __name__ == "__main__":
a = A()
a.method()
b = A()
print(hasattr(a, 'inserted'))
print(hasattr(b, 'inserted'))
In this example, we're wrapping def method(self) with #B. As written, the inserted attribute inserted will only persist in the a object because it's being applied to the instance. If we were to create a second object b as shown, the inserted attribute is not included. IE, hasattr(a, 'inserted') prints True and hasattr(b, 'inserted') prints False. If however we apply inserted to the owner class (as shown in the commented out line) instead, the inserted attribute will persist into all future A() objects. IE hasattr(a, 'inserted') prints True and hasattr(b, 'inserted') prints True, because b was created after a.method() was called.

Categories