Den*_*aia 843 python tuples namedtuple
阅读Python 3.1中的更改,我发现了一些......意外的:
sys.version_info元组现在是一个命名元组:
我之前从未听说过命名元组,我认为元素可以用数字(如元组和列表)或键(如dicts)索引.我从没想过他们可以两种方式编入索引.
因此,我的问题是:
fma*_*ark 1117
命名元组基本上是易于创建的轻量级对象类型.可以使用类似对象的变量解引用或标准元组语法来引用命名的元组实例.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)
Run Code Online (Sandbox Code Playgroud)
使用命名元组它变得更具可读性:
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)
Run Code Online (Sandbox Code Playgroud)
但是,命名元组仍然向后兼容正常元组,因此以下内容仍然有效:
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
Run Code Online (Sandbox Code Playgroud)
因此,您应该使用命名元组而不是元组,只要您认为对象符号会使您的代码更加pythonic并且更易于阅读.我个人已经开始使用它们来表示非常简单的值类型,特别是在将它们作为参数传递给函数时.它使函数更具可读性,而无需查看元组打包的上下文.
此外,您还可以替换没有函数的普通不可变类,只替换具有它们的字段.您甚至可以使用命名元组类型作为基类:
class Point(namedtuple('Point', 'x y')):
[...]
Run Code Online (Sandbox Code Playgroud)
但是,与元组一样,命名元组中的属性是不可变的:
>>> Point = namedtuple('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
AttributeError: can't set attribute
Run Code Online (Sandbox Code Playgroud)
如果您希望能够更改值,则需要其他类型.可变记录类型有一个方便的配方,允许您为属性设置新值.
>>> 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
Run Code Online (Sandbox Code Playgroud)
但是,我不知道任何形式的"命名列表"允许您添加新字段.在这种情况下,您可能只想使用字典.命名元组可以转换为使用pt1._asdict()哪些返回的字典,{'x': 1.0, 'y': 5.0}并且可以使用所有常用的字典函数进行操作.
如前所述,您应该查看文档以获取构建这些示例的更多信息.
The*_*emz 93
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)
Run Code Online (Sandbox Code Playgroud)
Aar*_*all 75
什么叫元组?
命名元组是一个元组.
它完成了元组所能做的一切.
但它不仅仅是一个元组.
它是元组的特定子类,以编程方式为您的规范创建,具有命名字段和固定长度.
例如,这创建了一个元组的子类,除了具有固定长度(在这种情况下为三个)之外,它可以在使用元组的任何地方使用而不会破坏.这被称为Liskov可替代性:
from typing import NamedTuple
class ANamedTuple(NamedTuple):
"""a docstring"""
foo: int
bar: str
baz: list
Run Code Online (Sandbox Code Playgroud)
这实例化它:
>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)
Run Code Online (Sandbox Code Playgroud)
我们可以检查它并使用它的属性:
>>> ant = ANamedTuple(1, 'bar', [])
Run Code Online (Sandbox Code Playgroud)
要了解命名元组,首先需要知道元组是什么.元组本质上是一个不可变的(不能在内存中就地更改)列表.
以下是使用常规元组的方法:
>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']
Run Code Online (Sandbox Code Playgroud)
您可以使用iterable unpacking扩展元组:
>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'
Run Code Online (Sandbox Code Playgroud)
命名元组是元组,允许通过名称而不是索引来访问它们的元素!
你创建一个像这样的命名元组:
>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
Run Code Online (Sandbox Code Playgroud)
您还可以使用单个字符串,其名称用空格分隔,API的使用稍微更具可读性:
>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])
Run Code Online (Sandbox Code Playgroud)
怎么用?
您可以执行元组可以执行的所有操作(请参见上文)以及执行以下操作:
>>> Student = namedtuple('Student', 'first last grade')
Run Code Online (Sandbox Code Playgroud)
一位评论者问:
在大型脚本或程序中,通常在哪里定义一个命名元组?
您创建的类型typing.NamedTuple基本上是您可以使用简单的速记创建的类.像对待课一样对待他们 在模块级别定义它们,以便pickle和其他用户可以找到它们.
全局模块级别的工作示例:
>>> 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')
Run Code Online (Sandbox Code Playgroud)
这表明无法查找定义:
>>> 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')
Run Code Online (Sandbox Code Playgroud)
为什么/何时应该使用命名元组而不是普通元组?
在改进代码时使用它们,以便在代码中表达元组元素的语义.如果您使用具有不变数据属性且没有功能的对象,则可以使用它们而不是对象.您还可以将它们子类化以添加功能,例如:
>>> 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
Run Code Online (Sandbox Code Playgroud)
为什么/何时应该使用普通元组而不是命名元组?
从使用命名元组切换到元组可能是一种回归.前期设计决策的核心是,在使用元组时,所涉及的额外代码的成本是否值得提高可读性.
命名元组与元组没有使用额外的内存.
是否有任何类型的"命名列表"(命名元组的可变版本)?
您正在寻找实现静态大小列表的所有功能的时隙对象或者像命名元组一样工作的子类列表(并且以某种方式阻止列表更改大小.)
一个现在扩展的,甚至可能是Liskov可替代的第一个例子:
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)
Run Code Online (Sandbox Code Playgroud)
并使用,只是子类和定义namedtuple:
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__)
Run Code Online (Sandbox Code Playgroud)
pyg*_*iel 41
namedtuples是一个很棒的功能,它们是数据的完美容器.当您必须"存储"数据时,您将使用元组或词典,例如:
user = dict(name="John", age=20)
Run Code Online (Sandbox Code Playgroud)
要么:
user = ("John", 20)
Run Code Online (Sandbox Code Playgroud)
字典方法是压倒性的,因为字典是可变的并且比元组慢.另一方面,元组是不可变的和轻量级的,但是对于数据字段中的大量条目缺乏可读性.
namedtuples是这两种方法的完美折衷方案,具有很好的可读性,轻量级和不变性(加上它们是多态的!).
Joh*_*ooy 28
命名元组允许向后兼容检查此类版本的代码
>>> sys.version_info[0:2]
(3, 1)
Run Code Online (Sandbox Code Playgroud)
同时通过使用此语法允许未来的代码更明确
>>> sys.version_info.major
3
>>> sys.version_info.minor
1
Run Code Online (Sandbox Code Playgroud)
Yil*_*maz 12
from collections import namedtuple \nRun Code Online (Sandbox Code Playgroud)\n“namedtuple”是一个函数,它生成一个继承自“tuple”的新类,但还提供“命名属性”来访问元组的元素。
\n“namedtuple”是一个类工厂。生成类需要一些东西
\n班级名称
\n我们要按照元组中元素的顺序分配的字段名称序列。字段名称可以是任何有效的变量名称,但不能以下划线开头。
\n调用“namedtuple”的返回值将是一个类。我们需要在代码中将该类分配给变量名,以便我们可以使用它来构造实例。一般来说,我们使用与生成的类的名称相同的名称。
\n# Coords is a class\nCoords = namedtuple('Coords', ['x', 'y'])\nRun Code Online (Sandbox Code Playgroud)\n现在我们可以创建 Coords 类的实例:
\npt=Coords(10,20)\nRun Code Online (Sandbox Code Playgroud)\n我们可以通过多种方式向namedtuple 函数提供字段名称列表。
\n字符串列表
\n namedtuple('Coords', ['x','y'])\nRun Code Online (Sandbox Code Playgroud)\n字符串元组
\n namedtuple('Coords', ('x','y'))\nRun Code Online (Sandbox Code Playgroud)\n字段名称以空格或逗号分隔的单个字符串
\n namedtuple('Coords', 'x, y')\nRun Code Online (Sandbox Code Playgroud)\n创建命名元组类后,我们可以像普通类一样实例化它们。事实上,__new__生成的类的方法使用我们提供的字段名称作为参数名称。
Coords = namedtuple('Coords', ['x', 'y'])\ncoord=Coords(10,20) \nRun Code Online (Sandbox Code Playgroud)\n由于命名元组继承自元组,我们仍然可以像任何其他元组一样处理它们:通过索引、切片、迭代
\nCoords = namedtuple('Coords', ['x', 'y'])\ncoord=Coords(10,20) isinstance(coord,tuple) --> True # namedtuple is subclass of tuple\n\nx,y=coord # Unpacking\nx=coord[0] # by index\nfor e in coord:\n print(e)\nRun Code Online (Sandbox Code Playgroud)\n现在我们也可以使用字段名称访问数据,就像使用类一样。
\ncoord.x --> 10\ncoord.y --> 20\nRun Code Online (Sandbox Code Playgroud)\n由于namedtuple是继承自tuple生成的类,我们可以这样写:
\nclass Coord(tuple):\n ....\nRun Code Online (Sandbox Code Playgroud)\n“coord”是一个元组,因此不可变
\n字段名称不能以下划线开头
\nCoords = namedtuple('Coords', ['x', '_y']) # does not work\nRun Code Online (Sandbox Code Playgroud)\nnametuple 有一个仅关键字参数rename(默认为 False),它将自动重命名任何无效的字段名称。
Coords = namedtuple('Coords', ['x', '_y'], rename=True)\nRun Code Online (Sandbox Code Playgroud)\n字段名称“x”不会更改,但“_y”将更改为_1。1 是字段名称的索引。
想象一下您需要更新应用程序的场景,因此您希望使用namedtuple 来存储应用程序的用户。您需要提取列名,但它们对于命名元组无效,并且会引发异常。在这种情况下,您使用rename=True.
Coords = namedtuple('Coords', ['x', 'y'])\ncoord=Coords(10,20)\ncoord._asdict()\n {'x': 10, 'y': 20}\nRun Code Online (Sandbox Code Playgroud)\n如果你有这门课:
\nclass Stock:\n def __init__(self, symbol, year, month, day, open, high, low, close):\n self.symbol = symbol\n self.year = year\n self.month = month\n self.day = day\n self.open = open \n self.high = high\n self.low = low\n self.close = close\nRun Code Online (Sandbox Code Playgroud)\n类方法- 与元组方法
\nstock.symbol stock[0] \nstock.open stock[4]\nstock.close stock[7]\nstock.high \xe2\x80\x93 stock.low stock[5] \xe2\x80\x93 stock[6]\nRun Code Online (Sandbox Code Playgroud)\n如您所见,元组方法不可读。集合中的函数namedtuple 允许我们创建一个元组,该元组也将名称附加到每个字段或属性。这可以方便地通过“名称”引用元组结构中的数据,而不仅仅是依赖位置。但请记住,元组是不可变的,因此如果您想要可变性,请坚持使用类
Kev*_*Zhu 11
是清理代码并使其更具可读性的最简单方法之一.它自我记录元组中发生的事情.Namedtuples实例与常规元组一样具有内存效率,因为它们没有每个实例的字典,使它们比字典更快.
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"
Run Code Online (Sandbox Code Playgroud)
如果没有命名元组中的每个元素,它将如下所示:
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"
Run Code Online (Sandbox Code Playgroud)
要理解第一个例子中发生的事情要困难得多.使用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
Run Code Online (Sandbox Code Playgroud)
p.hue而不是
p['hue'].语法
collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
Run Code Online (Sandbox Code Playgroud)
['x', 'y', 'z']或字符串中的序列x y z(没有逗号,只有空格)或x, y, z.True,则无效的字段名称将自动替换为位置名称.例如,['abc', 'def', 'ghi','abc']转换为['abc', '_1', 'ghi', '_3'],删除关键字'def'(因为这是用于定义函数的保留字)和重复的字段名'abc'.True,则在构建之前打印类定义.如果您愿意,您仍然可以按位置访问namedtuples.p[1] == p.saturation.它仍然像常规元组一样解压缩.
支持所有常规元组方法.例如:min(),max(),len(),in,not in,concatenation(+),index,slice等.还有一些额外的用于namedtuple.注意:这些都以下划线开头._replace,_make,_asdict.
_replace
返回使用新值替换指定字段的命名元组的新实例.
语法
somenamedtuple._replace(kwargs)
Run Code Online (Sandbox Code Playgroud)
例
>>>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)
Run Code Online (Sandbox Code Playgroud)
注意:字段名称不在引号中; 他们是这里的关键词.
记住:元组是不可变的 - 即使它们是有名的元组并且有_replace方法.的_replace产生new的实例; 它不会修改原始值或替换旧值.您当然可以将新结果保存到变量中.p = p._replace(hue=169)
_make
从现有序列或可迭代创建新实例.
语法
somenamedtuple._make(iterable)
Run Code Online (Sandbox Code Playgroud)
例
>>>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
Run Code Online (Sandbox Code Playgroud)
最后一个发生了什么?括号内的项应该是可迭代的.因此,括号内的列表或元组可以正常工作,但是没有作为迭代包含的值序列会返回错误.
_asdict
返回一个新的OrderedDict,它将字段名称映射到它们对应的值.
语法
somenamedtuple._asdict()
Run Code Online (Sandbox Code Playgroud)
例
>>>p._asdict()
OrderedDict([('hue', 169), ('saturation', 0.1), ('luminosity', 0.6)])
Run Code Online (Sandbox Code Playgroud)
参考:https://www.reddit.com/r/Python/comments/38ee9d/intro_to_namedtuple/
还有一个命名列表,类似于命名元组但可变的 https://pypi.python.org/pypi/namedlist
什么是名字?
顾名思义,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)
Run Code Online (Sandbox Code Playgroud)
读
>>>#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
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
在Python里面有一个很好用的容器叫做命名元组,它可以用来创建类的定义并具有原始元组的所有功能.
使用命名元组将直接应用于默认类模板以生成一个简单类,此方法允许大量代码提高可读性,并且在定义类时也非常方便.
| 归档时间: |
|
| 查看次数: |
318602 次 |
| 最近记录: |