嗨 Stackoverflow 社区
我一直试图了解 Django(和 Wagtail 的 Stream-field)如何在幕后工作。这样做我了解了元类,并相信掌握了这一原则。也就是说,SIX 如何执行 with_metaclass 函数对我来说仍然有点模糊。这是代码,后面是一个特定的问题:
模型.py
class BlogPage(Page):
blogElement = StreamField([
('heading', blocks.CharBlock(classname="full title")),
('paragraph', blocks.TextBlock()),
('picture', ImageChooserBlock()),
], default=[])
wagtailcore > fields.py
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)
wagtailcore > 块 > stream_block.py
class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):
pass
六.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_metaclass 函数对元类生成进行排序?(4) BaseStreamBlock 是从哪里来的?
让我困惑的部分是我们定义
[1] class metaclass(meta):
但只能通过以下方式调用它:
[2] return type.__new__(metaclass, 'temporary_class', (), {})
在 [2] 中,我们实例化了在 [1] 中定义的类元类。此类的实例包含 DeclarativeSubBlockMetaclass 作为类型,并包含“temporary_class”作为名称,没有基础或属性。
在 [1] 中,我们定义了看起来正在执行实际元类工作的元类类。在这里,我们开发了一个类生成器,它根据基数和名称生成 DeclarativeSubBlockMetaclass 类型的类(作为元传递)。
但是,由于对 [1] 的唯一调用来自 [2],因此我们似乎正在做的只是实例化没有任何基础或属性的DeclarativeSubBlockMetaclass类型的“temporary_class”。
我们如何用描述(1)中描述的实际元类替换这个临时虚拟元类?
我试图为此查阅六人的文档,但找不到任何可以解决我困惑的东西。
任何建议将不胜感激。
非常感谢Z
仅用于上下文:
我在上面的 Six.with_metaclass 调用中包含了两个类的代码:
声明性子块元类
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
基本流块
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()