Python 中有一种“特殊”类型的元组,称为“命名元组”

Python 中有一种“特殊”类型的元组,称为“命名元组”。Python 学习者对此感到困惑是很常见的,尤其是我们应该何时以及为何使用它。

命名元组是元组,因此它可以完成元组所能做的一切。但是,它超出了普通的 Python 元组。它更像是 C++ 等其他编程语言中的“结构”。它是元组的特定子类,它是根据您的规范以编程方式创建的,具有命名字段和固定长度。

  1. 创建一个命名元组

在我们开始之前,这里有一个小提示。从 Python 3.1 开始,有一个名为 tuple 的重要内置常量来指示我们现在使用的 Python 版本。我们可以得到它如下。before we started. Since Python 3.1, there is an important built-in constant named tuple to indicate the version of the Python that we are using right now. We can get it as follows.
import sys
sys.version_info

如果我们想在我们的程序中使用它,我们需要从集合模块中导入它。

从collection导入namedtuple
在namedtuple从采集模块是一个类工厂。换句话说,它制造类。我们需要提供以下内容来生成我们想要的类。
我们要使用的类名
我们要分配的字段名称序列,按元组中的元素顺序排列。
我们需要在我们的代码中将该类分配给一个变量名,以便我们可以使用它来构造实例。

例如,如果我们想定义一个Coords具有纬度和经度两个属性的类,我们可以如下实现。

Coords = namedtuple('Coords', ['Latitude', 'Longitude'])

Latitude: 经度
Longitude:纬度
重庆经度:106.55, 纬度:29.57
然后,我们可以使用Coords该类来实例化一个对象,该对象将是一个命名元组。

chongqing = Coords(Latitude=106.55,Longitude=29.57)
print(chongqing)

Coords(Latitude=106.55, Longitude=29.57)

我们可以验证它是一个元组,尽管它有字段名称。
isinstance(home,元组)

此外,要从类中实例化命名元组,我们不必每次都指定字段名称,因为命名元组的顺序和长度是固定的。
家 = 坐标(-37.8871270826, 144.7558373041)
重庆经度:106.55 纬度:29.57
chongqing =
再举一个描述位置坐标的表达,二维坐标扩展为三维描述时,可以这样做:

from collections import namedtuple
two_d = namedtuple('twoDPoint', ['x', 'y'])
x = two_d(1, 2)
#x = two_d(1, 2)
three_d = namedtuple('threeDPoint', ['x', 'y', 'z'])
print(x)
#twoDPoint(x=1, y=2)

y = three_d(*x, z=3)
print(y)
#threeDPoint(x=1, y=2, z=3)

1.1 定义命名元组类的简单方法
我们可以轻松地使用字符串来指定字段,而不是使用列表来指定字段。例如,我们可以使用 common 来分隔字段名称。
Coords = namedtuple('Coords', '纬度,经度')

我们甚至可以使用空格作为分隔符,这完全没问题。
Triangle = namedtuple('Triangle', 'first_side second_sidethird_side')
t1 = Triangle(5, 5, 5)

1.2 使用类型提示从超类创建
从 Python 3.6 开始,我们还可以更正式地定义一个命名元组类。这也将支持命名字段的类型提示。
从输入导入 NamedTuple # 3.6+

class Coords(NamedTuple): 
    """坐标由纬度和经度组成""" 
    latitude: float 
    longitude: float
家 = 坐标(-37.8871270826, 144.7558373041)

不同之处在于我们需要使用NamedTuple来自 Typing 模块的超类。

  1. 字段名称自动重命名

图像通过QK从Pixabay
当我们定义一个命名元组类时,虽然我们可能使用字符串作为字段名,但它们会被反映为类属性。因此,对这些字段名称会有一些限制。
首先,我们不能使用以下划线开头的字段名称。

MyNamedTuple = namedtuple('MyNamedTuple', ['_attr1', 'attr2'])

一些保留关键字也被禁止,例如def.
MyNamedTuple = namedtuple('MyNamedTuple', ['def', 'attr2'])

此外,字段名不能重复,因为一个类不能有两个同名的属性。
MyNamedTuple = namedtuple('MyNamedTuple', ['attr1', 'attr1'])

然而,从Python 3.1开始,我们可以将标志rename设置为True,这样任何无效的字段名都会被自动重命名,而不会抛出一个错误。

MyNamedTuple = namedtuple(
    'MyNamedTuple', 
    ['_attr1', 'def', 'attr2', 'attr2'], 
    rename=True
)

上面代码中的命名元组定义已经违反了这三条规则,但是因为我们将 rename 标志设置为 true,它将让它没有错误。有一个小技巧可以检查命名元组类的字段名,这就是使用其私有属性_fields。

MyNamedTuple._fields
  1. 使用一个命名元组

为了演示如何使用命名元组,让我们重复我们在上述章节中使用的例子。我们可以定义Coords类并实例化一个命名元组的家。

Coords = namedtuple('Coords', 'latitude, longitude')
home = Coords(-37.8871270826, 144.7558373041)

3.1 访问这些值
然后,我们可以访问命名元组中的值。非常直观的是,我们可以使用字段名来访问其相应的值。这是使用命名元组的主要好处之一。它也提高了我们代码的可读性。

print(home.latitude)
print(home.longitude)

另外,别忘了一个命名的元组就是一个元组。因此,我们也可以使用索引来获取数值。

