gpt4 book ai didi

python - 如何创建一个能够包装实例、类和静态方法的 Python 类装饰器?

转载 作者:太空狗 更新时间:2023-10-29 21:44:23 27 4
gpt4 key购买 nike

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

这是我目前拥有的代码,对破坏代码的部分进行了注释:

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)

我在尝试完成这项工作时遇到了两个问题:

  • 在遍历所有可调用对象时,如何确定它是实例、类还是静态类型?
  • 如何使用针对每种情况正确调用的适当包装版本覆盖该方法?

目前,此代码会根据未注释的注释片段生成不同的 TypeError,例如:

  • TypeError:未绑定(bind)方法 wrapped() 必须使用 SomeClass 实例作为第一个参数调用(取而代之的是 int 实例)
  • TypeError:classMethod() 正好接受 2 个参数(给定 3 个)

(*):如果你是decorating the methods directly,同样的问题就简单多了。 .

最佳答案

因为方法是函数的包装器,所以要在构造类后将装饰器应用于类的方法,您必须:

  1. 使用 im_func 属性从方法中提取底层函数。
  2. 装饰函数。
  3. 重新应用包装。
  4. 用包装的、修饰的函数覆盖属性。

一旦应用了 @classmethod 装饰器,就很难区分 classmethod 和常规方法;这两种方法都是 instancemethod 类型。但是,您可以检查 im_self 属性并查看它是否为 None。如果是这样,它就是一个普通的实例方法;否则它是一个classmethod

静态方法是简单的函数(@staticmethod 装饰器只是阻止应用通常的方法包装器)。所以你不必为这些做任何特别的事情,它看起来像。

所以基本上你的算法看起来像这样:

  1. 获取属性。
  2. 它可以调用吗?如果不是,则继续下一个属性。
  3. 它的类型是types.MethodType吗?如果是这样,它要么是类方法,要么是实例方法。
    • 如果它的im_selfNone,它就是一个实例方法。通过 im_func 属性提取底层函数,对其进行修饰,然后重新应用实例方法:meth = types.MethodType(func, None, cls)
    • 如果它的im_self不是None,它就是一个类方法。通过 im_func 提取底层函数并对其进行修饰。现在您必须重新应用 classmethod 装饰器,但您不能这样做,因为 classmethod() 不接受类,因此无法指定它将附加到哪个类至。相反,您必须使用实例方法装饰器:meth = types.MethodType(func, cls, type)。请注意,此处的 type 是实际的内置 type
  4. 如果它的类型不是types.MethodType,那么它是一个静态方法或其他非绑定(bind)的可调用对象,所以只需装饰它。
  5. 将新属性设置回类。

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

关于python - 如何创建一个能够包装实例、类和静态方法的 Python 类装饰器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8185375/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com