4

有没有办法编写一个元类,使得基于这个元类的类中定义的所有方法默认都是类方法(即不需要,例如@classmethod装饰等)?

谢谢!

编辑:我对 Python 2.7.3 感兴趣。请原谅遗漏。

4

2 回答 2

3

当然。真正的问题是你为什么要这样做。我将假设这仅用于教育。实际上,无论这可以用于什么,都可能最好明确地完成(即不使用元类并添加@classmethod)。

我知道两个选项:类定义的自定义命名空间和__new__. 第一个非常酷,在某些情况下实际上是不可避免的(例如记住方法定义的顺序),但后者更简单、更灵活,不会意外破坏同名的多个赋值,并且在 Python 2 中可用。你的目的,这排除了前者,但我会把它留给所有可以使用 Python 3 的人。

要提供自定义命名空间,您必须__prepare__在元类中定义并返回类似字典的对象(Ferdinand Beyer 在评论中指出:定义的映射接口collections就足够了)。在这种情况下,字典应该重写__setitem__以检查值是否为callable,如果是,则在classmethod存储之前将其包装起来。我非常感谢下面的评论,他们极大地改进了下面的代码。Ferdinand Beyer 注意到这callable(classmethod(...))是错误的,并且 agf 指出了与@classmethodPython 3 兼容性的不一致之处。

import types

# Either this, in a dictionary class instanciated in __prepare__
# Again, Python 3 only
def __setitem__(self, name, value):
    if isinstance(value, types.FunctionType):
        value = classmethod(value)
    super().__setitem__(name, value)

# __prepare__ would be: return AutomaticClassMethodNamespace() or something

# Or this in the metaclass
def __new__(mcls, clsname, bases, ns):
    for name, value in ns.items():
        if isinstance(value, types.FunctionType):
            ns[name] = classmethod(value)
    # Any other metaclass behaviour
于 2012-05-08T17:24:45.330 回答
0

像这样的东西(2.7)

def m(name, bases, dct):
    for k, v in dct.items():
        if type(v) is type(m):
            dct[k] = classmethod(v)
    return type(name, bases, dct)

class A:
    __metaclass__ = m

    def foo(self):
        print self


A.foo() # <class '__main__.A'>
于 2012-05-08T17:23:06.640 回答