print(home[0])
print(home[1])

3.2 将一个命名元组转换成一个字典
一个命名的元组在表现形式上与一个字典非常相似。字段名可以被看作是字典的键,而且它们都有相应的值。
事实上,一个命名元组有一个内置的私有方法来把自己转换成一个有序的字典。

home._asdict()

这是有道理的。也许命名元组和 dictionary 之间最重要的区别是,在命名元组中字段的顺序很重要。这意味着一个命名元组和一个有序的字典可以互换。

然而,如果我们不关心键的顺序,而只是想要一个字典呢?我们可以简单地在有序字典上再加一个类型化,如下所示。

dict(home._asdict())

3.3 替换字段的值
由于命名的元组是一个元组,而元组是不可改变的,所以不可能改变一个字段的值。

home.latitude = 10

在这种情况下,我们必须使用另一个私有方法_replace()来替换字段的值。

home1 = home._replace(latitude=10)

_replace()方法将返回一个新的命名元组。这很重要,因为即使使用这个方法,我们仍然不能修改一个命名元组。
如果我们检查原始的命名元组,它并没有改变。

3.4 有默认值的命名元组
就像在一个普通的类中我们可以为属性设置缺省值一样,一个命名元组类也可以设置缺省值。然而,由于带有缺省值的字段必须排在没有缺省值的字段之后,缺省值被应用于最右边的参数。
例如,让我们再次定义Coords类,只有一个默认值。

Coords = namedtuple('Coords', 'latitude, longitude', defaults=[100])
home = Coords(-37.8871270826)

如果我们实例化的命名元组只有一个值,默认值100将被用于经度,也就是我们定义中最右边的那个。如果我们明确设置该字段为经度,那么默认值将被用于纬度?

home = Coords(longitude=-37.8871270826)

答案当然是否定的。在一个命名元组中,字段的顺序是相当严格的。为了避免混乱和潜在的问题,默认值必须是最右边的,即使我们明确指定了一些东西。
如果我们给所有的字段提供默认值,这意味着所提供的默认值的数量与字段的数量相同,当我们实例化一个命名元组时,我们将不必传入任何值。

Coords = namedtuple('Coords', 'latitude, longitude', defaults=[-50, 100])
home = Coords()

检查命名元组类的默认值的一个技巧是使用其私有属性_field_defaults。

Coords._field_defaults

3.5 将一个元组转换为一个命名元组
如果我们有一个正常的元组和一个命名元组类,我们可以使用私有方法_make()轻松地将元组转换成一个命名元组。请注意,元组的长度必须与命名元组相同。

t1 = (-37.8871270826, 144.7558373041)
home = Coords._make(t1)
  1. 为什么以及何时使用命名元组?

好了,我们已经介绍了关于 Python 中命名元组的几乎所有内容。为什么Python有它,我们什么时候应该使用它呢?

答案如下

与普通元组相比,使用命名元组可以改善我们的代码,使元组元素的语义得到表达。
与Python类相比,使用命名元组可以提高代码的可读性,并大大减少代码的行数。
第一点是不言而喻的。对于第二点,让我们考虑下面的例子。假设我们需要定义一个学生类。它不一定有任何方法。换句话说,它只是保存一个学生对象的数据。

class Student:
    def __init__(self, student_no, first_name, last_name, birth_year, gender):
        self.student_no = student_no
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        self.gender = gender

如果我们使用一个命名的元组,其定义就像下面这样简单。

Student = namedtuple('Student', 'student_no, first_name, last_name, birth_year, gender')

因此,在这种情况下,使用一个命名的元组比一个类要容易和整洁得多。然而,如果我们需要任何类方法,命名元组将不再适用。

使用命名元组的另一个好处是它的可迭代性。也就是说,一个命名的元组是可迭代的,这样它就可以在许多情况下使用,比如循环和生成器。

让我们使用学生类来实例化一个命名元组

s1 = Student(123, 'Chris', 'Tao', 1900, 'Male')

然后,我们可以循环它的值。

for attr in s1:
    print(attr)

总结

在这篇文章中,我介绍了Python中的命名元组,它是什么,如何创建一个命名元组类以及如何将该类实例化为命名元组。然后,我说明了什么时候我们应该使用命名元组,什么时候我们不应该。希望你喜欢阅读!

继续搞事情!

#case 1st
import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print(df)
'''
   c1   c2
0  10  100
1  11  110
2  12  120

更多栗子......

import pandas as pd

a = [1, 2, 3, 4]
b = [5, 6, 7, 8]

mjr = pd.DataFrame({'a':a, 'b':b})
print(mjr)

   a  b
0  1  5
1  2  6
2  3  7
3  4  8

遍历输出形式:

size = mjr.shape

for i in range(size[0]):
    for j in range(size[1]):
        print(mjr.iloc[i, j])

Case 2rd

import pandas as pd
import numpy as np

df = pd.DataFrame( { 'x':[1,2,3,4,5,6], 'y':[1,1,1,0,1,1]  } )

   x  y
0  1  1
1  2  1
2  3  1
3  4  0
4  5  1
5  6  1

Case 3rd

import pandas as pd
df = pd.DataFrame({'c1': [10, 11, 12], 'c2': [100, 110, 120]})

for index, row in df.iterrows():
    print(row['c1'], row['c2'])

10 100
11 110
12 120

更多文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容