首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python :理解'with_metaclass()‘

Python :理解'with_metaclass()‘
EN

Stack Overflow用户
提问于 2013-08-29 14:32:49
回答 2查看 30.3K关注 0票数 61

我想问with_metaclass()调用在类的定义中意味着什么。

例如:

代码语言:javascript
复制
class Foo(with_metaclass(Cls1, Cls2)):
  • 这是一个特殊情况,类继承自元类吗?
  • 新的类也是元类吗?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-08-29 14:34:19

with_metaclass()图书馆提供的实用程序类工厂函数,它使为Python2和3开发代码变得更加容易。

它对临时元类使用了一些技巧(见下文),以与Python 2和Python 3交叉兼容的方式将元类附加到常规类。

引用文件的话:

使用基类基类和元类元类创建一个新类。它被设计用于类似于以下类的声明: 从六个导入with_metaclass类元(类型):传递类基础(对象):传递类MyClass(with_metaclass(Meta,Base)):pass

之所以需要这样做,是因为附加元类的语法在Python 2和3之间更改:

Python 2:

代码语言:javascript
复制
class MyClass(object):
    __metaclass__ = Meta

Python 3:

代码语言:javascript
复制
class MyClass(metaclass=Meta):
    pass

with_metaclass()函数利用了元类是由子类继承的事实,b)元类可以用于生成新的类;c)当您从带有元类的基类生成子类时,创建实际的子类对象被委托给元类。它有效地创建了一个具有临时metaclass元类的新的临时基类,当用于创建子类时,可以将临时基类和元类与您选择的元类组合起来:

代码语言:javascript
复制
def with_metaclass(meta, *bases):
    """Create a base class with a metaclass."""
    # This requires a bit of explanation: the basic idea is to make a dummy
    # metaclass for one level of class instantiation that replaces itself with
    # the actual metaclass.
    class metaclass(type):

        def __new__(cls, name, this_bases, d):
            return meta(name, bases, d)

        @classmethod
        def __prepare__(cls, name, this_bases):
            return meta.__prepare__(name, bases)
    return type.__new__(metaclass, 'temporary_class', (), {})

打破上面的话:

  • type.__new__(metaclass, 'temporary_class', (), {})使用metaclass元类来创建一个名为temporary_class的新类对象,否则它完全是空的。使用type.__new__(metaclass, ...)而不是metaclass(...)来避免使用下一步工作中需要的特殊metaclass.__new__()实现。
  • 仅在Python3中,当temporary_class用作基类时,Python首先调用metaclass.__prepare__() (传入派生类名,(temporary_class,)作为this_bases参数。然后使用预期的元类meta调用meta.__prepare__(),忽略this_bases并传入bases参数。
  • 接下来,在使用metaclass.__prepare__()的返回值作为类属性的基本命名空间(或者在Python2上只使用普通字典)之后,Python调用metaclass.__new__()来创建实际的类。这再次作为(temporary_class,)元组传递给this_bases,但是上面的代码忽略了这一点,而是使用bases,调用meta(name, bases, d)来创建新的派生类。

因此,使用with_metaclass()将为您提供一个没有附加基类的新类对象。

代码语言:javascript
复制
>>> class FooMeta(type): pass
...
>>> with_metaclass(FooMeta)  # returns a temporary_class object
<class '__main__.temporary_class'>
>>> type(with_metaclass(FooMeta))  # which has a custom metaclass
<class '__main__.metaclass'>
>>> class Foo(with_metaclass(FooMeta)): pass
...
>>> Foo.__mro__  # no extra base classes
(<class '__main__.Foo'>, <type 'object'>)
>>> type(Foo) # correct metaclass
<class '__main__.FooMeta'>
票数 88
EN

Stack Overflow用户

发布于 2016-05-26 01:27:02

UPDATE:从那时起,six.with_metaclass()函数就用装饰器变体(即@six.add_metaclass() )进行了修补。此更新修复了一些与基本对象相关的mro问题。新的装潢师将按以下方式适用:

代码语言:javascript
复制
import six

@six.add_metaclass(Meta)
class MyClass(Base):
    pass

这是补丁注意事项下面是一个类似的,详细的例子和解释。用于使用装饰器替代方案。

票数 28
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18513821

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档