如何在不添加每个方法的情况下反复输入类的所有函数? Python [重复]

时间:2021-07-29 14:26:58

This question already has an answer here:

这个问题在这里已有答案:

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 dont want to write @mydecorator above the method declaration all the time?

让我们说我的类有很多方法,我想在每个方法上应用我的装饰器,稍后当我添加新方法时,我想要应用相同的装饰器,但我不想在方法声明之上写@mydecorator所有时间?

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

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

Thanks

谢谢

IMPORTANT: the example below appears to be solving a different problem than the original question asked about.

重要提示:以下示例似乎解决了与原始问题不同的问题。

EDIT: Id like to show this way, which is a similar solution to my problem for anyobody finding this question later, using a mixin as mentioned in the comments.

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

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__:
         return super(Wrapmymethodsaround, self).__call__(hey, you, *args)

5 个解决方案

#1


44  

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):

使用遍历类的属性并装饰callables的函数来装饰类。如果你的类变量可能碰巧是可调用的,那么这可能是错误的做法,并且还会修饰嵌套类(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

Use like this:

使用这样:

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

In Python 3.0 and 3.1, callable does not exist. It existed since forever in Python 2.x and is back in Python 3.2 as wrapper for isinstance(x, collections.Callable), so you can use that (or define your own callable replacement using this) in those versions.

在Python 3.0和3.1中,callable不存在。它永远存在于Python 2.x中,并作为isinstance(x,collections.Callable)的包装器返回到Python 3.2中,因此您可以在这些版本中使用它(或使用此定义您自己的可调用替换)。

#2


24  

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

它就好像myClass中的每个callable都用myDecorator修饰一样

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

#3


7  

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

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

#4


3  

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.

上面的答案都没有对我有用,因为我还想装饰继承的方法,这是通过使用__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

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

来源(略有不同的解决方案):https://*.com/a/3467879/1243926在那里你还可以看到如何为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.

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

#5


2  

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

这将生成一个元类,用指定的函数装饰所有方法。你可以通过这样的方式在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

#1


44  

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):

使用遍历类的属性并装饰callables的函数来装饰类。如果你的类变量可能碰巧是可调用的,那么这可能是错误的做法,并且还会修饰嵌套类(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

Use like this:

使用这样:

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

In Python 3.0 and 3.1, callable does not exist. It existed since forever in Python 2.x and is back in Python 3.2 as wrapper for isinstance(x, collections.Callable), so you can use that (or define your own callable replacement using this) in those versions.

在Python 3.0和3.1中,callable不存在。它永远存在于Python 2.x中,并作为isinstance(x,collections.Callable)的包装器返回到Python 3.2中,因此您可以在这些版本中使用它(或使用此定义您自己的可调用替换)。

#2


24  

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

它就好像myClass中的每个callable都用myDecorator修饰一样

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

#3


7  

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

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

#4


3  

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.

上面的答案都没有对我有用,因为我还想装饰继承的方法,这是通过使用__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

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

来源(略有不同的解决方案):https://*.com/a/3467879/1243926在那里你还可以看到如何为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.

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

#5


2  

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

这将生成一个元类,用指定的函数装饰所有方法。你可以通过这样的方式在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