3

我正在制作一个元类,我在其中自定义__new__方法来自定义如何根据提供的值创建新类kwargs。这在一个例子中可能更有意义:

class FooMeta(type):
    def __new__(cls, name, bases, kwargs):
        # do something with the kwargs...
        # for example:
        if 'foo' in kwargs:
            kwargs.update({
                'fooattr': 'foovalue'
            })
        return super(FooMeta, cls).__new__(cls, name, bases, kwargs)

我的问题是如何使它兼容 Python 2 和3。Six是一个很好的兼容性库,但它不能解决我的问题。您可以将其用作:

class FooClass(six.with_metaclass(FooMeta, FooBase)):
    pass

这不起作用,因为 6 使用给定的元类创建了一个新的基类。以下是六的代码(链接)(截至 1.3):

def with_metaclass(meta, base=object):
    return meta("NewBase", (base,), {})

结果,我的__new__方法将在没有任何kwargs因此本质上“破坏”我的函数的情况下被调用。问题是如何在不破坏 Python 2 和 3 兼容性的情况下完成我想要的行为。请注意,我不需要 Python 2.6 支持,所以如果只有 Python 2.7.x 和 3.x 有可能的话,我是没关系。

背景

我需要这个在 Django 中工作。我想创建一个模型工厂元类,它根据模型属性将自定义模型的创建方式。

class ModelMeta(ModelBase):
    def __new__(cls, name, bases, kwargs):
        # depending on kwargs a different model is constructed
        # ...

class FooModel(six.with_metaclass(ModelMeta, models.Model):
    # some attrs here to be passed to the metaclass
4

1 回答 1

4

如果我理解你的话,没有问题,它已经工作了。您是否真的检查过您的元类是否具有预期的效果?因为我认为它已经做到了。

返回的类with_metaclass并不意味着扮演你的类 FooClass 的角色。它是一个虚拟类,用作您的类的类。由于这个基类属于元类 FooMeta,因此您的派生类也将具有元类 FooMeta,因此将使用适当的参数再次调用元类。

class FooMeta(type):
    def __new__(cls, name, bases, attrs):
        # do something with the kwargs...
        # for example:
        if 'foo' in attrs:
            attrs['fooattr'] = 'foovalue'
        return super(FooMeta, cls).__new__(cls, name, bases, attrs)
class FooBase(object):
    pass
class FooClass(with_metaclass(FooMeta, FooBase)):
    foo = "Yes"

>>> FooClass.fooattr
'foovalue'

顺便说一句,调用 metaclass 的第三个参数是令人困惑的kwargs。它不是真正的关键字参数。它是__dict__要创建的类的 --- 即类的属性及其值。以我的经验,这个属性通常被称为attrs或可能dct(参见例如,herehere)。

于 2013-05-18T22:39:36.063 回答