doc*_*ead 47 python oop class decorator class-method
我真的不需要这样做,但只是想知道,有没有办法将装饰器绑定到类中的所有函数,而不是明确地为每个函数声明它.
我认为它然后变成了一种方面,而不是装饰者,它确实感觉有点奇怪,但是想到时间或认证这样的东西它会非常整洁.
Dun*_*can 31
最简单的方法是对类定义进行其他修改,即定义元类.
或者,只需在类定义的末尾应用装饰器:
class Something:
def foo(self): pass
for name, fn in inspect.getmembers(Something):
if isinstance(fn, types.UnboundMethodType):
setattr(Something, name, decorator(fn))
Run Code Online (Sandbox Code Playgroud)
对于Python 3,将types.UnboundMethodType替换为types.FunctionType.
在实践中,您当然希望更有选择地应用您的装饰器,并且只要您想要装饰除一种方法之外的所有方法,您将发现以传统方式使用装饰器语法更容易和更灵活.
Anu*_*yal 29
每次想到更改类定义时,都可以使用类装饰器或元类.例如,使用元类
import types
class DecoMeta(type):
def __new__(cls, name, bases, attrs):
for attr_name, attr_value in attrs.iteritems():
if isinstance(attr_value, types.FunctionType):
attrs[attr_name] = cls.deco(attr_value)
return super(DecoMeta, cls).__new__(cls, name, bases, attrs)
@classmethod
def deco(cls, func):
def wrapper(*args, **kwargs):
print "before",func.func_name
result = func(*args, **kwargs)
print "after",func.func_name
return result
return wrapper
class MyKlass(object):
__metaclass__ = DecoMeta
def func1(self):
pass
MyKlass().func1()
Run Code Online (Sandbox Code Playgroud)
输出:
before func1
after func1
Run Code Online (Sandbox Code Playgroud)
注意:它不会修饰staticmethod和classmethod
Python 3 的更新:
class DecoMeta(type):
def __new__(cls, name, bases, attrs):
for attr_name, attr_value in attrs.items():
if isinstance(attr_value, types.FunctionType):
attrs[attr_name] = cls.deco(attr_value)
return super(DecoMeta, cls).__new__(cls, name, bases, attrs)
@classmethod
def deco(cls, func):
def wrapper(*args, **kwargs):
print("before",func.__name__)
result = func(*args, **kwargs)
print("after",func.__name__)
return result
return wrapper
Run Code Online (Sandbox Code Playgroud)
(并为此感谢邓肯)
以下代码适用于 python2.x 和 3.x
import inspect
def decorator_for_func(orig_func):
def decorator(*args, **kwargs):
print("Decorating wrapper called for method %s" % orig_func.__name__)
result = orig_func(*args, **kwargs)
return result
return decorator
def decorator_for_class(cls):
for name, method in inspect.getmembers(cls):
if (not inspect.ismethod(method) and not inspect.isfunction(method)) or inspect.isbuiltin(method):
continue
print("Decorating function %s" % name)
setattr(cls, name, decorator_for_func(method))
return cls
@decorator_for_class
class decorated_class:
def method1(self, arg, **kwargs):
print("Method 1 called with arg %s" % arg)
def method2(self, arg):
print("Method 2 called with arg %s" % arg)
d=decorated_class()
d.method1(1, a=10)
d.method2(2)
Run Code Online (Sandbox Code Playgroud)