命名元组的子类化集合
Subclassing collections namedtuple
Python 的 namedtuple 作为轻量级、不可变数据非常有用 class。我喜欢将它们用于簿记参数而不是字典。当需要更多功能时,例如简单的文档字符串或默认值,您可以轻松地将 namedtuple 重构为 class。但是,我已经看到 classes 继承自 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__
(保持命名元组的轻量级特性)。
是否有更好的推荐轻量级数据class来记录参数?注意我使用的是 Python 2.7.
新更新:
在 python 3.6+ 中,您可以使用新的类型语法并创建 typing.NamedTuple
。新语法支持所有常用的 python class 创建功能(文档字符串、多重继承、默认参数、方法等从 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
这个版本创建的class个对象大部分相当于原来的collections.namedtuple
,except for a few details.
您还可以使用与旧命名元组相同的语法:
Pokemon = typing.NamedTuple('Pokemon', [('name', str), ('type', str), ('level', int)])
原答案
简答:no, unless you are using Python < 3.5
P3 docs 似乎非常清楚地暗示除非您需要添加计算字段(即描述符),否则 subclassing namedtuple
不被视为规范方法。这是因为您可以直接更新文档字符串(从 3.5 开始它们现在是可写的!)。
Subclassing is not useful for adding new, stored fields. Instead, simply create a new named tuple type from the _fields
attribute...
Docstrings can be customized by making direct assignments to the __doc__
fields...
更新:
在 Python 的最新版本中,轻量级数据 classes 现在还有一些其他令人信服的可能性。
一个是types.SimpleNamespace
(Python 3.3 and later)。它的结构不像 namedtuple
,但结构并不总是必需的。
关于 SimpleNamespace
需要注意的一件事:默认情况下,在实例化 class 时需要明确指定字段名称。不过,这可以很容易地解决,只需调用 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 - is dataclasses.dataclass
(see also PEP 557):
from dataclasses import dataclass
@dataclass
class Pokemon:
__slots__ = ("name", "type", "level")
name: str # What do you call your Pokemon?
type: str # grass, rock, electric, etc.
level: int = 0 # Experience level [0, 100]
请注意,这两个建议在默认情况下都是可变的,__slots__
对任何一个都不是必需的。
Python 的 namedtuple 作为轻量级、不可变数据非常有用 class。我喜欢将它们用于簿记参数而不是字典。当需要更多功能时,例如简单的文档字符串或默认值,您可以轻松地将 namedtuple 重构为 class。但是,我已经看到 classes 继承自 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__
(保持命名元组的轻量级特性)。
是否有更好的推荐轻量级数据class来记录参数?注意我使用的是 Python 2.7.
新更新:
在 python 3.6+ 中,您可以使用新的类型语法并创建 typing.NamedTuple
。新语法支持所有常用的 python class 创建功能(文档字符串、多重继承、默认参数、方法等从 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
这个版本创建的class个对象大部分相当于原来的collections.namedtuple
,except for a few details.
您还可以使用与旧命名元组相同的语法:
Pokemon = typing.NamedTuple('Pokemon', [('name', str), ('type', str), ('level', int)])
原答案
简答:no, unless you are using Python < 3.5
P3 docs 似乎非常清楚地暗示除非您需要添加计算字段(即描述符),否则 subclassing namedtuple
不被视为规范方法。这是因为您可以直接更新文档字符串(从 3.5 开始它们现在是可写的!)。
Subclassing is not useful for adding new, stored fields. Instead, simply create a new named tuple type from the
_fields
attribute...Docstrings can be customized by making direct assignments to the
__doc__
fields...
更新:
在 Python 的最新版本中,轻量级数据 classes 现在还有一些其他令人信服的可能性。
一个是types.SimpleNamespace
(Python 3.3 and later)。它的结构不像 namedtuple
,但结构并不总是必需的。
关于 SimpleNamespace
需要注意的一件事:默认情况下,在实例化 class 时需要明确指定字段名称。不过,这可以很容易地解决,只需调用 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 - is dataclasses.dataclass
(see also PEP 557):
from dataclasses import dataclass
@dataclass
class Pokemon:
__slots__ = ("name", "type", "level")
name: str # What do you call your Pokemon?
type: str # grass, rock, electric, etc.
level: int = 0 # Experience level [0, 100]
请注意,这两个建议在默认情况下都是可变的,__slots__
对任何一个都不是必需的。