4

当你装饰一个方法时,它还没有绑定到类,因此还没有im_class属性。我正在寻找一种方法来获取有关装饰器内的类的信息。我试过这个:

import types

def decorator(method):

    def set_signal(self, name, value):
        print name
        if name == 'im_class':
            print "I got the class"

    method.__setattr__ = types.MethodType(set_signal, method)

    return method


class Test(object):
    @decorator
    def bar(self, foo):
        print foo

但它不打印任何东西。

我可以想象这样做:

class Test(object):
    @decorator(klass=Test)
    def bar(self, foo):
        print foo

但如果我能避免它,它会让我很开心。

4

4 回答 4

3

__setattr__仅在显式object.attribute =分配时调用;构建一个类不使用属性分配,而是构建一个字典 ( Test.__dict__)。

但是,要访问该课程,您有几个不同的选择:

  1. 改用类装饰器;它将在构建完成后传递给完成的类,您可以通过在类中替换它们(装饰)来装饰该类上的各个方法。您可以使用函数装饰器和类装饰器的组合来标记要装饰的方法:

    def methoddecoratormarker(func):
        func._decorate_me = True
        return func
    
    def realmethoddecorator(func):
        # do something with func. 
        # Note: it is still an unbound function here, not a method!
        return func
    
    def classdecorator(klass):
        for name, item in klass.__dict__.iteritems():
            if getattr(item, '_decorate_me', False):
                klass.__dict__[name] = realmethoddecorator(item)
    

    当然,您可以使用元类而不是类装饰器来实现相同的目的。

  2. 作弊,并用于sys._getframe()从调用框架中检索类:

    import sys
    
    def methoddecorator(func):
         callingframe = sys._getframe(1)
         classname = callingframe.f_code.co_name
    

    请注意,您只能检索类的名称;类本身仍在构建中。您可以将项目添加到callingframe.f_locals(映射),它们将成为新类对象的一部分。

  3. 调用方法时访问selfself毕竟是对实例的引用,并且self.__class__至少将成为定义函数的原始类的子类。

于 2012-10-08T09:57:34.127 回答
1

我的严格回答是:这是不可能的,因为在执行装饰器时该类还不存在。

更长的答案将取决于您非常确切的要求。正如我所写,如果该类尚不存在,您将无法访问该类。一种解决方案是,将修饰的方法标记为稍后“转换”。然后在创建类后使用元类或类装饰器应用您的修改。

另一种选择涉及一些魔法。在 中查找该implements方法的实现zope.interfaces。它可以访问有关刚刚解析的类的信息。不知道它是否足以满足您的用例。

于 2012-10-08T09:40:23.627 回答
0

您可能想看看描述符。它们允许您实现在__get__访问属性时使用的 a,并且可以根据对象及其类型返回不同的内容。

于 2012-10-08T09:30:17.997 回答
0

使用方法装饰器将一些标记属性添加到有趣的方法中,并使用一个元类来迭代方法、查找标记属性并执行逻辑。元类代码在创建类时运行,因此它具有对新创建类的引用。

class MyMeta(object):
  def __new__(...):
    ...
    cls = ...
    ... iterate over dir(cls), find methods having .is_decorated, act on them
    return cls
def decorator(f):
  f.is_decorated = True
  return f
class MyBase(object):
  __metaclass__ = MyMeta
class MyClass(MyBase):
  @decorator
  def bar(self, foo):
    print foo

如果您担心程序员MyClass忘记使用,您可以通过检查调用者堆栈框架的全局字典( )MyBase来强制设置元类。decoratorsys._getframe()

于 2012-10-08T09:50:45.037 回答