python decorator that call a function with delay - python

why this code does not work?
from threading import Timer
def delayed(seconds):
def decorator(f):
def wrapper(*args, **kargs):
Timer(seconds, f, args, kargs)
return wrapper
return decorator
#delayed(1)
def foo():
'''this function does not return'''
print('foo')
foo()
print('dudee')
i except this result:
dudee
foo
i have only
dudee

Because you didn't start your timer try like this:
from threading import Timer
def delayed(seconds):
def decorator(f):
def wrapper(*args, **kargs):
t = Timer(seconds, f, args, kargs)
t.start()
return wrapper
return decorator
#delayed(1)
def foo():
print('foo')
foo()
print('dudee')

Related

Accessing class property as decorator argument

I'm trying to apply a conditional decorator as described in another stackoverflow post, but I'd like the condition to be set from inside the class its being used. Instead I get a Reference error pointing that self is not defined.
class foo:
def __init__(self):
self.debug = True
#conditional_decorator(decorator, self.debug)
def function(self):
pass
I tried defining a global variable and updating it from inside the __init__() method but it kept its original value when called as an argument of the decorator.
debug = None
class foo:
def __init__(self):
self.debug = True
global debug
debug = self.debug
#conditional_decorator(decorator, debug)
def function(self):
pass
The only way it worked was declaring a global variable and setting it outside of the class.
How can I apply the value of the class property to the decorator?
An update to the answer given by #Maurice Meyer which allows a member of the class to be nominated:
from functools import wraps
def conditional_decorator(decoration, member):
def decorator(method):
predecorated = decoration(method)
#wraps(method)
def wrapper(*args, **kwargs):
self = args[0]
condition = getattr(self, member)
if not condition:
return method(*args, **kwargs)
return predecorated(*args, **kwargs)
return wrapper
return decorator
#And used like this for example:
class foo:
def __init__(self, debug):
self.debug = debug
#conditional_decorator(decorator, "debug")
def function(self):
pass
f1 = foo(True)
f1.function()
This is how you make a decorator handle classes and arguments:
from functools import wraps
def conditional_decorator(param):
def real_decorator(fn):
#wraps(fn)
def wrapper(*args, **kw):
cls = args[0]
print(cls.debug)
print(param)
return wrapper
return real_decorator
class foo:
def __init__(self):
self.debug = True
#conditional_decorator('param1')
def function(self):
pass
f = foo()
f.function()
Output:
True
param1
The decorator should not be conditional. Rather, when the decorated function is called, it should look at self.debug to determine whether to use the original function or the wrapped part.
def conditional_decorator(dec):
def decorator(func):
def _(self, *args, **kwargs):
f = func
if self.debug:
f = dec(f)
return f(self, *args, **kwargs)
return _
return decorator
def decorator(f):
def _(*args, **kwargs):
print("Decorated")
return f(*args, **kwargs)
return _
class foo:
def __init__(self, debug):
self.debug = debug
#conditional_decorator(decorator)
def function(self):
print("foo stuff")
foo(True).function()
print("===")
foo(False).function()
outputs
Decorated
foo stuff
===
foo stuff

Why do we use `wraps` instead of `update_wrapper` as a decorator?

