So I have the following decorator code
class Factory:
def __init__(self, cls):
self.cls = cls
def __instancecheck__(self, inst):
return isinstance(inst, self.cls)
def Produce(self):
return self.cls()
And the following class code
#Factory
class Foo:
def __init__(self, arg):
self.arg = arg
def method(self): pass
Which works great. Allows me to do stuff like
Foo.Produce().method()
Instead of
instance = Foo()
instance.method()
But now I cant use the class constructor normally
Foo(arg)
Gives the exception 'Factory object is not callable'. My question is the following: How can I make a decorator that allows me to instantiate the decorated class using its constructor, but also allows me to use a function in the decorator?
Alternative ways I'd rather not use:
Skip the constructor. Always use <Class>.Produce() (and use *args/**kwargs to make it abstract/reusable.
Use setters in all the classes, and make them return self so they can be chained.
Make a class containing the produce method and extend this class.
The exception is telling you all you need to know, just add a __call__ method:
class Factory:
# ...
def __call__(self, *args, **kwargs):
return self.cls(*args, **kwargs)
If all you want to do is to add a Produce function to the class, you can rewrite your decorator like this:
def Factory(cls):
def Produce():
return cls()
cls.Produce= Produce # add the function to the class
return cls
Related
I have created a class and declared some variables inside it's constructor.
This class also has some methods.
I have also created a decorator which takes a parameter.
What I want is to use that decorator before those methods and pass one of the variable from the class constructor.
Below is my code:
Decorator:
def thread_switch_decorator(argument):
def decorator(function):
def wrapper(*args, **kwargs):
argument.stop()
result = function(*args, **kwargs)
argument.start()
return result
return wrapper
return decorator
Class and Methods:
class MainWindow(QMainWindow):
def __init__(self):
self.my_thread = initiate_connect()
#thread_switch_decorator(argument=self.my_thread) # <--- Here is the problem
def home_page(self):
pass
Error:
#thread_switch_decorator(argument=self.my_thread)
NameError: name 'self' is not defined
On the code above where I am using the decorator I can not pass the parameter from the constructor. Which is logical.
My question is, how can I do this?
This question already has answers here:
Applying a decorator to every method in a class?
(4 answers)
Closed 3 years ago.
I'd like to wrap every method of a particular class in python, and I'd like to do so by editing the code of the class minimally. How should I go about this?
An elegant way to do it is described in Michael Foord's Voidspace blog in an entry about what metaclasses are and how to use them in the section titled A Method Decorating Metaclass. Simplifying it slightly and applying it to your situation resulted in this:
from functools import wraps
from types import FunctionType
def wrapper(method):
#wraps(method)
def wrapped(*args, **kwargs):
# ... <do something to/with "method" or the result of calling it>
return wrapped
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if isinstance(attribute, FunctionType):
# replace it with a wrapped version
attribute = wrapper(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
class MyClass(object):
__metaclass__ = MetaClass # wrap all the methods
def method1(self, ...):
# ...etc ...
In Python, function/method decorators are just function wrappers plus some syntactic sugar to make using them easy (and prettier).
Python 3 Compatibility Update
The previous code uses Python 2.x metaclass syntax which would need to be translated in order to be used in Python 3.x, however it would then no longer work in the previous version. This means it would need to use:
class MyClass(metaclass=MetaClass) # apply method-wrapping metaclass
...
instead of:
class MyClass(object):
__metaclass__ = MetaClass # wrap all the methods
...
If desired, it's possible to write code which is compatible with both Python 2.x and 3.x, but doing so requires using a slightly more complicated technique which dynamically creates a new base class that inherits the desired metaclass, thereby avoiding errors due to the syntax differences between the two versions of Python. This is basically what Benjamin Peterson's six module's with_metaclass() function does.
from types import FunctionType
from functools import wraps
def wrapper(method):
#wraps(method)
def wrapped(*args, **kwargs):
print('{!r} executing'.format(method.__name__))
return method(*args, **kwargs)
return wrapped
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if isinstance(attribute, FunctionType):
# replace it with a wrapped version
attribute = wrapper(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
def with_metaclass(meta):
""" Create an empty class with the supplied bases and metaclass. """
return type.__new__(meta, "TempBaseClass", (object,), {})
if __name__ == '__main__':
# Inherit metaclass from a dynamically-created base class.
class MyClass(with_metaclass(MetaClass)):
#staticmethod
def a_static_method():
pass
#classmethod
def a_class_method(cls):
pass
def a_method(self):
pass
instance = MyClass()
instance.a_static_method() # Not decorated.
instance.a_class_method() # Not decorated.
instance.a_method() # -> 'a_method' executing
You mean programatically set a wrapper to methods of a class?? Well, this is probably a really bad practice, but here's how you may do it:
def wrap_methods( cls, wrapper ):
for key, value in cls.__dict__.items( ):
if hasattr( value, '__call__' ):
setattr( cls, key, wrapper( value ) )
If you have class, for example
class Test( ):
def fire( self ):
return True
def fire2( self ):
return True
and a wrapper
def wrapper( fn ):
def result( *args, **kwargs ):
print 'TEST'
return fn( *args, **kwargs )
return result
then calling
wrap_methods( Test, wrapper )
will apply wrapper to all methods defined in class Test. Use with caution! Actually, don't use it at all!
If extensively modifying default class behavior is the requirement, MetaClasses are the way to go. Here's an alternative approach.
If your use case is limited to just wrapping instance methods of a class, you could try overriding the __getattribute__ magic method.
from functools import wraps
def wrapper(func):
#wraps(func)
def wrapped(*args, **kwargs):
print "Inside Wrapper. calling method %s now..."%(func.__name__)
return func(*args, **kwargs)
return wrapped
Make sure to use functools.wraps while creating wrappers, even more so if the wrapper is meant for debugging since it provides sensible TraceBacks.
import types
class MyClass(object): # works only for new-style classes
def method1(self):
return "Inside method1"
def __getattribute__(self, name):
attr = super(MyClass, self).__getattribute__(name)
if type(attr) == types.MethodType:
attr = wrapper(attr)
return attr
I have written a python Flask application, which has a class and methods as below.
class PythonSample:
def method1():
pass # does something
def method2():
pass # does something
Now I have written another class which has decorator functions as below.
class PythonAuth:
def oauthAuth():
pass
Now I'm wiring oauthAuth decorator for all the methods of PythonSample class as below
import oauthAuth from PythonAuth
class PythonSample
#oauthAuth
def method1():
pass # does something
#oauthAuth
def method2():
pass # does something
Applying decorator at each method works fine.
Question: Instead of applying oauthAuth decorator to each of the methods. Is there a way to configure in python, as apply oauthAuth decorator to all the methods in a class and exclude certain methods.
Something like include auth for certain URLs and exclude authentication for certain urls
Please ignore the syntax of the python code here.
You can use a class decorator plus some magic.
Decorating Functions
Assume you have a decorator that just logs a string before calling the function.
def log(func):
def logged_func(*args, **kwargs):
print('logged')
func(*args, **kwargs)
return logged_func
Decorating classes
You can use the same trick, but with a class. log_all is a class decorator, cls is a class type. We use vars to walk the class dictionary, and look for methods by using callable(v). Decorate the method with log(v) and use setattr to change the cls definition to the new decorated method. Just like function decorators, return the class in the end.
def log_all(cls):
for k, v in vars(cls).items():
if callable(v):
setattr(cls, k, log(v))
return cls
I am ignoring k essentially, but k is the method name, you could leverage it to achieve your usage scenario.
Full code
Here is a full example, that should make some sense now.
def log(func):
def logged_func(*args, **kwargs):
print('logged')
func(*args, **kwargs)
return logged_func
def log_all(cls):
for k, v in vars(cls).items():
if callable(v):
setattr(cls, k, log(v))
return cls
#log_all
class A:
def method(self):
pass
Every method in class A should be decorated with the log decorator.
>>> a = A()
>>> a.method()
logged
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
This question already has answers here:
Applying a decorator to every method in a class?
(4 answers)
Closed 3 years ago.
I'd like to wrap every method of a particular class in python, and I'd like to do so by editing the code of the class minimally. How should I go about this?
An elegant way to do it is described in Michael Foord's Voidspace blog in an entry about what metaclasses are and how to use them in the section titled A Method Decorating Metaclass. Simplifying it slightly and applying it to your situation resulted in this:
from functools import wraps
from types import FunctionType
def wrapper(method):
#wraps(method)
def wrapped(*args, **kwargs):
# ... <do something to/with "method" or the result of calling it>
return wrapped
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if isinstance(attribute, FunctionType):
# replace it with a wrapped version
attribute = wrapper(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
class MyClass(object):
__metaclass__ = MetaClass # wrap all the methods
def method1(self, ...):
# ...etc ...
In Python, function/method decorators are just function wrappers plus some syntactic sugar to make using them easy (and prettier).
Python 3 Compatibility Update
The previous code uses Python 2.x metaclass syntax which would need to be translated in order to be used in Python 3.x, however it would then no longer work in the previous version. This means it would need to use:
class MyClass(metaclass=MetaClass) # apply method-wrapping metaclass
...
instead of:
class MyClass(object):
__metaclass__ = MetaClass # wrap all the methods
...
If desired, it's possible to write code which is compatible with both Python 2.x and 3.x, but doing so requires using a slightly more complicated technique which dynamically creates a new base class that inherits the desired metaclass, thereby avoiding errors due to the syntax differences between the two versions of Python. This is basically what Benjamin Peterson's six module's with_metaclass() function does.
from types import FunctionType
from functools import wraps
def wrapper(method):
#wraps(method)
def wrapped(*args, **kwargs):
print('{!r} executing'.format(method.__name__))
return method(*args, **kwargs)
return wrapped
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if isinstance(attribute, FunctionType):
# replace it with a wrapped version
attribute = wrapper(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
def with_metaclass(meta):
""" Create an empty class with the supplied bases and metaclass. """
return type.__new__(meta, "TempBaseClass", (object,), {})
if __name__ == '__main__':
# Inherit metaclass from a dynamically-created base class.
class MyClass(with_metaclass(MetaClass)):
#staticmethod
def a_static_method():
pass
#classmethod
def a_class_method(cls):
pass
def a_method(self):
pass
instance = MyClass()
instance.a_static_method() # Not decorated.
instance.a_class_method() # Not decorated.
instance.a_method() # -> 'a_method' executing
You mean programatically set a wrapper to methods of a class?? Well, this is probably a really bad practice, but here's how you may do it:
def wrap_methods( cls, wrapper ):
for key, value in cls.__dict__.items( ):
if hasattr( value, '__call__' ):
setattr( cls, key, wrapper( value ) )
If you have class, for example
class Test( ):
def fire( self ):
return True
def fire2( self ):
return True
and a wrapper
def wrapper( fn ):
def result( *args, **kwargs ):
print 'TEST'
return fn( *args, **kwargs )
return result
then calling
wrap_methods( Test, wrapper )
will apply wrapper to all methods defined in class Test. Use with caution! Actually, don't use it at all!
If extensively modifying default class behavior is the requirement, MetaClasses are the way to go. Here's an alternative approach.
If your use case is limited to just wrapping instance methods of a class, you could try overriding the __getattribute__ magic method.
from functools import wraps
def wrapper(func):
#wraps(func)
def wrapped(*args, **kwargs):
print "Inside Wrapper. calling method %s now..."%(func.__name__)
return func(*args, **kwargs)
return wrapped
Make sure to use functools.wraps while creating wrappers, even more so if the wrapper is meant for debugging since it provides sensible TraceBacks.
import types
class MyClass(object): # works only for new-style classes
def method1(self):
return "Inside method1"
def __getattribute__(self, name):
attr = super(MyClass, self).__getattribute__(name)
if type(attr) == types.MethodType:
attr = wrapper(attr)
return attr