Python 中有一种“特殊”类型的元组,称为“命名元组”。Python 学习者对此感到困惑是很常见的,尤其是我们应该何时以及为何使用它。
命名元组是元组,因此它可以完成元组所能做的一切。但是,它超出了普通的 Python 元组。它更像是 C++ 等其他编程语言中的“结构”。它是元组的特定子类,它是根据您的规范以编程方式创建的,具有命名字段和固定长度。
- 创建一个命名元组
在我们开始之前,这里有一个小提示。从 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 模块的超类。
- 字段名称自动重命名
图像通过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
- 使用一个命名元组
为了演示如何使用命名元组,让我们重复我们在上述章节中使用的例子。我们可以定义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)
- 为什么以及何时使用命名元组?
好了,我们已经介绍了关于 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
更多文章