Decorator functools.wraps calls method functools.update_wrapper.
I want to understand the need to use wrap instead of update_wrapper.
Why can't we use update_wrapper as decorator instead of using wraps?
For example:
from functools import update_wrapper
def wrap1(func):
def call_it(*args, **kwargs):
"""wrap func: call_it1"""
print('before call in call_it1')
return func(*args, **kwargs)
return update_wrapper(call_it, func)
#wrap1
def hello1():
"""test hello 1"""
print('hello world1')
hello1()
and
def wrap3(func):
#wraps(func)
def call_it(*args, **kwargs):
"""wrap func: call_it3"""
print('before call in call_it3')
return func(*args, **kwargs)
return call_it
#wrap3
def hello3():
"""test hello 3"""
print('hello world3')
hello3()
work. But why the following doesn't?
def wrap2(func):
#update_wrapper(wrapped=func) # error, see below
def call_it(*args, **kwargs):
"""wrap func: call_it2"""
print('before call in call_it2')
return func(*args, **kwargs)
return call_it
#wrap2
def hello2():
"""test hello 2"""
print('hello world2')
hello2()
with error
TypeError: update_wrapper() missing 1 required positional argument: 'wrapper'
The declarations of wraps and update_wrapper are:
#functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
and
functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
The positional argument wrapper is the first argument to update_wrapper,
so why doesn't the following pick up call_it as wrapper argument to update_wrapper?
#update_wrapper(wrapped=func)
def call_it(*args, **kwargs):
Is there some way to use update_wrapper as a decorator instead of using wraps?
Using # as a decorator basically boils down to this:
#(value)
def f(...):
...
Being the same as:
def f(...):
...
f = (value)(f)
Now if we apply it to your case:
#update_wrapper(wrapped=func)
def call_it(*args, **kwargs):
...
def call_it(*args, **kwargs):
...
call_it = update_wrapper(wrapped=func)(call_it)
The problem here is that the first time, it is only called with the second argument. It then raises the error immediately.
This is because update_wrapper is not designed to be used as a decorator, but wraps is a decorator (factory).

Check that a function uses print-function in python

I want to write a decorator in python: if a called function contains print's, the decorator prints her name before this function being called. I'm familiar with decorators syntax, but I have a problem with checking if a function has print within itself.
def preceeding_name(func):
#wraps(func)
def wrapper(*args, **kwargs):
if 'print' in func:
print(func.__name__)
result = func(*args, **kwargs)
return result
return wrapper
It is not necessary to check if the print's from function will actually be called.
This can be done by holding the buffer of 'print' from flushing and checking it to see if a print has been done.
class Out(object):
def write(self,s):
self.s += s
def __init__(self)
self.s = ''
Now to check
def wrapper(*args, **kwargs):
our_out = Out()
sys.stdout = our_out
result = func(*args, **kwargs)
if len(our_out.s)>0:
sys.stdout = sys.__stdout__
print func.__name__
for s in our_out.s.split('\n'):
print s
return result
I this case you can redefine print
def preceeding_name(func):
#wraps(func)
def wrapper(*args, **kwargs):
old_print = print
def print(*arg, **kwarg):
old_print(func.__name__)
old_print(*arg, **kwarg)
result = func(*args, **kwargs)
return result
return wrapper
EDIT:
i test and this work
old_print = print
def preceeding_name(func):
def print(*arg, **kwarg):
old_print(func.__name__, end='')
old_print(*arg, **kwarg)
def wrapper(*args, **kwargs):
print('')
result = func(*args, **kwargs)
return result
return wrapper
#preceeding_name
def a():
print('hi')
a()
#preceeding_name
def b():
print('hi')
b()
EDIT2:
old_print = print
def preceeding_name(func):
global print
def print(*arg, **kwarg):
old_print(func.__name__)
old_print(*arg, **kwarg)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result
return wrapper
#preceeding_name
def a():
print('hi')
a()
#preceeding_name
def b():
# print('hi')
pass
b()

Function acting as both decorator and context manager in Python?

