问题:Python中的“命名元组”是什么?

阅读Python 3.1中更改后,我发现了一些意外……

sys.version_info元组现在是一个命名的元组

我以前从未听说过命名元组,并且我认为元素可以用数字(如在元组和列表中)或键(如字典中)索引。我从未想到它们可以同时被索引。

因此,我的问题是:

  • 什么叫元组?
  • 如何使用它们?
  • 为什么/何时应该使用命名元组而不是普通元组?
  • 为什么/何时应该使用普通元组而不是命名元组?
  • 是否有某种“命名列表”(命名元组的可变版本)?

Reading the changes in Python 3.1, I found something… unexpected:

The sys.version_info tuple is now a named tuple:

I never heard about named tuples before, and I thought elements could either be indexed by numbers (like in tuples and lists) or by keys (like in dicts). I never expected they could be indexed both ways.

Thus, my questions are:

  • What are named tuples?
  • How to use them?
  • Why/when should I use named tuples instead of normal tuples?
  • Why/when should I use normal tuples instead of named tuples?
  • Is there any kind of “named list” (a mutable version of the named tuple)?

回答 0

命名元组基本上是易于创建的轻量级对象类型。可以使用类对象变量解引用或标准元组语法来引用已命名的元组实例。struct除了它们是不可变的,它们可以类似于或其他常见的记录类型使用。它们是在Python 2.6和Python 3.0中添加的,尽管在Python 2.4中实现秘诀

例如,通常将一个点表示为元组(x, y)。这导致如下代码:

pt1 = (1.0, 5.0)
pt2 = (2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)

使用命名元组,它变得更具可读性:

from collections import namedtuple
Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)

但是,命名元组仍然与普通元组向后兼容,因此以下内容仍然有效:

Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
# use index referencing
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)
 # use tuple unpacking
x1, y1 = pt1

因此,在您认为对象表示法将使您的代码更具pythonic性且更易于阅读的任何地方都应使用命名元组而不是元组。我个人已经开始使用它们来表示非常简单的值类型,尤其是在将它们作为参数传递给函数时。它使函数更具可读性,而看不到元组包装的上下文。

此外,您还可以替换没有功能的普通不可变,仅将它们替换为字段。您甚至可以将命名的元组类型用作基类:

class Point(namedtuple('Point', 'x y')):
    [...]

但是,与元组一样,命名元组中的属性是不可变的:

>>> Point = namedtuple('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
AttributeError: can't set attribute

如果要能够更改值,则需要另一种类型。对于可变记录类型,有一个方便的用法,可让您为属性设置新值。

>>> from rcdtype import *
>>> Point = recordtype('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
>>> print(pt1[0])
    2.0

但是,我不知道有任何形式的“命名列表”可让您添加新字段。在这种情况下,您可能只想使用字典。命名的元组可以转换为字典,使用pt1._asdict()该返回{'x': 1.0, 'y': 5.0}可以使用所有常用的字典功能进行操作。

如前所述,您应该查看文档以获取构成这些示例的更多信息。

Named tuples are basically easy-to-create, lightweight object types. Named tuple instances can be referenced using object-like variable dereferencing or the standard tuple syntax. They can be used similarly to struct or other common record types, except that they are immutable. They were added in Python 2.6 and Python 3.0, although there is a recipe for implementation in Python 2.4.

For example, it is common to represent a point as a tuple (x, y). This leads to code like the following:

pt1 = (1.0, 5.0)
pt2 = (2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)

Using a named tuple it becomes more readable:

from collections import namedtuple
Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)

However, named tuples are still backwards compatible with normal tuples, so the following will still work:

Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
# use index referencing
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)
 # use tuple unpacking
x1, y1 = pt1

Thus, you should use named tuples instead of tuples anywhere you think object notation will make your code more pythonic and more easily readable. I personally have started using them to represent very simple value types, particularly when passing them as parameters to functions. It makes the functions more readable, without seeing the context of the tuple packing.

Furthermore, you can also replace ordinary immutable classes that have no functions, only fields with them. You can even use your named tuple types as base classes:

class Point(namedtuple('Point', 'x y')):
    [...]

However, as with tuples, attributes in named tuples are immutable:

