Skip to main content
 首页 » 编程设计

python之python中的动态方法生成

2025年05月04日14duanxz

我目前有这段代码:

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> 

请您参考如下方法:

这是一个元类,它将类定义中的 __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 返回正确的绑定(bind)/未绑定(bind)方法。随后的属性访问将使用类中的函数。由于相同的 __getattr__ 函数同时用于类和实例,因此需要进行 isinstance 检查以确保将动态函数存储到类而不是实例。

在 Python 3 中,将函数作为类的属性获取仅返回函数,因为从语言中删除了未绑定(bind)的方法。此外,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)