python中的动态方法生成

时间:2012-11-02 11:18:44

标签: python getattr

我目前有这段代码:

class Generator(object):
    def __getattr__(self, name):    
        def f(self):
            return ("Result of"+name, self)
        f.__name__ = name
        return f

    def foo(self):
        pass

g = Generator()
print g.foo
print Generator.foo
print g.bar
print Generator.bar

给出了:

<bound method Generator.foo of <__main__.Generator object at 0x00B62D30>>
<unbound method Generator.foo>
<function bar at 0x00A9DE70>
AttributeError: type object 'Generator' has no attribute 'bar'

我需要做些什么来实现:

<bound method Generator.foo of <__main__.Generator object at 0x00B62D30>>
<unbound method Generator.foo>
<bound method Generator.bar of <__main__.Generator object at 0x00B62D30>>
<unbound method Generator.bar>

4 个答案:

答案 0 :(得分:2)

__getattr__()仅适用于实例,您需要在Generator上的元类上创建该函数以获得您想要的行为。

答案 1 :(得分:2)

你有两个问题。

  1. 您只在实例 g(而不是类Generator)上设置动态功能,因此未定义Generator.bar
  2. 你没有将它包装在MethodType中,所以你得到的是函数而不是方法。

  3. 对于1,如果您在致电g.foo之前始终致电Generator.foo,则可以添加该行

    setattr(self.__class__, name, f)
    

    __getattr__内部,它将名称绑定为类的方法。否则,您将需要类型对象上的自定义__getattr__,这意味着您必须使其成为自定义类的实例,即编写您自己的元类。


    2,请参阅@ thg435的回答。请注意,由于Python 2中的向后兼容性,这很糟糕,并且已经在Py3k中大大加入了 - 现在你正在做的事情基本上是可行的。这是因为self的自动注入。

答案 2 :(得分:2)

这是一个元类,它将类定义中的__getattr__函数添加回元类本身。这避免了必须在多个位置定义函数,或者作为预先定义的单独的全局函数,并单独添加到元类和类。

class Meta(type):

    def __new__(mcls, name, bases, dikt):
        fgetattr = dikt.get('__getattr__')
        if fgetattr is not None:
            setattr(mcls, '__getattr__', fgetattr)
        return super(Meta, mcls).__new__(mcls, name, bases, dikt)

class Generator(object):
    __metaclass__ = Meta

    def __getattr__(obj, name):

        def f(self):
            return "Result of %s for %r" % (name, self)
        f.__name__ = name

        if isinstance(obj, type):
            setattr(obj, name, f)
        else:
            setattr(type(obj), name, f)
        return getattr(obj, name)

不是通过动态函数的__get__描述符方法直接创建方法,我认为最好将函数存储在类dict中,并依赖getattr返回正确的绑定/未绑定方法。后续属性访问将使用该类中的函数。由于同一个__getattr__函数用于类和实例,因此需要进行isinstance检查以确保将动态函数存储到类而不是实例。

在Python 3中,将函数作为类的属性仅返回函数,因为从语言中删除了未绑定的方法。此外,metaclass syntax已更改为类定义行中的关键字参数。

测试:

>>> g = Generator()
>>> g.foo
<bound method Generator.foo of <__main__.Generator object at 0xb7248c2c>>
>>> Generator.foo
<unbound method Generator.foo>
>>> g.bar
<bound method Generator.bar of <__main__.Generator object at 0xb7248c2c>>
>>> Generator.bar
<unbound method Generator.bar>
>>> g.foo()
'Result of foo for <__main__.Generator object at 0xb7248c2c>'
>>> Generator.foo(g)
'Result of foo for <__main__.Generator object at 0xb7248c2c>'
>>> 'foo' in vars(Generator), 'bar' in vars(Generator)
(True, True)

答案 3 :(得分:1)

对于第一种情况(g.bar),请将return f替换为return MethodType(f, self)