>>> Point = namedtuple('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
AttributeError: can't set attribute

If you want to be able change the values, you need another type. There is a handy recipe for mutable recordtypes which allow you to set new values to attributes.

>>> from rcdtype import *
>>> Point = recordtype('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
>>> print(pt1[0])
    2.0

I am not aware of any form of “named list” that lets you add new fields, however. You may just want to use a dictionary in this situation. Named tuples can be converted to dictionaries using pt1._asdict() which returns {'x': 1.0, 'y': 5.0} and can be operated upon with all the usual dictionary functions.

As already noted, you should check the documentation for more information from which these examples were constructed.


回答 1

namedtuple是用于创建元组类的工厂函数。通过该类,我们可以创建可通过名称调用的元组。

import collections

#Create a namedtuple class with names "a" "b" "c"
Row = collections.namedtuple("Row", ["a", "b", "c"], verbose=False, rename=False)   

row = Row(a=1,b=2,c=3) #Make a namedtuple from the Row class we created

print row    #Prints: Row(a=1, b=2, c=3)
print row.a  #Prints: 1
print row[0] #Prints: 1

row = Row._make([2, 3, 4]) #Make a namedtuple from a list of values

print row   #Prints: Row(a=2, b=3, c=4)

namedtuple is a factory function for making a tuple class. With that class we can create tuples that are callable by name also.

import collections

#Create a namedtuple class with names "a" "b" "c"
Row = collections.namedtuple("Row", ["a", "b", "c"], verbose=False, rename=False)   

row = Row(a=1,b=2,c=3) #Make a namedtuple from the Row class we created

print row    #Prints: Row(a=1, b=2, c=3)
print row.a  #Prints: 1
print row[0] #Prints: 1

row = Row._make([2, 3, 4]) #Make a namedtuple from a list of values

print row   #Prints: Row(a=2, b=3, c=4)

回答 2

什么叫元组?

一个命名的元组是一个元组。

它完成了元组可以做的所有事情。

但这不仅仅是一个元组。

它是元组的特定子类,它是根据您的规范以编程方式创建的,具有命名字段和固定长度。

例如,这创建了一个元组的子类,除了具有固定的长度(在这种情况下为三个)之外,它还可以在使用元组的任何地方使用而不会中断。这称为Liskov替代性。

Python 3.6中的新功能,我们可以使用类定义typing.NamedTuple来创建namedtuple:

from typing import NamedTuple

class ANamedTuple(NamedTuple):
    """a docstring"""
    foo: int
    bar: str
    baz: list

上面与下面相同,除了上面还带有类型注释和文档字符串。以下在Python 2+中可用:

>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)

实例化它:

>>> ant = ANamedTuple(1, 'bar', [])

我们可以检查它并使用其属性:

>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']

更深入的解释

要了解命名元组,您首先需要知道什么是元组。元组本质上是一个不变的(不能在内存中就地更改)列表。

这是使用常规元组的方法:

>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'

您可以使用可迭代的拆包扩展元组:

>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'

命名元组是允许通过名称而不是索引访问其元素的元组!

您可以这样创建一个namedtuple:

>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])

您还可以使用名称以空格分隔的单个字符串,该API的可读性更高:

>>> Student = namedtuple('Student', 'first last grade')

如何使用它们?

您可以做元组可以做的所有事情(见上文),还可以执行以下操作:

>>> named_student_tuple = Student('Lisa', 'Simpson', 'A')
>>> named_student_tuple.first
'Lisa'
>>> named_student_tuple.last
'Simpson'
>>> named_student_tuple.grade
'A'
>>> named_student_tuple._asdict()
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> vars(named_student_tuple)
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> new_named_student_tuple = named_student_tuple._replace(first='Bart', grade='C')
>>> new_named_student_tuple
Student(first='Bart', last='Simpson', grade='C')

有评论者问:

在大型脚本或程序中,通常在哪里定义命名元组?

您创建的类型namedtuple基本上是可以用简单的速记创建的类。像上课一样对待他们。在模块级别上定义它们,以便pickle和其他用户可以找到它们。

在全局模块级别上的工作示例:

>>> from collections import namedtuple
>>> NT = namedtuple('NT', 'foo bar')
>>> nt = NT('foo', 'bar')
>>> import pickle
>>> pickle.loads(pickle.dumps(nt))
NT(foo='foo', bar='bar')

这证明了查找定义的失败:

