如何装饰类的所有函数,而无需为每个方法一遍又一遍地键入它?

发布于 2024-11-15 08:59:34 字数 790 浏览 2 评论 0原文

假设我的类有很多方法,我想在每个方法上应用我的装饰器,稍后当我添加新方法时,我希望应用相同的装饰器,但我不想写 @mydecorator 始终位于方法声明上方。

如果我查看 __call__ 这是正确的方法吗?


我想展示这种方式,对于后来发现这个问题的任何人来说,这是与我的问题类似的解决方案,使用评论中提到的混合。

class WrapinMixin(object):
    def __call__(self, hey, you, *args):
        print 'entering', hey, you, repr(args)
        try:
            ret = getattr(self, hey)(you, *args)
            return ret
        except:
            ret = str(e)
            raise
        finally:
            print 'leaving', hey, repr(ret)
    

然后您可以在另一个

class Wrapmymethodsaround(WrapinMixin): 
    def __call__(self, hey, you, *args):
         return super(Wrapmymethodsaround, self).__call__(hey, you, *args)

编者注中:此示例似乎解决了与所询问的问题不同的问题。

Lets say my class has many methods, and I want to apply my decorator on each one of them, later when I add new methods, I want the same decorator to be applied, but I don't want to write @mydecorator above the method declaration all the time.

If I look into __call__ is that the right way to go?


I'd like to show this way, which is a similar solution to my problem for anybody finding this question later, using a mixin as mentioned in the comments.

class WrapinMixin(object):
    def __call__(self, hey, you, *args):
        print 'entering', hey, you, repr(args)
        try:
            ret = getattr(self, hey)(you, *args)
            return ret
        except:
            ret = str(e)
            raise
        finally:
            print 'leaving', hey, repr(ret)
    

Then you can in another

class Wrapmymethodsaround(WrapinMixin): 
    def __call__(self, hey, you, *args):
         return super(Wrapmymethodsaround, self).__call__(hey, you, *args)

Editor's note: this example appears to be solving a different problem than what is asked about.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

小巷里的女流氓 2024-11-22 08:59:34

使用遍历类的属性并装饰可调用对象的函数来装饰类。如果您的类变量可能是可调用的,并且还会装饰嵌套类(感谢 Sven Marnach 指出了这一点),那么这可能是错误的做法,但通常这是一个相当干净和简单的解决方案。示例实现(请注意,这不会排除特殊方法(__init__ 等),这可能是需要的,也可能不是):

def for_all_methods(decorator):
    def decorate(cls):
        for attr in cls.__dict__: # there's propably a better way to do this
            if callable(getattr(cls, attr)):
                setattr(cls, attr, decorator(getattr(cls, attr)))
        return cls
    return decorate

像这样使用:

@for_all_methods(mydecorator)
class C(object):
    def m1(self): pass
    def m2(self, x): pass
    ...

Decorate the class with a function that walks through the class's attributes and decorates callables. This may be the wrong thing to do if you have class variables that may happen to be callable, and will also decorate nested classes (credits to Sven Marnach for pointing this out) but generally it's a rather clean and simple solution. Example implementation (note that this will not exclude special methods (__init__ etc.), which may or may not be desired):

def for_all_methods(decorator):
    def decorate(cls):
        for attr in cls.__dict__: # there's propably a better way to do this
            if callable(getattr(cls, attr)):
                setattr(cls, attr, decorator(getattr(cls, attr)))
        return cls
    return decorate

Use like this:

@for_all_methods(mydecorator)
class C(object):
    def m1(self): pass
    def m2(self, x): pass
    ...
一场春暖 2024-11-22 08:59:34

虽然当显式方法可以时我不喜欢使用神奇的方法,但您可能可以为此使用元类。

def myDecorator(fn):
    fn.foo = 'bar'
    return fn

class myMetaClass(type):
    def __new__(cls, name, bases, local):
        for attr in local:
            value = local[attr]
            if callable(value):
                local[attr] = myDecorator(value)
        return type.__new__(cls, name, bases, local)

class myClass(object):
    __metaclass__ = myMetaClass
    def baz(self):
        print self.baz.foo

它的工作原理就好像 myClass 中的每个可调用对象都用 myDecorator 进行了装饰

>>> quux = myClass()
>>> quux.baz()
bar

While I'm not fond of using magical approaches when an explicit approach would do, you can probably use a metaclass for this.

def myDecorator(fn):
    fn.foo = 'bar'
    return fn

class myMetaClass(type):
    def __new__(cls, name, bases, local):
        for attr in local:
            value = local[attr]
            if callable(value):
                local[attr] = myDecorator(value)
        return type.__new__(cls, name, bases, local)

