A function decorates a class - python

I happened to read the following code yesterday (I cannot guarantee this is a valid code):
def singleton(cls, *args, **kw):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance
#singleton
class MyClass:
...
Looks like a function singleton is designed to decorate a class MyClass. I understand the simple and standard decorator which, as a function, decorates a function. Like this:
def bold(func):
def wrapper():
return '<b>'+func()+'</b>'
return wrapper
#bold
def test():
return 'This is a test'
But I can't really get how the function-decorates-class thing works. Can anyone provide a more detailed example?

Related

How to write a decorator class in Python? [duplicate]

This is Python 2.5, and it's GAE too, not that it matters.
I have the following code. I'm decorating the foo() method in bar, using the dec_check class as a decorator.
class dec_check(object):
def __init__(self, f):
self.func = f
def __call__(self):
print 'In dec_check.__init__()'
self.func()
class bar(object):
#dec_check
def foo(self):
print 'In bar.foo()'
b = bar()
b.foo()
When executing this I was hoping to see:
In dec_check.__init__()
In bar.foo()
But I'm getting TypeError: foo() takes exactly 1 argument (0 given) as .foo(), being an object method, takes self as an argument. I'm guessing problem is that the instance of bar doesn't actually exist when I'm executing the decorator code.
So how do I pass an instance of bar to the decorator class?
You need to make the decorator into a descriptor -- either by ensuring its (meta)class has a __get__ method, or, way simpler, by using a decorator function instead of a decorator class (since functions are already descriptors). E.g.:
def dec_check(f):
def deco(self):
print 'In deco'
f(self)
return deco
class bar(object):
#dec_check
def foo(self):
print 'in bar.foo'
b = bar()
b.foo()
this prints
In deco
in bar.foo
as desired.
Alex's answer suffices when a function is sufficient. However, when you need a class you can make it work by adding the following method to the decorator class.
def __get__(self, obj, objtype):
"""Support instance methods."""
import functools
return functools.partial(self.__call__, obj)
To understand this you need to understand the descriptor protocol. The descriptor protocol is the mechanism for binding a thing to an instance. It consists of __get__, __set__ and __delete__, which are called when the thing is got, set or deleted from the instances dictionary.
In this case when the thing is got from the instance we are binding the first argument of its __call__ method to the instance, using partial. This is done automatically for member functions when the class is constructed, but for a synthetic member function like this we need to do it explicitly.
If you want to write the decorator as a class you can do:
from functools import update_wrapper, partial
class MyDecorator(object):
def __init__(self, func):
update_wrapper(self, func)
self.func = func
def __get__(self, obj, objtype):
"""Support instance methods."""
return partial(self.__call__, obj)
def __call__(self, obj, *args, **kwargs):
print('Logic here')
return self.func(obj, *args, **kwargs)
my_decorator = MyDecorator
class MyClass(object):
#my_decorator
def my_method(self):
pass

Using decorator from base class both in base class and derived class

I have some python objects with some methods in which i would like to do some check at the beggining, depending of this check, the method's code would run, or an execption would be raised. Instead of replicating the "check" code at the beginning of every method I though of doing a decorator, I also want the decorator to be embedded inside the class itself, since it is closely related to it. So basically:
instead of this
class A(object):
def a_method(self):
if self.check_var is True:
(some_code)
else:
raise Exception
I would like to have this
class A(object):
def decorator(function):
def function_wrapper(self, *args, **kwargs):
if self.check_var is True:
return function(self, *args, **kwargs)
else:
raise Exception
return function_wrapper
#decorator
def a_method(self):
(some_code)
My first question is, am I going about this right? or is there a better way. I have many methods of the A class that need to have this check, so that is why I don't want to replicate the code unnecessarily.
My second question is, if I go about this the way I described, I run into a problem when I want to derive a class from class A and performe the same decorator checks. Again I don't want to replicate the code, so I want to reuse the decorator in the base class A to performe checks in the derived class. I read about turning the decorator into a #classmethod however when I do this I am able to use the decorator in the derived class but not in the base class anymore!
So basically I would like something like this:
class A(object):
#classmethod #maybe
def decorator(function):
def function_wrapper(self, *args, **kwargs):
if self.check_var is True:
return function(self, *args, **kwargs)
else:
raise Exception
return function_wrapper
#decorator
def a_method(self):
(some_code)
class B(A):
#decorator
def b_method(self):
(some_code)
Does anybody know of any clean way to do this?
Since you would prefer to put the decorator inside the class (rather than outside both of them as I suggested in a comment), below shows a way to do it. It makes the decorator a staticmethod instead of a classmethod, and requires using it in a slightly unusual manner, but only within the class.
For more information regarding the necessity of using the decorator like this, see my question Calling class staticmethod within the class body?
class A(object):
#staticmethod
def decorator(function):
def function_wrapper(*args, **kwargs):
print('in function_wrapper')
return function(*args, **kwargs)
return function_wrapper
#decorator.__func__ #### Note unusual decorator usage inside defining class
def a_method(self):
print('in a_method')
class B(A):
#A.decorator #### Normal decorator usage outside defining class
def b_method(self):
print('in b_method')
One way to avoid having to use __func__ and still keep the definition in the first class would be to postpone turning it into a staticmethod until the very end of the class definition:
class A(object):
def decorator(function):
def function_wrapper(*args, **kwargs):
print('in function_wrapper')
return function(*args, **kwargs)
return function_wrapper
#decorator
def a_method(self):
print('in a_method')
decorator = staticmethod(decorator) #### convert for use outside this class
class B(A):
#A.decorator
def b_method(self):
print('in b_method')
Yet another way to avoid the __func__ is something like this:
class A(object):
class Check:
#staticmethod
def decorator(function):
def function_wrapper(*args, **kwargs):
print('in function_wrapper')
return function(*args, **kwargs)
return function_wrapper
#Check.decorator
def a_method(self):
print('in a_method')
class B(A):
Check = A.Check
#Check.decorator
def b_method(self):
print('in b_method')
Which has the additional advantage of making usage of the decorator very uniform.
My first question is, am I going about this right?
As martineau said below, the good practice is put classic decorator outside class.
def get_decorator(function, argument):
def function_wrapper(*args, **kwargs):
if argument is True:
return function(*args, **kwargs)
else:
raise Exception
return function_wrapper
class A(object):
def __init__(self):
self.check_var = True
self.a_method = get_decorator(self.a_method, self.check_var)
def a_method(self):
(whatever)
class B(A):
def __init__(self):
super(B, self).__init__()
self.b_method = get_decorator(self.b_method, self.check_var)
def b_method(self):
(whatever)
Classic decorator is called during class creation time, which is long before an instance is created. Reference