>>> def foo():
...     LocalNT = namedtuple('LocalNT', 'foo bar')
...     return LocalNT('foo', 'bar')
... 
>>> pickle.loads(pickle.dumps(foo()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <class '__main__.LocalNT'>: attribute lookup LocalNT on __main__ failed

为什么/何时应该使用命名元组而不是普通元组?

在改进代码以使元组元素的语义在代码中表达时使用它们。

如果不使用数据属性不变且没有功能的对象,则可以使用它们代替对象。

您也可以将它们子类化以添加功能,例如

class Point(namedtuple('Point', 'x y')):
    """adding functionality to a named tuple"""
        __slots__ = ()
        @property
        def hypot(self):
            return (self.x ** 2 + self.y ** 2) ** 0.5
        def __str__(self):
            return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

为什么/何时应该使用普通元组而不是命名元组?

从使用命名元组切换到元组可能是一种回归。前期设计决策集中在使用元组时,是否值得使用额外代码带来的成本来提高可读性。

元组和元组之间没有使用额外的内存。

是否有某种“命名列表”(命名元组的可变版本)?

您正在寻找实现静态大小列表的所有功能的带槽对象,或者寻找像命名元组一样工作的子类列表(并以某种方式阻止列表大小的改变)。

现在是第一个的扩展示例,甚至可以用Liskov替代:

from collections import Sequence

class MutableTuple(Sequence): 
    """Abstract Base Class for objects that work like mutable
    namedtuples. Subclass and define your named fields with 
    __slots__ and away you go.
    """
    __slots__ = ()
    def __init__(self, *args):
        for slot, arg in zip(self.__slots__, args):
            setattr(self, slot, arg)
    def __repr__(self):
        return type(self).__name__ + repr(tuple(self))
    # more direct __iter__ than Sequence's
    def __iter__(self): 
        for name in self.__slots__:
            yield getattr(self, name)
    # Sequence requires __getitem__ & __len__:
    def __getitem__(self, index):
        return getattr(self, self.__slots__[index])
    def __len__(self):
        return len(self.__slots__)

要使用,只需继承并定义__slots__

class Student(MutableTuple):
    __slots__ = 'first', 'last', 'grade' # customize 


>>> student = Student('Lisa', 'Simpson', 'A')
>>> student
Student('Lisa', 'Simpson', 'A')
>>> first, last, grade = student
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
>>> student[0]
'Lisa'
>>> student[2]
'A'
>>> len(student)
3
>>> 'Lisa' in student
True
>>> 'Bart' in student
False
>>> student.first = 'Bart'
>>> for i in student: print(i)
... 
Bart
Simpson
A

What are named tuples?

A named tuple is a tuple.

It does everything a tuple can.

But it’s more than just a tuple.

It’s a specific subclass of a tuple that is programmatically created to your specification, with named fields and a fixed length.

This, for example, creates a subclass of tuple, and aside from being of fixed length (in this case, three), it can be used everywhere a tuple is used without breaking. This is known as Liskov substitutability.

New in Python 3.6, we can use a class definition with typing.NamedTuple to create a namedtuple:

from typing import NamedTuple

class ANamedTuple(NamedTuple):
    """a docstring"""
    foo: int
    bar: str
    baz: list

The above is the same as the below, except the above additionally has type annotations and a docstring. The below is available in Python 2+:

>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)

This instantiates it:

>>> ant = ANamedTuple(1, 'bar', [])

We can inspect it and use its attributes:

>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']

Deeper explanation

To understand named tuples, you first need to know what a tuple is. A tuple is essentially an immutable (can’t be changed in-place in memory) list.

Here’s how you might use a regular tuple:

>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'

You can expand a tuple with iterable unpacking:

>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'

Named tuples are tuples that allow their elements to be accessed by name instead of just index!

You make a namedtuple like this:

>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])

You can also use a single string with the names separated by spaces, a slightly more readable use of the API:

>>> Student = namedtuple('Student', 'first last grade')

How to use them?

You can do everything tuples can do (see above) as well as do the following:

>>> named_student_tuple = Student('Lisa', 'Simpson', 'A')
>>> named_student_tuple.first
'Lisa'
>>> named_student_tuple.last
'Simpson'
>>> named_student_tuple.grade
'A'
>>> named_student_tuple._asdict()
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> vars(named_student_tuple)
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> new_named_student_tuple = named_student_tuple._replace(first='Bart', grade='C')
>>> new_named_student_tuple
Student(first='Bart', last='Simpson', grade='C')

