【问题标题】:Python 2 and 3 metaclass compatibility when kwargs are used使用 kwargs 时的 Python 2 和 3 元类兼容性
【发布时间】:2013-05-13 19:57:06
【问题描述】:

我正在创建一个元类,我在其中自定义 __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 使用给定的元类创建了一个新的基类。以下是六位代码 (link)(截至 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

【问题讨论】:

    标签: python django python-3.x metaclass


    【解决方案1】:

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

    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'
    

    顺便说一句,调用元类的第三个参数kwargs 会让人感到困惑。它不是真正的关键字参数。就是要创建的类的__dict__——即类的属性及其值。根据我的经验,这个属性通常称为attrsdct(参见例如herehere)。

    【讨论】:

    • 你是对的。该问题与 Django 以及我如何在 __new__ 中实现自定义登录有关。我只是将问题归咎于兼容性。感谢您澄清情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2010-09-14
    • 2016-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多