class myClass(object):
    __metaclass__ = myMetaClass
    def baz(self):
        print self.baz.foo

and it works as though each callable in myClass had been decorated with myDecorator

>>> quux = myClass()
>>> quux.baz()
bar
暗地喜欢 2024-11-22 08:59:34

不是为了死而复生,但我真的很喜欢德尔南的答案,但发现它缺乏。

def for_all_methods(exclude, decorator):
    def decorate(cls):
        for attr in cls.__dict__:
            if callable(getattr(cls, attr)) and attr not in exclude:
                setattr(cls, attr, decorator(getattr(cls, attr)))
        return cls
    return decorate

编辑:修复缩进

所以你可以指定方法//属性//你不想装饰的东西

Not to revive things from the dead, but I really liked delnan's answer, but found it sllliigghhtttlllyy lacking.

def for_all_methods(exclude, decorator):
    def decorate(cls):
        for attr in cls.__dict__:
            if callable(getattr(cls, attr)) and attr not in exclude:
                setattr(cls, attr, decorator(getattr(cls, attr)))
        return cls
    return decorate

EDIT: fix indenting

So you can specify methods//attributes//stuff you don't want decorated

分开我的手 2024-11-22 08:59:34

上述答案都不适合我,因为我还想装饰继承的方法,这不是通过使用 __dict__ 来完成的,而且我不想使用元类使事情变得过于复杂。最后,我很乐意为 Python 2 提供一个解决方案,因为我只是立即需要添加一些分析代码来测量类的所有函数所使用的时间。

import inspect
def for_all_methods(decorator):
    def decorate(cls):
        for name, fn in inspect.getmembers(cls, inspect.ismethod):
            setattr(cls, name, decorator(fn))
        return cls
    return decorate

来源(略有不同的解决方案):https://stackoverflow.com/a/3467879/1243926
在那里,您还可以了解如何针对 Python 3 更改它。

正如对其他答案的评论所建议的那样,请考虑使用 inspect.getmembers(cls,spectr.isroutine) 代替。如果您找到了适用于 Python 2 和 Python 3 并装饰继承方法的正确解决方案,并且仍然可以在 7 行内完成,请编辑。

None of the above answers worked for me, since I wanted to also decorate the inherited methods, which was not accomplished by using __dict__, and I did not want to overcomplicate things with metaclasses. Lastly, I am fine with having a solution for Python 2, since I just have an immediate need to add some profiling code for measuring time used by all functions of a class.

import inspect
def for_all_methods(decorator):
    def decorate(cls):
        for name, fn in inspect.getmembers(cls, inspect.ismethod):
            setattr(cls, name, decorator(fn))
        return cls
    return decorate

Source (slightly different solution): https://stackoverflow.com/a/3467879/1243926
There you can also see how to change it for Python 3.

As comments to other answers suggest, consider using inspect.getmembers(cls, inspect.isroutine) instead. If you have found a proper solution that works for both Python 2 and Python 3 and decorates inherited methods, and can still be done in 7 lines, please, edit.

╭ゆ眷念 2024-11-22 08:59:34

您可以生成一个元类。这不会修饰继承的方法。

def decorating_meta(decorator):
    class DecoratingMetaclass(type):
        def __new__(self, class_name, bases, namespace):
            for key, value in list(namespace.items()):
                if callable(value):
                    namespace[key] = decorator(value)

            return type.__new__(self, class_name, bases, namespace)

    return DecoratingMetaclass

这将生成一个元类,用指定的函数装饰所有方法。您可以通过执行以下操作在 Python 2 或 3 中使用它

def doubling_decorator(f):
    def decorated(*a, **kw):
        return f(*a, **kw) * 2
    return decorated

class Foo(dict):
    __metaclass__ = decorating_meta(doubling_decorator)

    def lookup(self, key):
        return self[key]

d = Foo()
d["bar"] = 5
print(d.lookup("bar")) # prints 10

You could generate a metaclass. This will not decorate inherited methods.

def decorating_meta(decorator):
    class DecoratingMetaclass(type):
        def __new__(self, class_name, bases, namespace):
            for key, value in list(namespace.items()):
                if callable(value):
                    namespace[key] = decorator(value)

            return type.__new__(self, class_name, bases, namespace)

    return DecoratingMetaclass

This will generate a metaclass decorating all methods with the specified function. You can use it in Python 2 or 3 by doing something like this

def doubling_decorator(f):
    def decorated(*a, **kw):
        return f(*a, **kw) * 2
    return decorated

class Foo(dict):
    __metaclass__ = decorating_meta(doubling_decorator)

    def lookup(self, key):
        return self[key]

d = Foo()
d["bar"] = 5
print(d.lookup("bar")) # prints 10
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文