1

我目前有这个代码:

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

4 回答 4

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 中,将函数作为类的属性仅返回函数,因为未绑定的方法已从语言中删除。此外,元类语法已更改为类定义行中的关键字参数。

测试:

>>> 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)
于 2012-11-03T01:26:56.233 回答
2

你有两个问题。

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

对于 1,如果您总是先调用,g.foo再调用Generator.foo,则只需添加该行

setattr(self.__class__, name, f)

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


对于 2,请参阅@thg435 的回答。请注意,由于 Python 2 中的向后兼容性,这很麻烦,并且在 Py3k 中已经得到了很大的改进——现在你所做的基本上可以工作了。这是因为自动注入self.

于 2012-11-02T11:33:08.987 回答
2

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

于 2012-11-02T11:24:20.810 回答
1

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

于 2012-11-02T11:28:30.670 回答