Как создать декоратор классов Python, который может оборачивать экземпляры, классы и статические методы?

Я хотел бы создать декоратор классов 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 s в зависимости от того, какой закомментированный фрагмент раскомментирован, например:

  • TypeError: несвязанный метод wrapped () должен вызываться с экземпляром SomeClass в качестве первого аргумента (вместо этого получен экземпляр int)
  • TypeError: classMethod () принимает ровно 2 аргументы (3 дано)

(*): Та же проблема намного проще, если вы декорируете методы напрямую .

7
задан Community 23 May 2017 в 11:52
поделиться