I'm at an intermediate level with Python, and I've recently been playing around with Python context managers. I wanted to invert the order in which the enter and exit are run. So I wrote this context manager:
class ReversibleContextManager(object):
def __enter__(self, *args):
print('d')
return self
def __exit__(self, *args):
print('g')
return self
def __invert__(self):
self.__enter__, self.__exit__ = self.__exit__, self.__enter__
return self
It works fine forwards:
with ContextManager():
print('o')
d
o
g
But in reverse, we still get:
with ~ContextManager():
print('a')
d
o
g
If we call the enter and exit functions explicitly, as expected, we get:
with ReversibleContextManager() as c:
c.__enter__()
print('o')
c.__exit__()
d
d
o
g
g
BUT the order IS reversed for the instance's method!
with ~ReversibleContextManager() as c:
c.__enter__()
print('o')
c.__exit__()
d
g
o
d
g
So it looks like the with statement calls using the method bound to the Class rather than the instance (is this the right terminology?). Is this expected?
i.e.
what is called is:
c = ReversibleContextManager()
c.__invert__()
ReversibleContextManager.__enter__(c)
...in context...
ReversibleContextManager.__exit__(c)
Rather than what I expect:
c = ReversibleContextManager()
c.__invert__()
c.__enter__()
...in context...
c.__exit__()
So it looks like the with statement calls using the method bound to the Class rather than the instance (is this the right terminology?). Is this expected?
Absolutely. That's how Python generally looks up special methods. This is mostly so in cases like if you have a class Foo that implements __str__, print Foo calls type(Foo).__str__ instead of Foo.__str__.
As a workaround, you could create your reversed class inside the __invert__ function and return an instance of the new class.
class ReversibleContextManager(object):
def __enter__(self, *args):
print('enter')
return self
def __exit__(self, *args):
print('exit')
return self
def __invert__(self):
new = type("ReversibleContextManager",
(object,),
{'__enter__': self.__exit__,
'__exit__': self.__enter__})
return new()
>>> with ReversibleContextManager() as f:
... print("normal")
enter
normal
exit
>>> with ~ReversibleContextManager() as f:
... print("reversed")
exit
reversed
enter
A more verbose but pretty explicit way is to use two helper functions and just switch which one comes at enter and exit by a flag reverse:
class ReversibleContextManager(object):
def __init__(self, reverse=False):
self.reverse = reverse
def _enter(self, *args):
print('d')
return self
def _exit(self, *args):
print('g')
return self
def __enter__(self, *args):
if self.reverse:
return self._exit(*args)
return self._enter(*args)
def __exit__(self, *args):
if self.reverse:
return self._enter(*args)
return self._exit(*args)
def __invert__(self):
self.reverse = True
return self
>>> with ReversibleContextManager() as r:
print('o')
d
o
g
>>> with ~ReversibleContextManager() as r:
print('o')
g
o
d
>>> with ReversibleContextManager(reverse=True) as r:
print('o')
g
o
d
Another way:
class ReversibleContextManager(object):
inverted = False
def __init__(self):
if self.__class__.inverted:
self.__invert__()
self.__class__.inverted = False
def __enter__(self, *args):
print('d')
return self
def __exit__(self, *args):
print('g')
return self
def __invert__(self):
self.__class__.inverted = True
self.__class__.__enter__, self.__class__.__exit__ = self.__exit__, self.__enter__
return self
Related
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
Currently I use the following technique:
def Myfb(param1, param2, firstTime):
if firstTime:
global a = compute()
global b = compute2()
global a
global b
c = doNormalExecution(param1, param2, a, b)
Is there a more elegant way? I don't like creating globals
The technique is called memoization. The functools module has an lru_cache function that does what you want.
from functools import lru_cache
#lru_cache(maxsize=None)
def Myfb(param1, param2):
b = doNormalExecution(a)
The python docs have more information like what maxsize is and how lru_cache works so that you can implement it suitably.
You can use a generator:
def Myfb():
a = compute()
while True:
param1, param2 = yield
b = doNormalExecution(a, param1, param2)
yield b
Here you have a live example
Example code:
def compute():
return 10
def doNormalExecution(a, b, c):
return a + b + c
def Myfb():
a = compute()
while True:
param1, param2 = yield
b = doNormalExecution(a, param1, param2)
yield b
f = Myfb()
next(f)
for a, b in zip(range(10), range(10)):
print(f.send((a, b)))
next(f)
You can create a custom callable that will maintain it's own state:
class MyFB(object):
_sentinel = object()
def __init__(self):
self._a = self._sentinel
self._b = self._sentinel
def __call__(self, param1, param2, reinit=False):
if reinit or self._a is self._sentinel or self._b is self._sentinel:
self._a = compute_a()
self._b = compute_b()
return doNormalExecution(param1, param2, self._a, self._b)
myfb = MyFB()
# now use `myfb` like an ordinary function
Seeing as compute1() and compute2() don't take arguments, you could use functools to cache their results. (Unless they have side effects.)
from functools import cache
#cache
def compute():
#do complicated stuff first time called
return result
#cache
def compute2():
#do complicated stuff first time called
return result
def Myfb(param1, param2):
a = compute()
b = compute2()
c = doNormalExecution(param1, param2, a, b)
If you don't pass any parameters to a function, use this decorator (I had it lying around):
import functools
def lazy(func):
""" Decorator which only actually runs a function the first time it is
called and stores the result to be returned on later calls.
Usage:
#lazy
def func_to_be_only_run_once():
...
"""
FLAG = object()
result = FLAG
#functools.wraps(func)
def inner():
nonlocal result
if result is FLAG:
result = func()
return result
return inner
If you have one or more arguments that change (including self) use functools.lru_cache
Here's a cool way to do it using closures.
def closure(firstTime=True):
def Myfb():
nonlocal firstTime
if firstTime:
print("First time.")
firstTime = False
return Myfb
myfb = closure()
myfb()
myfb()
I have the following callable:
class SomeClass(object):
def __init__(self, expr, return_status):
self._expr = expr
self._status = return_status
def __call__(self):
if self._expr == self._status:
return True
def __str__(self):
return ("Function: %s\n Return Status: %s\n" %
(self.__class__.__name__, self._status))
The problem I am facing is this that whenever I try to pass an expression like:
some_variable = SomeFunction(SomeClass.some_method,return_status=True)
SomeClass.some_method gets evaluated and gets stored in self._expr as a boolean value.
What I actually want is this expression (SomeClass.some_method) be stored in self._expr and get evaluated each time the __call__(self) method is called.
Am I making sense?
Let's say I am taking the following example:
def addition(c,b):
print "'addition' function called!\n"
sum = c+b
if sum>5:
return True
else:
return False
script_timeout = 3
some_variable = SomeFunction(addition(1,2),return_status=True)
print "some_variable: \n%s" %some_variable
some_class.some_method(some_variable, script_timeout, 1)
This gives me the following output:
'addition' function called!
SomeFunction (_init_) function called!
expr: False
self._expr = False and self._status = True
SomeFunction (_str_) function called!
self.__class__.__name__ = SomeFunction and self._expr = False
monitor:
Function: SomeFunction
Return Status of the Expression: True
SomeFunction (_call_) function called!
self._expr = False and self._status = True
SomeFunction (_call_) function called!
self._expr = False and self._status = True
SomeFunction (_call_) function called!
self._expr = False and self._status = True
So, the concern is the addition function is not getting called with each iteration calling of SomeFunction (by the some_method method.)
The required functionality is this that SomeFunction (when called by some_method) should call the function addition.
Assuming expr will be a method/function and assuming you know what method/function returns, you have 3 options. Follow just one of these 3 options and you'll achieve what you want.
1) You can call expr in the assignement to self.expr:
....
class CheckStatus:
def __init__(self, expr, ...)
self.expr = expr() # expr() being called here, store whatever the result is to self.expr
def __call__(self):
# self.expr already holds a boolean value, or anything your expr returns
if self.expr == self.status:
# self.expr match ...
# do what else you have to do
obj = CheckStatus(SomeClass().method, ...) # pay attention how we pass the method here
2) If self.expr is a reference to that expr, then:
class CheckStatus:
def __init__(self, expr, ...):
self.expr = expr
def __call__(self):
# in this example, self.expr now it's a reference to some method
# thus you need to call self.expr here
if self.expr() == self.status:
....
obj = CheckStatus(SomeClass().method, ...) # pay attention how we pass method for this example
3) call the SomeClass().method() at instantiation of CheckStatus():
class CheckStatus:
def __init__(self, expr, ...):
self.expr = expr # for this example, expr already is a boolean or anything else some method/function returned
def __call__(self):
# don't need to call anything here
if self.expr == self.status:
....
obj = CheckStatus(SomeClass().method(), ...) # because here we called SomeClass().method()
You have to call the method/function your passing in to your CheckStatus class somewhere, otherwise you'll never have that method/function result to check.
Hope it was clear.
class S(object):
def __init__(self, expr, return_status):
self._expr = expr
self._status = return_status
def __call__(self):
if self._expr() == self._status:
raise Exception
self._expr()
def __str__(self):
return ("Function: %s\n Return Status of the Expression: %s\n" %
(self.__class__.__name__, self._status))
def some_method():return True
try:
S(some_method,return_status=True)()
except Exception as e:
print('Got Exception')
Given a class and a set of its methods - how can you determine from within that class which methods have been decorated with a certain decorator?
My goal is to basically get the actual values of the methods that are decorated, so something like:
class A():
def get_values(self):
...
# returned {'a-special-name': 1, 'b': 2}
#my_dec('a-special-name') # Ideally be able to also put optional name
def a(self):
return 1
#my_dec
def b(self):
return 2
Any idea on how to accomplish this?
Edit: this should also work on parent classes, that is, if A is a subclass of:
class B():
#my_dec
def c(self):
return 3
then get_values() of A instance should return {'a-special-name': 1, 'b': 2, 'c': 3} (order is irrelevant of course)
Edit: class based decorator that works but not with inheritance. Any idea how to make it work with inheritance but without having to decorate the class itself?
class my_dec(object):
def __init__(self, func, name=None):
self.func = func
self.name = name or func.__name__
self.func._some_flag = True
def __get__(self, instance, cls=None):
if instance is None:
return self
return self.func(instance)
If you can define the decorator yourself, then simply have it "mark" the method object in some way:
def my_dec(method):
method._this_be_decorated = True
return method
The class can then look for those marked methods; something like:
from inspect import isfunction
class A:
def get_values(self):
return filter(lambda i: isfunction(i) and hasattr(i, '_this_be_decorated'),
vars(type(self)).values())
This will return an iterable of function objects which you can process further as needed.
def my_dec(name):
if callable(name):
# name is callable – take its name
func = name # no make the code more readable
func.special_name = func.__name__
return func
else:
# name is the name to give – add an inner layer of functions
def inner(function_object):
function_object.special_name = name
return function_object
return inner
class A():
def get_values(self):
# return a dict of special name to call result mapping for every class member that has a special_name.
return {func.special_name: func(self) for func in self.__class__.__dict__.values() if hasattr(func, 'special_name')}
# returned {'a-special-name': 1, 'b': 2}
#my_dec('a-special-name') # Ideally be able to also put optional name
def a(self):
return 1
#my_dec
def b(self):
return 2
def no_dec(self):
return 42
should do what you want.
As deceze mentions, decorators can do whatever they want so there's no reliable generic answer. If you "own" the decorator you can add special properties to it's return value ie (Q&D py2.7 example):
def mydec(name=''):
# py27 hack - for py3 you want nonlocal instead
n = [name]
def innerdec(func):
# py27 hack - for py3 you want nonlocal instead
name = n[0] or func.__name__
def wrapper(*args, **kw):
print("in mydec.wrapper for {}".format(name))
return func(*args, **kw)
wrapper.ismydec = True # so we know this is decorated by mydec
wrapper.func = func # so we can get the original func
wrapper.name = name
return wrapper
return innerdec
def collect_dec(cls):
decorated = {}
for attname in dir(cls):
obj = getattr(cls, attname)
if getattr(obj, "ismydec", False):
decorated[obj.name] = obj.func
cls._decorated_funcs = decorated
return cls
#collect_dec
class A():
def get_values(self):
return {
name:func(self) for name, func in self._decorated_funcs.items()
}
#mydec('a-special-name') # Ideally be able to also put optional name
def a(self):
return 1
#mydec() # no name
def b(self):
return 2
a = A()
print(a.get_values())
Which outputs:
{'a-special-name': 1, 'b': 2}
I want to write class decorator which for all non-magic methods, to decorate these methods. The idea is that to all methods of class print its name after call; I do not want decor all methods but only class. Decorator log_method works. I have problem with log_class decorator. There are no errors and no output.
import traceback
import inspect
def log_method(func):
def inner(*args, **kwargs):
print("{}{}".format(int(len(traceback.extract_stack()) / 2) * " ", func.__name__))
return func(*args, **kwargs)
return inner
def log_class(cls):
for m in dir(cls):
if not m.startswith("__") and inspect.isfunction(getattr(cls, m)):
m = log_method(m)
print(m)
return cls
#log_class
class Cls:
def __init__(self):
pass
def A(self):
self.B()
def B(self):
self.C()
def C(self):
pass
Cls().A()
"""
Excepted output:
A
B
C
"""
You should rebind the method to the class object using setattr passing the method name m; assigning to the local name m like you've done, does nothing.
More so, you're currently passing m, a string, to log_method. Instead, you should pass the function object itself after retrieving via getattr:
def log_method(func):
def inner(*args, **kwargs):
print("{}{}".format(int(len(traceback.extract_stack()) / 2) * " ", func.__name__))
return func(*args, **kwargs)
return inner
def log_class(cls):
for m in dir(cls):
if not m.startswith("__") and inspect.isfunction(getattr(cls, m)):
setattr(cls, m, log_method(getattr(cls, m))) # here
return cls
Cls.A()
# A
# B
# C
PS: log_method is never used for decorating, so it's not a decorator.