Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.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 为什么';namedtuple模块是否使用元类来创建nt类对象?_Python_Metaclass_Python Internals_Namedtuple - Fatal编程技术网

Python 为什么';namedtuple模块是否使用元类来创建nt类对象?

Python 为什么';namedtuple模块是否使用元类来创建nt类对象?,python,metaclass,python-internals,namedtuple,Python,Metaclass,Python Internals,Namedtuple,几周前,我花了一些时间调查这件事。该模块使用一个工厂函数,将动态数据(新的namedtuple类的名称和类属性名称)填充到一个非常大的字符串中。然后执行exec,以字符串(表示代码)作为参数,并返回新类 有人知道为什么会这样做,当有一个特定的工具可以用于这类事情时,即元类?我自己没有尝试过这么做,但似乎namedtuple模块中发生的所有事情都可以使用namedtuple元类轻松完成,如下所示: class namedtuple(type): 等等。中有一些提示。作者提出了一种创建命名元组的新

几周前,我花了一些时间调查这件事。该模块使用一个工厂函数,将动态数据(新的
namedtuple
类的名称和类属性名称)填充到一个非常大的字符串中。然后执行
exec
,以字符串(表示代码)作为参数,并返回新类

有人知道为什么会这样做,当有一个特定的工具可以用于这类事情时,即元类?我自己没有尝试过这么做,但似乎
namedtuple
模块中发生的所有事情都可以使用
namedtuple
元类轻松完成,如下所示:

class namedtuple(type):

等等。

中有一些提示。作者提出了一种创建命名元组的新方法,但遭到拒绝,并给出以下评论:

原始版本的好处似乎是速度更快, 由于硬编码的关键方法。 -安托万·皮特罗

使用exec并没有什么不好的地方。早期版本使用其他版本 方法和它们被证明是不必要的复杂,并且具有意想不到的效果 问题。命名元组的一个关键特性是它们完全相同 相当于手写的课堂雷蒙德·赫廷格

此外,以下是以下部分的说明:

。。。配方已经发展到目前的exec风格,我们可以从中获得所有 免费使用Python的高速内置参数检查。新的 构建和执行模板的样式使 __与此配方的以前版本相比,repr___;的功能更快、更干净

如果您正在寻找一些替代实现:

  • Jan Kaliszewski的食谱

  • 亚伦·艾利斯(见他的)


作为旁注:我最常看到的反对使用
exec
的另一个理由是,出于安全原因,一些地方(阅读公司)禁用了它

除了高级的
Enum
NamedConstant
,*还有基于
元类的
NamedTuple



*
aenum
由和backport的作者编写。

这里是另一种方法

""" Subclass of tuple with named fields """
from operator import itemgetter
from inspect import signature

class MetaTuple(type):
    """ metaclass for NamedTuple """

    def __new__(mcs, name, bases, namespace):
        cls = type.__new__(mcs, name, bases, namespace)
        names = signature(cls._signature).parameters.keys()
        for i, key in enumerate(names):
            setattr(cls, key, property(itemgetter(i)))
        return cls

class NamedTuple(tuple, metaclass=MetaTuple):
    """ Subclass of tuple with named fields """

    @staticmethod
    def _signature():
        " Override in subclass "

    def __new__(cls, *args):
        new = super().__new__(cls, *args)
        if len(new) == len(signature(cls._signature).parameters):
            return new
        return new._signature(*new)

if __name__ == '__main__':
    class Point(NamedTuple):
        " Simple test "
        @staticmethod
        def _signature(x, y, z): # pylint: disable=arguments-differ
            " Three coordinates "
    print(Point((1, 2, 4)))
如果说这种方法有什么优点的话,那就是简单。如果不使用
命名为tuple.\uuuu new\uuuuu
,它将更简单,但仅用于强制元素计数。如果没有这一点,它很高兴地允许额外的匿名元素超过命名元素,省略元素的主要效果是在按名称访问被省略的元素时,
索引器
(只需少量工作,就可以转换为
AttributeError
)。元素计数不正确的错误消息有点奇怪,但它可以理解这一点。我不希望它与Python2一起工作


还有进一步复杂化的空间,例如
\uuuu repr\uuu
方法。我不知道性能与其他实现相比如何(缓存签名长度可能会有所帮助),但与本机
namedtuple
实现相比,我更喜欢调用约定。

还有一个原因,其他答案都没有提到*

一个类只能有一个元类。原因之一是元类充当创建类的工厂。随意把工厂混在一起是不可能的。您必须创建一个知道如何按正确顺序调用多个工厂的“组合工厂”,或者创建一个知道“父工厂”并正确使用它的“子工厂”

如果
namedtuple
使用了自己的元类,则涉及任何其他元类的继承都会中断:

>>M1类(类型):。。。
...
>>>M2类(类型):。。。
...
>>>类C1(元类=M1):。。。
...
>>>C2类(元类=M2):。。。
...
>>>C类(C1、C2):。。。
...
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:元类冲突:派生类的元类必须是其所有基元类的(非严格)子类
相反,如果您想拥有自己的元类并从
namedtuple
类继承,则必须使用某种所谓的
namedtuple\u meta
元类来实现这一点:

从namedtuple导入namedtuple_meta#假装存在
类MyMeta(类型):。。。
类MyMetaWithNT(名称为tuple\u meta,MyMeta):。。。
类C(元类=MyMetaWithNT):。。。
..或者直接从
namedtuple\u meta
继承自定义元类:

class MyMeta(namedtuple_meta): ...

class C(metaclass=MyMeta): ...
起初这看起来很容易,但是编写自己的mataclass并很好地处理某些(复杂的)nt元类可能很快就会出现问题。这种限制可能不会经常出现,但经常会阻碍
namedtuple
的使用。因此,让所有
命名的tuple
类都是
类型
类型,并消除自定义元类的复杂性,这无疑是一个优势


*Raymond Hettinger的的确暗示了这一点:

命名元组的一个关键特性是它们与手写类完全等效


嗯,这当然回答了一般的问题,但我很想知道这些意想不到的问题在哪里。根据元类本身的不同,问题可能在于元类本身,在这种情况下,元类可能需要修复。2.5年后对该评论的回复似乎也提出了一些人们可能有的真实问题。无论如何,谢谢你的链接,那里有很多信息。我从来没有真正买过这个。在我看来,答案总是“因为雷蒙德·赫廷格(Raymond Hettinger)可以使用奇怪的黑客技术”。作为一个正在学习的人,这真的让我停下来在标准库中看到类似的东西。我曾认为标准库将是检验“好”的好地方