将装饰器附加到类中的所有函数
有没有一种方法可以将装饰器一般地绑定到类中的所有函数,而不是为每个函数显式声明它?
我想它会成为一种方面,而不是装饰器,它确实感觉有点奇怪,但考虑到诸如计时或身份验证之类的东西,它会非常整洁。
Is there a way to bind a decorator to all functions within a class generically, rather than explicitly stating it for every function?
I suppose it then becomes a kind of aspect, rather than a decorator and it does feel a bit odd, but was thinking for something like timing or auth it'd be pretty neat.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
执行此操作或对类定义进行其他修改的最简洁方法是定义元类。
或者,只需使用
inspect
:在实践中,您当然会希望更有选择性地应用装饰器。一旦您想要装饰除一个方法之外的所有方法,您就会发现以传统方式使用装饰器语法更容易、更灵活。
The cleanest way to do this, or to do other modifications to a class definition, is to define a metaclass.
Alternatively, just apply your decorator at the end of the class definition using
inspect
:In practice of course you'll want to apply your decorator more selectively. As soon as you want to decorate all but one method you'll discover that it is easier and more flexible just to use the decorator syntax in the traditional way.
每次您想要更改类定义时,都可以使用类装饰器或元类。例如使用元类:
输出:
注意:它不会装饰静态方法和类方法。
Every time you think of changing a class definition, you can either use the class decorator or metaclass. E.g. using metaclass:
Output:
Note: it will not decorate staticmethods and classmethods.
以下代码适用于 python2.x 和 3.x
Following code works for python2.x and 3.x
Python 3 更新:(
感谢 Duncan)
Update for Python 3:
(and thanks to Duncan for this)
当然,当你想要修改 python 创建对象的方式时,元类是最 Pythonic 的方法。这可以通过重写类的 __new__ 方法来完成。但围绕这个问题(特别是 python 3.X),我想提一下:
types.FunctionType
不能保护特殊方法不被修饰,因为它们是函数类型。作为更通用的方法,您可以装饰名称不以双下划线(__
)开头的对象。此方法的另一个好处是,它还涵盖了命名空间中存在且以 __ 开头但不像 __qualname__ 、__module__
那样具有功能的对象。等__new__
标头中的namespace
参数不包含__init__
中的类属性。原因是__new__
在__init__
(初始化)之前执行。没有必要使用
classmethod
作为装饰器,就像大多数时候您从另一个模块导入装饰器一样。__init__
之外),用于拒绝装饰并检查名称是否不以__
开头,您可以使用以下命令检查类型types.FunctionType
以确保您没有装饰非函数对象。以下是您可以使用的示例元计算:
演示:
输出:
要检查上述注释中的第三项,您可以取消注释行
a = 10
并执行print(myinstance.a)< /code> 并查看结果,然后按如下方式更改
__new__
中的字典理解,然后再次查看结果:Of course that the metaclasses are the most pythonic way to go when you want to modify the way that python creates the objects. Which can be done by overriding the
__new__
method of your class. But there are some points around this problem (specially for python 3.X) that I'd like to mention:types.FunctionType
doesn't protect the special methods from being decorated, as they are function types. As a more general way you can just decorate the objects which their names are not started with double underscore (__
). One other benefit of this method is that it also covers those objects that exist in namespace and starts with__
but are not function like__qualname__
,__module__
, etc.The
namespace
argument in__new__
's header doesn't contain class attributes within the__init__
. The reason is that the__new__
executes before the__init__
(initializing).It's not necessary to use a
classmethod
as the decorator, as in most of the times you import your decorator from another module.__init__
) for refusing of being decorated alongside checking if the name is not started with__
you can check the type withtypes.FunctionType
to be sure that you're not decorating a non-function object.Here is a sample metacalss that you can use:
Demo:
Output:
For checking the 3rd item from the aforementioned notes you can uncomment the line
a = 10
and doprint(myinstance.a)
and see the result then change the dictionary comprehension in__new__
as follows then see the result again:对于类似的问题,我将在这里重复我的答案< /a>
可以通过多种不同的方式来完成。我将展示如何通过元类、类装饰器和继承来实现它。
通过更改元类
此外,还将展示两种方法如何在不更改类的元信息的情况下实现它(通过类装饰器和类继承)。第一种方法是通过类装饰器
put_decorator_on_all_methods
接受装饰器来包装类的所有成员可调用对象。而且,最近,我遇到了同样的问题,但我无法将装饰器放在类上或以任何其他方式更改它,除非我被允许仅通过继承添加此类行为(如果您可以根据需要更改代码库,我不确定这是否是最佳选择)。
这里的 Logger 类强制子类的所有可调用成员写入有关其调用的信息,请参阅下面的代码。
或者更抽象地讲,您可以基于某些装饰器实例化基类。
I will repeat my answer here, for a similar issue
It can be done many different ways. I will show how to make it through meta-class, class decorator and inheritance.
by changing meta class
Also, will show two approaches how to make it without changing meta information of class (through class decorator and class inheritance). The first approach through class decorator
put_decorator_on_all_methods
accepts decorator to wrap all member callable objects of class.And, recently, I've come across on the same problem, but I couldn't put decorator on class or change it in any other way, except I was allowed to add such behavior through inheritance only (I am not sure that this is the best choice if you can change codebase as you wish though).
Here class
Logger
forces all callable members of subclasses to write information about their invocations, see code below.Or more abstractly, you can instantiate base class based on some decorator.
在某些情况下,您可能还想做另一件稍微相似的事情。有时您想要触发附件以进行诸如调试之类的操作,而不是在所有类上触发附件,但对于对象的每个方法,您可能需要记录其正在执行的操作。
该函数将遍历一些对象(当前仅是 self),并用调试装饰器替换所有不以 _ 开头的函数和方法。
上面没有提到用于迭代 dir(self) 的方法,但完全有效。并且可以从对象外部调用,而且更加任意。
There's another slightly similar thing you might want to do in some cases. Sometimes you want to trigger the attachment for something like debugging and not on all the classes but for every method of an object you might want a record of what it's doing.
This function will go through some objects (only self currently) and replace all functions and methods that do not start with _ with a debugging decorator.
The method used for this of just iterating the dir(self) is not addressed above but totally works. And can be called externally from the object and much more arbitrarily.
在 Python 3 中,您还可以编写一个简单的函数,将装饰器覆盖/应用到某些方法,如下所示:
In Python 3 you could also write a simple function that overwrites/applies a decorator to certain methods like so:
结合各种答案的信息,这里有一个 DecorateMethods 元类:
用作:
它与单元测试配合得很好,而不是基于函数的解决方案。
归功于 1, 2 以及这个问题的其他答案。
Combining information from various answers, here's a DecorateMethods metaclass:
Used as:
It works nicely with unittests, as opposed to function-based solutions.
Credit to answers in 1, 2 and other answers in this question.
我是从这个问题来的
如何装饰类的所有函数,而无需为每个方法一遍又一遍地键入它?
我想添加一条注释:
使用类装饰器或替换类方法(例如这个)的答案将不适用于
staticmethod
。您将得到
TypeError, Unexpected argument
因为您的方法将获取self/cls
作为第一个参数。大概是
装饰类不知道
self
方法的装饰器,即使使用inspect.ismethod
也无法区分它们。我找到了一个快速解决办法:
我没有仔细检查过它,但它通过了我的(不那么全面的)测试。
使用动态装饰器已经是一种糟糕的方法,因此,作为临时解决方案,它一定是可以的。
TLD:TD 添加
try/ except
以与staticmethod
一起使用I came to this question from
How to decorate all functions of a class without typing it over and over for each method?
and I want to add a note:
Answers with class decorators or repalcing class methods like this one will not work with
staticmethod
.You will get
TypeError, unexpected argument
because your method will getself/cls
as first argument.Probably the
decorated class doesn't know about decorators of
self
methods and can't distinguish them even withinspect.ismethod
.I come to such a quick fix:
I have not not checked it closely but it passes my (no so comprehensive) tests.
Using dynamic decorators is already a bad approach, so, it must be okay as a temporary solution.
TLD:TD Add
try/except
to use withstaticmethod
您可以重写 __getattr__ 方法。它实际上并没有附加装饰器,但它允许您返回装饰方法。您可能想做这样的事情:
那里隐藏着一些丑陋的递归,您需要防止它们,但这只是一个开始。
You could override the
__getattr__
method. It's not actually attaching a decorator, but it lets you return a decorated method. You'd probably want to do something like this:There's some ugly recursion hiding in there that you'll want to protect against, but that's a start.