子类化集合namedtuple

问题描述 投票:15回答:1

Python的namedtuple作为轻量级,不变的数据类非常有用。我喜欢将它们用于簿记参数,而不是字典。如果需要更多功能,例如简单的文档字符串或默认值,则可以轻松地将namedtuple重构为类。但是,我看到了从namedtuple继承的类。他们获得了什么功能,而失去了什么性能?例如,我将其实现为

from collections import namedtuple

class Pokemon(namedtuple('Pokemon', 'name type level')):
    """
    Attributes
    ----------
    name : str
        What do you call your Pokemon?
    type : str
        grass, rock, electric, etc.
    level : int
        Experience level [0, 100]
    """
     __slots__ = ()

仅出于能够清晰地记录attrs的目的,并且__slots__用于防止创建__dict__(保持命名元组的轻量性质)。

是否有更好的建议,建议使用轻量级数据类来记录参数?注意我正在使用Python 2.7。

python namedtuple
1个回答
20
投票

NEW UPDATE:

在python 3.6+中,您可以使用新类型的语法并创建一个typing.NamedTuple。新语法支持所有常规的python类创建功能(从3.6.1版本开始提供文档字符串,多重继承,默认参数,方法等):

import typing

class Pokemon(MyMixin, typing.NamedTuple):
    """
    Attributes
    ----------
    name : str
        What do you call your Pokemon?
    type : str
        grass, rock, electric, etc.
    level : int
        Experience level [0, 100]
    """
    name: str
    type: str
    level: int = 0 # 3.6.1 required for default args

    def method(self):
        # method work

此版本创建的类对象主要等同于原始的collections.namedtupleexcept for a few details

您还可以使用与旧命名元组相同的语法:

Pokemon = typing.NamedTuple('Pokemon', [('name', str), ('type', str), ('level', int)])

原始答案


简短回答:no, unless you are using Python < 3.5

P3 docs似乎很清楚地暗示,除非您需要添加计算字段(即描述符),否则不将子类namedtuple视为规范方法。这是因为您可以直接更新文档字符串(它们从3.5开始就可以写了!)。

子类化对于添加新的存储字段没有用。相反,只需从_fields属性创建一个新的命名元组类型...

可以通过直接分配__doc__字段来定制文档字符串...

更新:

在最新版本的Python中,轻量级数据类现在还有其他两种引人入胜的可能性。

一个是types.SimpleNamespace (Python 3.3 and later)。它的结构不像types.SimpleNamespace,但结构并不总是必需的。

关于namedtuple的注意事项:默认情况下,在实例化类时需要显式指定字段名称。不过,可以通过调用SimpleNamespace

轻松解决此问题。
super().__init__

另一个有趣的选项-from types import SimpleNamespace class Pokemon(SimpleNamespace): """ Attributes ---------- name : str What do you call your Pokemon? type : str grass, rock, electric, etc. level : int Experience level [0, 100] """ __slots__ = ("name", "type", "level") # note that use of __init__ is optional def __init__(self, name, type, level): super().__init__(name=name, type=type, level=level) -是which is available as of Python 3.7(另请参见dataclasses.dataclass):

dataclasses.dataclass

请注意,这两个建议在默认情况下都是可变的,并且其中一个都不要求PEP 557

© www.soinside.com 2019 - 2024. All rights reserved.