A commenter asked:

In a large script or programme, where does one usually define a named tuple?

The types you create with namedtuple are basically classes you can create with easy shorthand. Treat them like classes. Define them on the module level, so that pickle and other users can find them.

The working example, on the global module level:

>>> from collections import namedtuple
>>> NT = namedtuple('NT', 'foo bar')
>>> nt = NT('foo', 'bar')
>>> import pickle
>>> pickle.loads(pickle.dumps(nt))
NT(foo='foo', bar='bar')

And this demonstrates the failure to lookup the definition:

>>> def foo():
...     LocalNT = namedtuple('LocalNT', 'foo bar')
...     return LocalNT('foo', 'bar')
... 
>>> pickle.loads(pickle.dumps(foo()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <class '__main__.LocalNT'>: attribute lookup LocalNT on __main__ failed

Why/when should I use named tuples instead of normal tuples?

Use them when it improves your code to have the semantics of tuple elements expressed in your code.

You can use them instead of an object if you would otherwise use an object with unchanging data attributes and no functionality.

You can also subclass them to add functionality, for example:

class Point(namedtuple('Point', 'x y')):
    """adding functionality to a named tuple"""
        __slots__ = ()
        @property
        def hypot(self):
            return (self.x ** 2 + self.y ** 2) ** 0.5
        def __str__(self):
            return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

Why/when should I use normal tuples instead of named tuples?

It would probably be a regression to switch from using named tuples to tuples. The upfront design decision centers around whether the cost from the extra code involved is worth the improved readability when the tuple is used.

There is no extra memory used by named tuples versus tuples.

Is there any kind of “named list” (a mutable version of the named tuple)?

You’re looking for either a slotted object that implements all of the functionality of a statically sized list or a subclassed list that works like a named tuple (and that somehow blocks the list from changing in size.)

A now expanded, and perhaps even Liskov substitutable, example of the first:

from collections import Sequence

class MutableTuple(Sequence): 
    """Abstract Base Class for objects that work like mutable
    namedtuples. Subclass and define your named fields with 
    __slots__ and away you go.
    """
    __slots__ = ()
    def __init__(self, *args):
        for slot, arg in zip(self.__slots__, args):
            setattr(self, slot, arg)
    def __repr__(self):
        return type(self).__name__ + repr(tuple(self))
    # more direct __iter__ than Sequence's
    def __iter__(self): 
        for name in self.__slots__:
            yield getattr(self, name)
    # Sequence requires __getitem__ & __len__:
    def __getitem__(self, index):
        return getattr(self, self.__slots__[index])
    def __len__(self):
        return len(self.__slots__)

And to use, just subclass and define __slots__:

class Student(MutableTuple):
    __slots__ = 'first', 'last', 'grade' # customize 


>>> student = Student('Lisa', 'Simpson', 'A')
>>> student
Student('Lisa', 'Simpson', 'A')
>>> first, last, grade = student
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
>>> student[0]
'Lisa'
>>> student[2]
'A'
>>> len(student)
3
>>> 'Lisa' in student
True
>>> 'Bart' in student
False
>>> student.first = 'Bart'
>>> for i in student: print(i)
... 
Bart
Simpson
A

回答 3

namedtuple是一个很棒的功能,它们是数据的完美容器。当您必须“存储”数据时,可以使用元组或字典,例如:

user = dict(name="John", age=20)

要么:

user = ("John", 20)

字典方法是压倒性的,因为字典比元组易变且速度慢。另一方面,元组是不可变的且轻量级的,但是对于数据字段中的大量条目却缺乏可读性。

namedtuple是这两种方法的完美折衷,它们具有出色的可读性,轻巧性和不变性(而且它们是多态的!)。

namedtuples are a great feature, they are perfect container for data. When you have to “store” data you would use tuples or dictionaries, like:

user = dict(name="John", age=20)

or:

user = ("John", 20)

The dictionary approach is overwhelming, since dict are mutable and slower than tuples. On the other hand, the tuples are immutable and lightweight but lack readability for a great number of entries in the data fields.

namedtuples are the perfect compromise for the two approaches, the have great readability, lightweightness and immutability (plus they are polymorphic!).


回答 4

命名元组允许向后兼容与检查像这样的版本的代码

>>> sys.version_info[0:2]
(3, 1)

同时通过使用此语法使将来的代码更加明确

>>> sys.version_info.major
3
>>> sys.version_info.minor
1

named tuples allow backward compatibility with code that checks for the version like this

>>> sys.version_info[0:2]
(3, 1)

while allowing future code to be more explicit by using this syntax

>>> sys.version_info.major
3
>>> sys.version_info.minor
1

回答 5

元组

是清理代码并使代码更具可读性的最简单方法之一。它自我记录元组中发生的事情。Namedtuple实例不具有按实例字典,因此它们与常规元组的存储效率相同,这使它们比字典快。

from collections import namedtuple

Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])

 p = Color(170, 0.1, 0.6)
 if p.saturation >= 0.5:
     print "Whew, that is bright!"
 if p.luminosity >= 0.5:
     print "Wow, that is light"

