首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >哇,six.with_metaclass()有用吗?

哇,six.with_metaclass()有用吗?
EN

Stack Overflow用户
提问于 2017-03-16 04:26:59
回答 1查看 1.8K关注 0票数 3

嗨Stackoverflow社区

我一直在试图了解Django (和Wagtail的流场)是如何在引擎盖下工作的。为此,我学习了元类,并相信掌握了这一原则。尽管如此,对于我来说,6到底是如何执行with_metaclass函数仍然有点模糊。下面是代码后面的一个具体问题:

models.py

代码语言:javascript
复制
class BlogPage(Page):
    blogElement = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.TextBlock()),
        ('picture', ImageChooserBlock()),
    ], default=[])

车芯> fields.py

代码语言:javascript
复制
class StreamField(models.Field):
    def __init__(self, block_types, **kwargs):
        if isinstance(block_types, Block):
            self.stream_block = block_types
        elif isinstance(block_types, type):
            self.stream_block = block_types()
        else:
            self.stream_block = StreamBlock(block_types)
        super(StreamField, self).__init__(**kwargs)

车芯>区块> stream_block.py

代码语言:javascript
复制
class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):
    pass

six.py

代码语言: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(meta):

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

问题

(1)描述表明,我们生成一个临时的虚拟元类,它用实际的元类替换自己。(2)这是如何工作的?(3)如何通过with_metaclass函数对元类生成进行排序?(4)以及doesBaseStreamBlock是如何产生的?

让我困惑的是我们定义了

代码语言:javascript
复制
[1] class metaclass(meta):

但只能通过:

代码语言:javascript
复制
[2] return type.__new__(metaclass, 'temporary_class', (), {})

在2中,我们实例化了我们在1中定义的类元类。这个类的实例包含DeclarativeSubBlockMetaclass作为类型,'temporary_class‘作为名称,没有基或属性。

在1中,我们定义了元类,它似乎在执行实际的元类工作。在这里,我们开发了一个类生成器,它根据基和名称生成DeclarativeSubBlockMetaclass类型的类(作为元传入)。

但是,由于对1的唯一调用来自2,我们似乎所做的就是实例化DeclarativeSubBlockMetaclass类型的‘DeclarativeSubBlockMetaclass’,而没有任何基或属性。

如何将这个临时虚拟元类替换为描述(1)中描述的实际元类?

为此,我试着查阅六人的文档,但找不到任何能解决我困惑的东西。

如有任何建议,将不胜感激。

非常感谢Z

仅用于上下文:

我包括了上面six.with_metaclass调用中使用的两个类的代码:

DeclarativeSubBlocksMetaclass

代码语言:javascript
复制
class DeclarativeSubBlocksMetaclass(BaseBlock):
    """
    Metaclass that collects sub-blocks declared on the base classes.
    (cheerfully stolen from      https://github.com/django/django/blob/master/django/forms/forms.py)
    """
    def __new__(mcs, name, bases, attrs):
        # Collect sub-blocks declared on the current class.
        # These are available on the class as `declared_blocks`
        current_blocks = []
        for key, value in list(attrs.items()):
            if isinstance(value, Block):
                current_blocks.append((key, value))
                value.set_name(key)
                attrs.pop(key)
        current_blocks.sort(key=lambda x: x[1].creation_counter)
        attrs['declared_blocks'] = collections.OrderedDict(current_blocks)

        new_class = (super(DeclarativeSubBlocksMetaclass, mcs).__new__(mcs, name, bases, attrs))

        # Walk through the MRO, collecting all inherited sub-blocks, to make
        # the combined `base_blocks`.
        base_blocks = collections.OrderedDict()
        for base in reversed(new_class.__mro__):
            # Collect sub-blocks from base class.
            if hasattr(base, 'declared_blocks'):
                base_blocks.update(base.declared_blocks)

            # Field shadowing.
            for attr, value in base.__dict__.items():
                if value is None and attr in base_blocks:
                    base_blocks.pop(attr)
        new_class.base_blocks = base_blocks

        return new_class

BaseStreamBlock

代码语言:javascript
复制
class BaseStreamBlock(Block):

    def __init__(self, local_blocks=None, **kwargs):
        self._constructor_kwargs = kwargs

        super(BaseStreamBlock, self).__init__(**kwargs)

        # create a local (shallow) copy of base_blocks so that it can be supplemented by local_blocks
        self.child_blocks = self.base_blocks.copy()
        if local_blocks:
            for name, block in local_blocks:
                block.set_name(name)
                self.child_blocks[name] = block

        self.dependencies = self.child_blocks.values()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-16 09:02:48

好吧-我想我想明白了。问题的症结在于

代码语言:javascript
复制
return meta(name, bases, d)

的with_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(meta):

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

下面是我认为它在sudo代码中的工作方式:

代码语言:javascript
复制
(1) with_metaclass takes <<DeclarativeSubBlocksMetaclass>> as meta; and <<BaseStreamBlock>> as bases
(2) class metaclass(meta) --> the class metaclass is then created extending <<DeclarativeSubBlockMetaclass>> as the class type
(3) def __new__(cls, name, this_bases, d): Only rarely will you have to worry about __new__. Usually, you'll just define __init__ and let the default __new__ pass the constructor arguments to it. __new__ takes care of creating the object and assigning memory space to it. This __new__ method is a class method that gets called when you create an instance of the class and it gets called before __init__.  Its main job is to allocate the memory that the object that you are creating uses. It can also be used to set up any aspect of the instance of the class that is immutable Because classes are kind of immutable (they cannot be changed), overloading __new_ is the best place to overload how they are created.
(4) return meta(name, bases, d) --> the class definition ends with returning a <<DeclarativeSubBlockMetaclass>> with the arguments (name, base = BaseStreamBlock, d)

NOTE: We only define the class in 1 - 3; we are not instantiating it this comes below

(5) return type.__new__(metaclass, 'temporary_class', (), {}) --> Here we are using the classic metaclass syntax. This syntax usually looks like this: return type.__new__(cls, name, bases, attrs). We are using this syntax to instantiate the metaclass we defined in (3) and (4). One might think that it is confusing that temporary_class', (), {} are passed on as the 'name', 'bases', and 'attrs' arguments. BUT...
(6) ... when the instantiation arrives at return meta(name,bases,d) we notice that meta doesn't take 'this_bases' as an argument but 'bases'. It derives this value from the arguments which were passed to (1) with_metaclasses. As such bases in this instance == <<BaseStreamBlock>>
(7) Therefore, when we instantiate type.__new__(metaclass, 'temporary_class', (), {}) we essentially execute <<DeclarativeSubBlocksMetaClass>>('temporary_class', <<BaseStreamBlock>>, {})

(7)中所解释的步骤就是所述的解释。从本质上说,6所做的就是通过规定的步骤创建一个虚拟元类,它称为temporary_class。因为DeclarativeSubBlocksMetaClass也是元类,所以它使用BaseStreamBlock基生成一个新类。

我希望这是合理的。

Z

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

https://stackoverflow.com/questions/42825295

复制
相关文章

相似问题

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