我正在创建一个元类,我在其中自定义__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
这不起作用,因为六个使用给定的元类创建一个新的基类。下面是六个代码(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
答案 0 :(得分:2)
如果我理解你的话,那就没问题了,它已经有效了。你真的检查过你的元类是否有预期的效果吗?因为我认为它已经存在了。
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__
- 即类的属性及其值。根据我的经验,此属性通常称为attrs
或dct
(请参阅例如here和here)。