如果不命名元组中的每个元素,它将显示为:

p = (170, 0.1, 0.6)
if p[1] >= 0.5:
    print "Whew, that is bright!"
if p[2]>= 0.5:
   print "Wow, that is light"

要理解第一个示例中发生的事情要困难得多。对于namedtuple,每个字段都有一个名称。您可以通过名称而不是位置或索引来访问它。代替p[1],我们可以称它为p.saturation。更容易理解。而且看起来更干净。

创建namedtuple的实例比创建字典要容易。

# dictionary
>>>p = dict(hue = 170, saturation = 0.1, luminosity = 0.6)
>>>p['hue']
170

#nametuple
>>>from collections import namedtuple
>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)
>>>p.hue
170

什么时候可以使用namedtuple

  1. 如前所述,namedtuple使理解元组更加容易。因此,如果您需要引用元组中的项目,那么将它们创建为namedtuples就很有意义。
  2. 除了比字典轻巧之外,namedtuple还保留了与字典不同的顺序。
  3. 如上例所示,创建namedtuple的实例比使用字典更简单。并且在命名元组中引用该项目看起来比字典更干净。p.hue而不是 p['hue']

语法

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
  • namedtuple在集合库中。
  • typename:这是新的元组子类的名称。
  • field_names:每个字段的名称序列。它可以是列表['x', 'y', 'z']或字符串中的序列x y z(不带逗号,只有空格)或x, y, z
  • 重命名:如果重命名为True,则无效的字段名称将自动替换为位置名称。例如,['abc', 'def', 'ghi','abc']将转换为['abc', '_1', 'ghi', '_3'],消除关键字'def'(因为它是定义函数的保留字)和重复的fieldname 'abc'
  • verbose:如果verbose为True,则在构建之前就打印类定义。

如果选择,您仍然可以按名称元组的位置访问它们。p[1] == p.saturation。它仍然像普通的元组一样打开包装。

方法

支持所有常规元组方法。例如:min(),max(),len(),并入(+),索引,切片等,而不是在其中。namedtuple还有一些其他附加名称。注意:所有这些都以下划线开头。_replace_make_asdict

_replace 返回命名元组的新实例,用新值替换指定字段。

语法

somenamedtuple._replace(kwargs)

>>>from collections import namedtuple

>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)

>>>p._replace(hue=87)
Color(87, 0.1, 0.6)

>>>p._replace(hue=87, saturation=0.2)
Color(87, 0.2, 0.6)

注意:字段名称不带引号;他们是这里的关键词。 请记住:元组是不可变的-即使它们是namedtuple并具有_replace方法。的_replace产生new的实例; 它不会修改原始值或替换旧值。您当然可以将新结果保存到变量中。p = p._replace(hue=169)

_make

根据现有序列创建新实例或使其可迭代。

语法

somenamedtuple._make(iterable)

 >>>data = (170, 0.1, 0.6)
 >>>Color._make(data)
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make([170, 0.1, 0.6])  #the list is an iterable
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make((170, 0.1, 0.6))  #the tuple is an iterable
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make(170, 0.1, 0.6) 
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<string>", line 15, in _make
TypeError: 'float' object is not callable

最后一个发生了什么?括号内的项目应该是可迭代的。因此,括号内的列表或元组可以工作,但是未封装为可迭代值的值序列将返回错误。

_asdict

返回一个新的OrderedDict,它将字段名称映射到其对应的值。

语法

