哇是的六、用元类()工作?

2024-09-30 04:38:11 发布

您现在位置:Python中文网/ 问答频道 /正文

Hi Stackoverflow社区

我一直在试图理解Django(和Wagtail的溪流场)是如何在引擎盖下工作的。这样做,我学会了元类,并相信掌握了原理。也就是说,对于我来说,SIX是如何执行with_元类函数的仍然有点模糊。下面是代码后面跟着一个特定的问题:

模型.py

class BlogPage(Page):
    blogElement = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.TextBlock()),
        ('picture', ImageChooserBlock()),
    ], default=[])

wagtailcore>;字段.py

^{pr2}$

wagtailcore>;街区>;溪流_块.py

class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):
    pass

6.py

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_元类函数对元类生成进行排序? (4) 那么BaseStreamBlock从何而来?在

让我困惑的是我们定义

[1] class metaclass(meta):

但只能通过以下方式调用:

[2] return type.__new__(metaclass, 'temporary_class', (), {})

在[2]中,我们实例化了我们在[1]中定义的类元类。该类的实例包含DeclarativeSubBlockMetaclass作为类型,而“temporary_class”作为名称,没有基或属性。在

在[1]中,我们定义了元类类,它似乎在做实际的元类工作。这里我们开发了一个类生成器,它基于基和名称生成DeclarativeSubBlockMetaclass(作为meta传递)类型的类。在

但是,由于对[1]的唯一调用来自[2],所以我们似乎要做的就是实例化类型为DeclarativeSubBlockMetaclass的“temporary\u class”,而没有任何基或属性。在

我们如何用描述(1)中描述的实际元类替换这个临时的伪元类?在

我试着去咨询六号医院的医生,但是没有找到任何能解决我困惑的东西。在

任何建议都将不胜感激。在

非常感谢 Z

仅供参考:

我包括了在六、用元类以上电话:

声明子块类

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

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()

Tags: thenamepyselfnewbasevaluewith
1条回答
网友
1楼 · 发布于 2024-09-30 04:38:11

好吧-我想我已经想好了。问题的关键在于

return meta(name, bases, d)

with_元类函数的:

^{pr2}$

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

(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)中解释的步骤就是解释所说的。实际上,SIX所做的就是按照规定的步骤创建一个虚拟元类,它称之为临时的_类。由于DeclarativeSubBlocksMetaClass也是一个元类,因此它使用BaseStreamBlock基来生成一个新类。在

我希望这有道理。在

Z

相关问题 更多 >

    热门问题