This might be pushing things a little too far, but mostly out of curiosity..
Would it be possible to have a callable object (function/class) that acts as both a Context Manager and a decorator at the same time:
def xxx(*args, **kw):
# or as a class
#xxx(foo, bar)
def im_decorated(a, b):
print('do the stuff')
with xxx(foo, bar):
print('do the stuff')
Starting in Python 3.2, support for this is even included in the standard library. Deriving from the class contextlib.ContextDecorator makes it easy to write classes that can be used as both, a decorator or a context manager. This functionality could be easily backported to Python 2.x -- here is a basic implementation:
class ContextDecorator(object):
def __call__(self, f):
#functools.wraps(f)
def decorated(*args, **kwds):
with self:
return f(*args, **kwds)
return decorated
Derive your context manager from this class and define the __enter__() and __exit__() methods as usual.
In Python 3.2+, you can define a context manager that is also a decorator using #contextlib.contextmanager.
From the docs:
contextmanager() uses ContextDecorator so the context managers it creates can be used as decorators as well as in with statements
Example usage:
>>> from contextlib import contextmanager
>>> #contextmanager
... def example_manager(message):
... print('Starting', message)
... try:
... yield
... finally:
... print('Done', message)
...
>>> with example_manager('printing Hello World'):
... print('Hello, World!')
...
Starting printing Hello World
Hello, World!
Done printing Hello World
>>>
>>> #example_manager('running my function')
... def some_function():
... print('Inside my function')
...
>>> some_function()
Starting running my function
Inside my function
Done running my function
class Decontext(object):
"""
makes a context manager also act as decorator
"""
def __init__(self, context_manager):
self._cm = context_manager
def __enter__(self):
return self._cm.__enter__()
def __exit__(self, *args, **kwds):
return self._cm.__exit__(*args, **kwds)
def __call__(self, func):
def wrapper(*args, **kwds):
with self:
return func(*args, **kwds)
return wrapper
now you can do:
mydeco = Decontext(some_context_manager)
and that allows both
#mydeco
def foo(...):
do_bar()
foo(...)
and
with mydeco:
do_bar()
Here's an example:
class ContextDecorator(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
print("init", foo, bar)
def __call__(self, f):
print("call")
def wrapped_f():
print("about to call")
f()
print("done calling")
return wrapped_f
def __enter__(self):
print("enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("exit")
with ContextDecorator(1, 2):
print("with")
#ContextDecorator(3, 4)
def sample():
print("sample")
sample()
This prints:
init 1 2
enter
with
exit
init 3 4
call
about to call
sample
done calling
Although I agree (and upvoted) #jterrace here, I'm adding a very slight variation that returns the decorated function, and includes arguments for both the decorator and the decorated function.
class Decon:
def __init__(self, a=None, b=None, c=True):
self.a = a
self.b = b
self.c = c
def __enter__(self):
# only need to return self
# if you want access to it
# inside the context
return self
def __exit__(self, exit_type, exit_value, exit_traceback):
# clean up anything you need to
# otherwise, nothing much more here
pass
def __call__(self, func):
def decorator(*args, **kwargs):
with self:
return func(*args, **kwargs)
return decorator

is there any way to run a other function after a function run finish?

def foo():
pass
def bar():
print 'good bay'
two function like blow
and now i want to run bar function after foo run finish
is there some method like class use __del__?
as i know in class method i can use __del__ like follow:
class A(object):
def __init__(self):
pass
def __del__(self):
bar()
but i can't use foo.__del__
is there any other method to do this ?
This is what decorators are for. This decorator, used on foo with bar as an argument will will run bar after foo and still return foos result. It will work on functions with any number of arguments.
def run_before(lastfunc, *args1, **kwargs1):
def run(func):
def wrapped_func(*args, **kwargs):
try:
result = func(*args, **kwargs)
except:
result = None
finally:
lastfunc(*args1, **kwargs1)
return result
return wrapped_func
return run
def bar():
print 'goodby'
#run_before(bar)
def foo():
print "hello"
foo()
Edit: Added error handling. Thanks #Björn
Why not:
foo()
bar()
?
In case you want to have some general way to do it, you can try:
def run_after(f_after):
def wrapper(f):
def wrapped(*args, **kwargs):
ret = f(*args, **kwargs)
f_after()
return ret
return wrapped
return wrapper
#run_after(bar)
def foo():
....
This way bar is always run after foo is executed.

Categories

Resources