8

我有一个案例,我的类有一个自定义元类,它在创建它时调用该类的类方法,例如:

class Metaclass(type):
    def __new__(cls, name, bases, attrs):
        ...
        new_class = super(Metaclass, cls).__new__(cls, name, bases, attrs)
        ...
        new_class.get_fields() # do something
        ...
        return new_class

class FooBar(object):
    __metaclass__ = Metaclass

    @classmethod
    def get_fields(cls):
        ...

(此类代码的示例在Tastypie中。)

问题是如果我想做:

class NewBar(FooBar):
    @classmethod
    def get_fields(cls):
        super(NewBar, cls).get_fields()
        ...

这不起作用,因为NewBar在调用点尚未创建super(程序流仍在元类中)。那么,有什么解决方法吗?

我知道get_fields方法可能会成为元类的方法,但这会使继承更难实现(您必须同时定义新的元类和类本身,这对想要扩展这些类的开发人员不利)。

(Python 2.7。)

4

3 回答 3

2

如果NewBar可以在get_fields被调用时不可用,您仍然可以在 MRO 中找到它cls

@classmethod
def get_fields(cls):
    # we can get invoked before NewBar is available in globals,
    # so get NewBar from cls.__mro__
    NewBar = next(c for c in cls.__mro__
                  if c.__module__ == __name__ and c.__name__ == 'NewBar')
    super(NewBar, cls).get_fields()
    ...

尽管此代码看起来很有趣,但它可以正常工作并且比问题中提出的替代方案要简单得多。虽然大多数super使用非常量第一个参数(例如 unqualified super(cls, cls))的调用都是不正确的并且会破坏继承,但这个调用是安全的,因为生成器表达式只不过是获取NewBar.

在 MRO 中查找 clas 时,我们会检查类和模块名称(如 Mitar 所指出的那样可用__name__避免误报,如果othermodule.NewBar继承自thismodule.NewBar.

于 2012-10-06T07:30:42.013 回答
0

根据@user4815162342 的回答,我找到了更简单的解决方案:

try:
    super(NewBar, cls).get_fields()
except NameError, e:
    if 'NewBar' in str(e):
        super(cls, cls).get_fields()
    else:
        raise
于 2012-10-06T08:09:37.720 回答
0

我知道这个问题是 python 2.7 特有的,但是,对于那些使用 python 3.6 的人,你可以简单地调用super().

class NewBar(FooBar):
    @classmethod
    def get_fields(cls):
        super().get_fields()
        ...
于 2017-09-07T08:38:40.310 回答