somenamedtuple._asdict()

 >>>p._asdict()
OrderedDict([('hue', 169), ('saturation', 0.1), ('luminosity', 0.6)])

参考https : //www.reddit.com/r/Python/comments/38ee9d/intro_to_namedtuple/

还有一个命名列表,类似于命名元组,但是可变 https://pypi.python.org/pypi/namedlist

namedtuple

is one of the easiest ways to clean up your code and make it more readable. It self-documents what is happening in the tuple. Namedtuples instances are just as memory efficient as regular tuples as they do not have per-instance dictionaries, making them faster than dictionaries.

from collections import namedtuple

Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])

 p = Color(170, 0.1, 0.6)
 if p.saturation >= 0.5:
     print "Whew, that is bright!"
 if p.luminosity >= 0.5:
     print "Wow, that is light"

Without naming each element in the tuple, it would read like this:

p = (170, 0.1, 0.6)
if p[1] >= 0.5:
    print "Whew, that is bright!"
if p[2]>= 0.5:
   print "Wow, that is light"

It is so much harder to understand what is going on in the first example. With a namedtuple, each field has a name. And you access it by name rather than position or index. Instead of p[1], we can call it p.saturation. It’s easier to understand. And it looks cleaner.

Creating an instance of the namedtuple is easier than creating a dictionary.

# dictionary
>>>p = dict(hue = 170, saturation = 0.1, luminosity = 0.6)
>>>p['hue']
170

#nametuple
>>>from collections import namedtuple
>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)
>>>p.hue
170

When might you use namedtuple

  1. As just stated, the namedtuple makes understanding tuples much easier. So if you need to reference the items in the tuple, then creating them as namedtuples just makes sense.
  2. Besides being more lightweight than a dictionary, namedtuple also keeps the order unlike the dictionary.
  3. As in the example above, it is simpler to create an instance of namedtuple than dictionary. And referencing the item in the named tuple looks cleaner than a dictionary. p.hue rather than p['hue'].

The syntax

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
  • namedtuple is in the collections library.
  • typename: This is the name of the new tuple subclass.
  • field_names: A sequence of names for each field. It can be a sequence as in a list ['x', 'y', 'z'] or string x y z (without commas, just whitespace) or x, y, z.
  • rename: If rename is True, invalid fieldnames are automatically replaced with positional names. For example, ['abc', 'def', 'ghi','abc'] is converted to ['abc', '_1', 'ghi', '_3'], eliminating the keyword 'def' (since that is a reserved word for defining functions) and the duplicate fieldname 'abc'.
  • verbose: If verbose is True, the class definition is printed just before being built.

You can still access namedtuples by their position, if you so choose. p[1] == p.saturation. It still unpacks like a regular tuple.

Methods

All the regular tuple methods are supported. Ex: min(), max(), len(), in, not in, concatenation (+), index, slice, etc. And there are a few additional ones for namedtuple. Note: these all start with an underscore. _replace, _make, _asdict.

_replace Returns a new instance of the named tuple replacing specified fields with new values.

The syntax

somenamedtuple._replace(kwargs)

Example

>>>from collections import namedtuple

>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)

>>>p._replace(hue=87)
Color(87, 0.1, 0.6)

>>>p._replace(hue=87, saturation=0.2)
Color(87, 0.2, 0.6)

Notice: The field names are not in quotes; they are keywords here. Remember: Tuples are immutable – even if they are namedtuples and have the _replace method. The _replace produces a new instance; it does not modify the original or replace the old value. You can of course save the new result to the variable. p = p._replace(hue=169)

_make

Makes a new instance from an existing sequence or iterable.

The syntax

somenamedtuple._make(iterable)

Example

 >>>data = (170, 0.1, 0.6)
 >>>Color._make(data)
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make([170, 0.1, 0.6])  #the list is an iterable
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make((170, 0.1, 0.6))  #the tuple is an iterable
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make(170, 0.1, 0.6) 
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<string>", line 15, in _make
TypeError: 'float' object is not callable

What happened with the last one? The item inside the parenthesis should be the iterable. So a list or tuple inside the parenthesis works, but the sequence of values without enclosing as an iterable returns an error.

_asdict

Returns a new OrderedDict which maps field names to their corresponding values.

The syntax

somenamedtuple._asdict()

Example

 >>>p._asdict()
