Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/google-maps/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 哇,六个元类()有用吗?_Python_Django_Metaclass_Wagtail_Six - Fatal编程技术网

Python 哇,六个元类()有用吗?

Python 哇,六个元类()有用吗?,python,django,metaclass,wagtail,six,Python,Django,Metaclass,Wagtail,Six,Hi Stackoverflow社区 我一直试图了解Django(和Wagtail的流场)是如何在引擎盖下工作的。通过这样做,我学习了元类,并相信自己掌握了这个原理。也就是说,SIX如何执行with_元类函数对我来说仍然有点模糊。下面是代码,后面是一个具体问题: 型号.py class BlogPage(Page): blogElement = StreamField([ ('heading', blocks.CharBlock(classname="full title

Hi Stackoverflow社区

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

型号.py

class BlogPage(Page):
    blogElement = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.TextBlock()),
        ('picture', ImageChooserBlock()),
    ], default=[])
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)
class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):
    pass
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', (), {})
wagtailcore>fields.py

class BlogPage(Page):
    blogElement = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.TextBlock()),
        ('picture', ImageChooserBlock()),
    ], default=[])
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)
class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):
    pass
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', (), {})
wagtailcore>blocks>stream_block.py

class BlogPage(Page):
    blogElement = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.TextBlock()),
        ('picture', ImageChooserBlock()),
    ], default=[])
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)
class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):
    pass
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', (), {})
six.py

class BlogPage(Page):
    blogElement = StreamField([
        ('heading', blocks.CharBlock(classname="full title")),
        ('paragraph', blocks.TextBlock()),
        ('picture', ImageChooserBlock()),
    ], default=[])
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)
class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBlock)):
    pass
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类型的“临时_类”,而不带任何基或属性

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

我试着查阅六人的文档,但找不到任何可以解决我困惑的方法

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

多谢各位 Z

仅用于上下文:

我包含了上述six.with_元类调用中使用的两个类的代码:

声明性SubblocksMetaClass

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

好吧,我想我已经明白了。问题的关键在于

return meta(name, bases, d)
with_元类函数的:

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代码中的工作方式:

(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>>, {})
(1)带_元类作为元;作为基础
(2) 类元类(meta)->然后创建类元类并扩展为类类型
(3) 定义新的(cls,name,this_base,d):你很少需要担心新的。通常,您只需定义uuu init uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu__new_u;负责创建对象并为其分配内存空间。这个_new _方法是一个类方法,在创建类的实例时调用它,并在_init _之前调用它。它的主要任务是分配正在创建的对象所使用的内存。它还可以用于设置类实例的任何方面,这些方面是不可变的,因为类是不可变的(它们不能更改),重载uu new_u是重载它们的创建方式的最佳位置。
(4) return meta(name,base,d)->类定义以返回一个带有参数(name,base=BaseStreamBlock,d)的
注:我们只在1-3中定义类;我们不是在实例化它,下面就是
(5) 返回类型.uuu new_uuu(元类,'temporary_class',(),{})-->这里我们使用的是经典元类语法。此语法通常如下所示:返回类型.\uuuuu new\uuuuuu(cls、name、base、attrs)。我们使用这个语法来实例化(3)和(4)中定义的元类。有人可能会认为,将临时_类'、()、{}作为'name'、'base'和'attrs'参数传递是令人困惑的。但是
(6) ... 当实例化到达return meta(name,base,d)时,我们注意到meta没有将'this_base'作为参数,而是将'base'作为参数。它从使用_元类传递给(1)的参数中派生此值。因此,在本实例中的基==
(7) 因此,当我们实例化type.uu new_uu(元类,'temporary_class',(),{})时,我们基本上执行('temporary_class',{})
(7)中解释的步骤就是解释中提到的步骤。基本上,SIX所做的是通过规定的步骤创建一个虚拟元类,它称之为临时类。由于DeclarativeSubBlocksMetaClass也是一个元类,因此它使用BaseStreamBlock基生成一个新类

我希望这是有道理的


Z

我花了比six的密码更多的时间来理解你的答案。是的,这很棘手,但你得到了它的核心:问题是所创建的临时元类从来没有被实际实例化过:它的
\uuuuuu new\uuuuu
方法实例化了原始元类。