如何创建一个能够包装实例,类和静态方法的Python类装饰器? [英] How to create a Python class decorator that is able to wrap instance, class and static methods?

查看:104
本文介绍了如何创建一个能够包装实例,类和静态方法的Python类装饰器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个Python 类装饰器(*),它将能够无缝包装该类可能具有的所有方法类型:实例,类和静态。

I'd like to create a Python class decorator (*) that would be able to seamlessly wrap all method types the class might have: instance, class and static.

这是我现在拥有的代码,带有注释的部分已注释:

This is the code I have for now, with the parts that break it commented:

def wrapItUp(method):
    def wrapped(*args, **kwargs):
        print "This method call was wrapped!"
        return method(*args, **kwargs)
    return wrapped

dundersICareAbout = ["__init__", "__str__", "__repr__"]#, "__new__"]

def doICareAboutThisOne(cls, methodName):
    return (callable(getattr(cls, methodName))
            and (not (methodName.startswith("__") and methodName.endswith("__"))
            or methodName in dundersICareAbout))

def classDeco(cls):
    myCallables = ((aname, getattr(cls, aname)) for aname in dir(cls) if doICareAboutThisOne(cls, aname))
    for name, call in myCallables:
        print "*** Decorating: %s.%s(...)" % (cls.__name__, name)
        setattr(cls, name, wrapItUp(call))
    return cls

@classDeco
class SomeClass(object):

    def instanceMethod(self, p):
        print "instanceMethod: p =", p

    @classmethod
    def classMethod(cls, p):
        print "classMethod: p =", p

    @staticmethod
    def staticMethod(p):
        print "staticMethod: p =", p


instance = SomeClass()
instance.instanceMethod(1)
#SomeClass.classMethod(2)
#instance.classMethod(2)
#SomeClass.staticMethod(3)
#instance.staticMethod(3)

我有两个问题要尝试完成此工作:

I'm having two issues trying to make this work:


  • 遍历所有可调用对象时,如何确定它是实例,类还是静态类型?

  • 如何用适当的包装版本覆盖该方法,

当前,此代码会生成不同的 TypeError s取决于未注释的摘录片段,例如:

Currently, this code generates different TypeErrors depending on what commented snippet is uncommented, like:


  • TypeError:必须绑定未绑定的方法wrapd()以SomeClass实例作为第一个参数调用(改为int实例)

  • TypeError:classMethod()恰好接受2个参数(给定3个)

  • TypeError: unbound method wrapped() must be called with SomeClass instance as first argument (got int instance instead)
  • TypeError: classMethod() takes exactly 2 arguments (3 given)

(*):如果您直接装饰方法

推荐答案

由于方法是函数的包装器,因此在构造类之后,要在类的方法上应用装饰器,您必须:

Because methods are wrappers for functions, to apply a decorator to a method on a class after the class has been constructed, you have to:


  1. 使用其 im_func 属性从方法中提取基础函数。

  2. 装饰函数。

  3. 重新应用包装器。

  4. 用包装后的装饰函数覆盖属性。

  1. Extract the underlying function from the method using its im_func attribute.
  2. Decorate the function.
  3. Re-apply the wrapper.
  4. Overwrite the attribute with the wrapped, decorated function.

一旦类方法与常规方法区分开> @classmethod 装饰器已被应用;两种方法的类型均为 instancemethod 。但是,您可以检查 im_self 属性,查看它是否为 None 。如果是这样,这是一个常规实例方法;否则,这是类方法

It is difficult to distinguish a classmethod from a regular method once the @classmethod decorator has been applied; both kinds of methods are of type instancemethod. However, you can check the im_self attribute and see whether it is None. If so, it's a regular instance method; otherwise it's a classmethod.

静态方法是简单的函数( @staticmethod 装饰器仅阻止应用常规方法包装器)。因此,您不必为此做任何特殊的事情。

Static methods are simple functions (the @staticmethod decorator merely prevents the usual method wrapper from being applied). So you don't have to do anything special for these, it looks like.

所以基本上您的算法如下:

So basically your algorithm looks like this:


  1. 获取属性。

  2. 可调用吗?如果不是,请转到下一个属性。

  3. 其类型是否为 types.MethodType ?如果是这样,则它是类方法或实例方法。

    • 如果其 im_self None ,则为实例方法。通过 im_func 属性提取基础函数,进行修饰,然后重新应用实例方法: meth = types.MethodType(func,None,cls )

    • 如果其 im_self 不是 None ,这是一个类方法。通过 im_func 提取基础函数并进行装饰。现在,您必须重新应用 classmethod 装饰器,但是您不能这样做,因为 classmethod()不上课,因此无法指定它将附加到的类。相反,您必须使用实例方法装饰器: meth = types.MethodType(func,cls,type)。请注意,这里的 type 是实际的内置 type

  1. Get the attribute.
  2. Is it callable? If not, proceed to the next attribute.
  3. Is its type types.MethodType? If so, it is either a class method or an instance method.
    • If its im_self is None, it is an instance method. Extract the underlying function via the im_func attribute, decorate that, and re-apply the instance method: meth = types.MethodType(func, None, cls)
    • If its im_self is not None, it is a class method. Exctract the underlying function via im_func and decorate that. Now you have to reapply the classmethod decorator but you can't because classmethod() doesn't take a class, so there's no way to specify what class it will be attached to. Instead you have to use the instance method decorator: meth = types.MethodType(func, cls, type). Note that the type here is the actual built-in, type.

这些变化在Python中有所改变3-IIRC是函数的绑定方法。无论如何,这可能需要在这里完全重新考虑。

These change somewhat in Python 3 -- unbound methods are functions there, IIRC. In any case this will probably need to be completely rethought there.

这篇关于如何创建一个能够包装实例,类和静态方法的Python类装饰器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