OrderedDict([('hue', 169), ('saturation', 0.1), ('luminosity', 0.6)])

Reference: https://www.reddit.com/r/Python/comments/38ee9d/intro_to_namedtuple/

There is also named list which is similar to named tuple but mutable https://pypi.python.org/pypi/namedlist


回答 6

什么是namedtuple?

顾名思义,namedtuple是具有名称的元组。在标准元组中,我们使用索引访问元素,而namedtuple允许用户定义元素的名称。这非常方便,尤其是处理csv(逗号分隔值)文件并处理复杂而又庞大的数据集时,其中的代码因使用索引而变得混乱(不是pythonic)。

如何使用它们?

>>>from collections import namedtuple
>>>saleRecord = namedtuple('saleRecord','shopId saleDate salesAmout totalCustomers')
>>>
>>>
>>>#Assign values to a named tuple 
>>>shop11=saleRecord(11,'2015-01-01',2300,150) 
>>>shop12=saleRecord(shopId=22,saleDate="2015-01-01",saleAmout=1512,totalCustomers=125)

阅读

>>>#Reading as a namedtuple
>>>print("Shop Id =",shop12.shopId)
12
>>>print("Sale Date=",shop12.saleDate)
2015-01-01
>>>print("Sales Amount =",shop12.salesAmount)
1512
>>>print("Total Customers =",shop12.totalCustomers)
125

CSV处理中有趣的场景:

from csv import reader
from collections import namedtuple

saleRecord = namedtuple('saleRecord','shopId saleDate totalSales totalCustomers')
fileHandle = open("salesRecord.csv","r")
csvFieldsList=csv.reader(fileHandle)
for fieldsList in csvFieldsList:
    shopRec = saleRecord._make(fieldsList)
    overAllSales += shopRec.totalSales;

print("Total Sales of The Retail Chain =",overAllSales)

What is namedtuple ?

As the name suggests, namedtuple is a tuple with name. In standard tuple, we access the elements using the index, whereas namedtuple allows user to define name for elements. This is very handy especially processing csv (comma separated value) files and working with complex and large dataset, where the code becomes messy with the use of indices (not so pythonic).

How to use them ?

>>>from collections import namedtuple
>>>saleRecord = namedtuple('saleRecord','shopId saleDate salesAmout totalCustomers')
>>>
>>>
>>>#Assign values to a named tuple 
>>>shop11=saleRecord(11,'2015-01-01',2300,150) 
>>>shop12=saleRecord(shopId=22,saleDate="2015-01-01",saleAmout=1512,totalCustomers=125)

Reading

>>>#Reading as a namedtuple
>>>print("Shop Id =",shop12.shopId)
12
>>>print("Sale Date=",shop12.saleDate)
2015-01-01
>>>print("Sales Amount =",shop12.salesAmount)
1512
>>>print("Total Customers =",shop12.totalCustomers)
125

Interesting Scenario in CSV Processing :

from csv import reader
from collections import namedtuple

saleRecord = namedtuple('saleRecord','shopId saleDate totalSales totalCustomers')
fileHandle = open("salesRecord.csv","r")
csvFieldsList=csv.reader(fileHandle)
for fieldsList in csvFieldsList:
    shopRec = saleRecord._make(fieldsList)
    overAllSales += shopRec.totalSales;

print("Total Sales of The Retail Chain =",overAllSales)

回答 7

在Python内部,有一个很好使用的容器,称为命名元组,它可以用于创建类的定义,并具有原始元组的所有功能。

使用命名元组将直接应用于默认的类模板以生成一个简单的类,此方法允许使用大量代码来提高可读性,并且在定义类时也非常方便。

In Python inside there is a good use of container called a named tuple, it can be used to create a definition of class and has all the features of the original tuple.

Using named tuple will be directly applied to the default class template to generate a simple class, this method allows a lot of code to improve readability and it is also very convenient when defining a class.


回答 8

使用命名元组的另一种方法(新方法)是通过键入包来使用NamedTuple: namedtuple中键入提示

让我们以本文中最常见的答案为例,看看如何使用它。

(1)在使用命名元组之前,代码是这样的:

pt1 = (1.0, 5.0)
pt2 = (2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)
print(line_length)

(2)现在我们使用命名的元组

from typing import NamedTuple, Number

继承NamedTuple类,并在新类中定义变量名称。测试是类的名称。

