如何使用 metaclass 添加方法

10 投票
2 回答
6291 浏览
提问于 2025-04-11 09:22

我想知道怎么通过元类给一个类添加实例方法(是的,我确实需要用元类)。下面的代码有点效果,但函数的名字还是“foo”:

def bar(self):
    print "bar"

class MetaFoo(type):
    def __new__(cls, name, bases, dict):
        dict["foobar"] = bar
        return type(name, bases, dict)

class Foo(object):
    __metaclass__ = MetaFoo

>>> f = Foo()
>>> f.foobar()
bar
>>> f.foobar.func_name
'bar'

我的问题是,有些库的代码实际上会用到这个函数名,结果找不到Foo实例的“bar”方法。我可以这样做:

dict["foobar"] = types.FunctionType(bar.func_code, {}, "foobar")

还有一种叫做types.MethodType的东西,但我需要一个还不存在的实例来使用它。我是不是漏掉了什么?

2 个回答

3

我觉得你想做的事情是这样的:

>>> class Foo():
...   def __init__(self, x):
...     self.x = x
... 
>>> def bar(self):
...   print 'bar:', self.x
... 
>>> bar.func_name = 'foobar'
>>> Foo.foobar = bar
>>> f = Foo(12)
>>> f.foobar()
bar: 12
>>> f.foobar.func_name
'foobar'

现在你可以把 Foo 对象传给一个需要 Foo 实例有一个叫 foobar 方法的库了。

不过很遗憾的是,(1) 我不知道怎么使用 metaclass(元类),(2) 我也不太确定我理解了你的问题,但我希望这些能对你有帮助。

请注意,func_name 这个功能只有在 Python 2.4 及以上版本中才能使用。

17

试着以这种方式动态地扩展基类,这样你就可以利用方法解析顺序(mro),而且这些方法是真正的可用方法:

Python 3:

class Parent(object):
    def bar(self):
        print("bar")

class MetaFoo(type):
    def __new__(cls, name, bases, dict):
        return type(name, (Parent,) + bases, dict)

class Foo(metaclass=MetaFoo): 
    ...

f = Foo()
f.bar()

print(f.bar.__qualname__)

Python 2:

class Parent(object):
    def bar(self):
        print "bar"

class MetaFoo(type):
    def __new__(cls, name, bases, dict):
        return type(name, (Parent,) + bases, dict)

class Foo(object):
    __metaclass__ = MetaFoo

if __name__ == "__main__":
    f = Foo()
    f.bar()
    print f.bar.func_name

撰写回答