こんにちはStackoverflowのコミュニティうわーはsix.with_metaclass()の仕事をしていますか?
私はDjango(とWagtailのストリームフィールド)がボンネットの下でどのように動作するかを理解しようとしています。それをやって、メタクラスについて学び、原則を扱うと信じています。つまり、ちょうどSIXがwith_metaclass関数をどのように実行するかは、まだ私にとってはあまりあいまいです。ここでは具体的な質問が続いコードです:
models.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
six.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',(), {})
QUESTION
(1)の説明は、我々が実際のメタクラスで自身を置き換える一時ダミーメタクラスを生成することを示唆しています。 (2)これはどのように機能しますか? (3)with_metaclass関数を使ってメタクラス生成をどのように順序付けますか? (4)そして、どこのBaseStreamBlockが入りますか?
[2]我々は[で定義されたクラス メタクラスをインスタンス化して[2] return type.__new__(metaclass, 'temporary_class',(), {})
:
私を混乱させる部分があるが、我々は
[1] class metaclass(meta):
を定義するだけ経由して、それを呼び出すことです1]。このクラスのインスタンスには、型としてDeclarativeSubBlockMetaclassが含まれています。'temporary_class'は、ベースまたは属性のない名前です。
[1]では、実際のメタクラス作業を行っているように見えるメタクラスクラスを定義しています。ここでは、基底と名前に基づいて型DeclarativeSubBlockMetaclass(メタとして渡される)型のクラスを生成するクラスジェネレータを開発します。
しかし、にのみ呼び出しは、[1] [2]私たちがやっているように見えるすべてが任意の塩基または属性なしタイプDeclarativeSubBlockMetaclassの「temporary_class」をインスタンス化することですから来ているので。
説明(1)で説明したように、この一時的なダミーメタクラスを実際のメタクラスに置き換えるにはどうすればよいですか?
私はこの6つのドキュメントを調べようとしましたが、私の混乱を解消するものは見つかりませんでした。
アドバイスをいただければ幸いです。
はJUSTコンテキストの とてもZ
をありがとう:
私は上記six.with_metaclassコールで使用される2つのクラスのためのコードが含ま:
DeclarativeSubBlocksMetaclass
を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()
6つのコードよりも答えを理解するのに時間がかかりました。うん、それは難しいですが、あなたはそれの核心を得ます:作成される一時的なメタクラスは決して実際にはインスタンス化されません:その '__new__'メソッドは代わりに元のメタクラスをインスタンス化します。 – jsbueno