class test(NamedTuple):
x: Number
y: Number

从类创建实例并为其分配值

pt1 = test(1.0, 5.0)   # x is 1.0, and y is 5.0. The order matters
pt2 = test(2.5, 1.5)

使用实例中的变量进行计算

line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)
print(line_length)

Another way (a new way) to use named tuple is using NamedTuple from typing package: Type hints in namedtuple

Let’s use the example of the top answer in this post to see how to use it.

(1) Before using the named tuple, the code is like this:

pt1 = (1.0, 5.0)
pt2 = (2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)
print(line_length)

(2) Now we use the named tuple

from typing import NamedTuple, Number

inherit the NamedTuple class and define the variable name in the new class. test is the name of the class.

class test(NamedTuple):
x: Number
y: Number

create instances from the class and assign values to them

pt1 = test(1.0, 5.0)   # x is 1.0, and y is 5.0. The order matters
pt2 = test(2.5, 1.5)

use the variables from the instances to calculate

line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)
print(line_length)

回答 9

尝试这个:

collections.namedtuple()

基本上,namedtuples易于创建的轻量级对象类型。他们将元组变成方便执行简单任务的容器。用namedtuples,您不必使用整数索引来访问元组的成员。

例子:

代码1:

>>> from collections import namedtuple

>>> Point = namedtuple('Point','x,y')

>>> pt1 = Point(1,2)

>>> pt2 = Point(3,4)

>>> dot_product = ( pt1.x * pt2.x ) +( pt1.y * pt2.y )

>>> print dot_product
11

代码2:

>>> from collections import namedtuple

>>> Car = namedtuple('Car','Price Mileage Colour Class')

>>> xyz = Car(Price = 100000, Mileage = 30, Colour = 'Cyan', Class = 'Y')

>>> print xyz

Car(Price=100000, Mileage=30, Colour='Cyan', Class='Y')
>>> print xyz.Class
Y

Try this:

collections.namedtuple()

Basically, namedtuples are easy to create, lightweight object types. They turn tuples into convenient containers for simple tasks. With namedtuples, you don’t have to use integer indices for accessing members of a tuple.

Examples:

Code 1:

>>> from collections import namedtuple

>>> Point = namedtuple('Point','x,y')

>>> pt1 = Point(1,2)

>>> pt2 = Point(3,4)

>>> dot_product = ( pt1.x * pt2.x ) +( pt1.y * pt2.y )

>>> print dot_product
11

Code 2:

>>> from collections import namedtuple

>>> Car = namedtuple('Car','Price Mileage Colour Class')

>>> xyz = Car(Price = 100000, Mileage = 30, Colour = 'Cyan', Class = 'Y')

>>> print xyz

Car(Price=100000, Mileage=30, Colour='Cyan', Class='Y')
>>> print xyz.Class
Y

回答 10

其他人都已经回答了,但是我想我还有其他事情要补充。

Namedtuple可以直观地视为定义类的捷径。

请参阅定义一个繁琐而常规的方法class

class Duck:
    def __init__(self, color, weight):
        self.color = color
        self.weight = weight
red_duck = Duck('red', '10')

    In [50]: red_duck
    Out[50]: <__main__.Duck at 0x1068e4e10>
    In [51]: red_duck.color
    Out[51]: 'red'

至于 namedtuple

from collections import namedtuple
Duck = namedtuple('Duck', ['color', 'weight'])
red_duck = Duck('red', '10')

In [54]: red_duck
Out[54]: Duck(color='red', weight='10')
In [55]: red_duck.color
Out[55]: 'red'

Everyone else has already answered it, but I think I still have something else to add.

Namedtuple could be intuitively deemed as a shortcut to define a class.

See a cumbersome and conventional way to define a class .

class Duck:
    def __init__(self, color, weight):
        self.color = color
        self.weight = weight
red_duck = Duck('red', '10')

    In [50]: red_duck
    Out[50]: <__main__.Duck at 0x1068e4e10>
    In [51]: red_duck.color
    Out[51]: 'red'

As for namedtuple

from collections import namedtuple
Duck = namedtuple('Duck', ['color', 'weight'])
red_duck = Duck('red', '10')

In [54]: red_duck
Out[54]: Duck(color='red', weight='10')
In [55]: red_duck.color
Out[55]: 'red'

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。