Why does a decorated class looses its docstrings?

I'm currently implementing an API on which I need to decorate the class Wrapper, but I want it to keep its docstring to make it available to the API user. Take a look at the following minimal working example :
class ClassDecorator:
"""ClassDecorator docstring
"""
def __init__(self, enableCache=True):
self.enableCache = enableCache
def __call__(self, wrapper):
def numericalmathfunction(*args, **kwargs):
func = wrapper(*args, **kwargs)
return func
return numericalmathfunction
#ClassDecorator(enableCache=True)
class Wrapper(object):
"""Wrapper docstring
Instructions on how to use the Wrapper
"""
def __init__(self, p):
self.p = p
model = Wrapper(4)
print model.__doc__
print Wrapper.__doc__
This returns
Wrapper docstring
None
Instances of Wrapper do keep the docstring, which is fine, but Wrapper itself does not. If a user wants to learn how to use Wrapper using help(Wrapper), he won't get what he wants.
I know I could just copy paste the dosctring into numericalmathfunction, but the decorator will be used on several classes with different docstrings.
Any ideas on how to make numericalmathfunction systematically inherit the docstrings of the wrapped class ?
Use functools.wraps() to update the attributes of the decorator:
from functools import wraps
class ClassDecorator:
"""ClassDecorator docstring
"""
def __init__(self, enableCache=True):
self.enableCache = enableCache
def __call__(self, wrapper):
#wraps(wrapper) # <-----------
def numericalmathfunction(*args, **kwargs):
func = wrapper(*args, **kwargs)
return func
return numericalmathfunction
#ClassDecorator(enableCache=True)
class Wrapper(object):
"""Wrapper docstring
Instructions on how to use the Wrapper
"""
def __init__(self, p):
self.p = p
See more standard library documentation for functools.wrap.

Pass parameters to a decorator for a class method is to be decorated

I am trying to define a decorator in flask which will finally be decorating class methods passing parameters of that class instance. Here is an example what I really want to do.
from functools import wraps
def user_permission(myname):
def decorator(f):
#wraps(f)
def decorated(*args,**argws):
if myname == 'My Name':
return f(*args,**argws)
else:
return "Not Permitted"
return decorated
return decorator
And my manager class is defined as:
class Manager(flask.views.MethodView):
def __init__(self,name):
self.name = name
#user_permission(self.my_name)
def post(self):
return "Response"
def get(self):
return "Response"
What I am trying to do is pass the class variables to the decorator. Yes "self" is not defined at that point but "#decorator.user_permission(self.my_name)" is what I am trying actually because I am yet not solved with my problem.
I couldn't find solution from HERE.
Does anybody knows about these stuffs please?
As you say, self is not defined at that point. This could never work, as a decorator is executed when the class is defined, whereas you want something to run when the instance method is called.
However I think you're really overcomplicating this. self is passed to the method itself. So there's no reason to try and make it a parameter to the decorator, since the decorator has access to the method arguments. This would be much simpler:
from functools import wraps
def user_permission():
#wraps(f)
def decorated(self, *args, **kwargs):
if self.myname == 'My Name':
return f(self, *args, **kwargs)
else:
return "Not Permitted"
return decorated
self is just an argument. You don't need a decorator factory.
def user_permission(f):
#wraps(f)
def decorated(self, *args, **kw):
if self.myname == 'My Name':
return f(self, *args, **kw)
else:
return "Not Permitted"
return decorated

Access self from decorator

In setUp() method of unittest I've setup some self variables, which are later referenced in actual tests. I've also created a decorator to do some logging. Is there a way in which I can access those self variables from decorator?
For the sake of simplicity, I'm posting this code:
def decorator(func):
def _decorator(*args, **kwargs):
# access a from TestSample
func(*args, **kwargs)
return _decorator
class TestSample(unittest.TestCase):
def setUp(self):
self.a = 10
def tearDown(self):
# tear down code
#decorator
def test_a(self):
# testing code goes here
What would be the best way of accessing a (set in setUp()) from decorator?
Since you're decorating a method, and self is a method argument, your decorator has access to self at runtime. Obviously not at parsetime, because there are no objects yet, just a class.
So you change your decorator to:
def decorator(func):
def _decorator(self, *args, **kwargs):
# access a from TestSample
print 'self is %s' % self
return func(self, *args, **kwargs)
return _decorator

Categories