简介
本节介绍以元组和字典形式存在的数据结构。
This tutorial is from open-source community. Access the source code
💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版
本节介绍以元组和字典形式存在的数据结构。
Python 有几种基本数据类型:
我们在引言部分已经了解过这些内容。
email_address = None
None
通常用作可选值或缺失值的占位符。在条件判断中,它被视为 False
。
if email_address:
send_email(email_address, msg)
实际的程序会有更复杂的数据。例如,关于股票持仓的信息:
100 shares of GOOG at $490.10
这是一个包含三个部分的“对象”:
元组是一组组合在一起的值。
示例:
s = ('GOOG', 100, 490.1)
有时在语法中会省略 ()
。
s = 'GOOG', 100, 490.1
特殊情况(零元组、一元组)。
t = () ## 一个空元组
w = ('GOOG', ) ## 一个包含一项的元组
元组通常用于表示 简单的 记录或结构。通常,它是一个由多个部分组成的单个 对象。一个很好的类比是:元组就像数据库表中的一行。
元组的内容是有序的(类似于数组)。
s = ('GOOG', 100, 490.1)
name = s[0] ## 'GOOG'
shares = s[1] ## 100
price = s[2] ## 490.1
然而,内容不能被修改。
>>> s[1] = 75
TypeError: object does not support item assignment
不过,你可以基于当前元组创建一个新的元组。
s = (s[0], 75, s[2])
元组更多的是将相关的项打包成一个单一的 实体。
s = ('GOOG', 100, 490.1)
然后,这个元组作为一个单一对象很容易传递到程序的其他部分。
要在其他地方使用元组,你可以将其各个部分解包到变量中。
name, shares, price = s
print('Cost', shares * price)
左边变量的数量必须与元组结构匹配。
name, shares = s ## 错误
Traceback (most recent call last):
...
ValueError: too many values to unpack
元组看起来像是只读列表。然而,元组最常用于由多个部分组成的 单个项。列表通常是不同项的集合,通常所有项都属于同一类型。
record = ('GOOG', 100, 490.1) ## 一个表示投资组合中一条记录的元组
symbols = [ 'GOOG', 'AAPL', 'IBM' ] ## 一个表示三个股票代码的列表
字典是键到值的映射。它有时也被称为哈希表或关联数组。键用作访问值的索引。
s = {
'name': 'GOOG',
'shares': 100,
'price': 490.1
}
要从字典中获取值,请使用键名。
>>> print(s['name'], s['shares'])
GOOG 100
>>> s['price']
490.10
>>>
要添加或修改值,请使用键名进行赋值。
>>> s['shares'] = 75
>>> s['date'] = '6/6/2007'
>>>
要删除一个值,请使用 del
语句。
>>> del s['date']
>>>
当存在 许多 不同的值,并且这些值可能需要修改或操作时,字典就很有用。字典能让你的代码更具可读性。
s['price']
## 对比
s[2]
在前几个练习中,你编写了一个程序来读取数据文件 portfolio.csv
。使用 csv
模块,可以很容易地逐行读取文件。
>>> import csv
>>> f = open('portfolio.csv')
>>> rows = csv.reader(f)
>>> next(rows)
['name','shares', 'price']
>>> row = next(rows)
>>> row
['AA', '100', '32.20']
>>>
虽然读取文件很容易,但你通常希望对数据进行更多操作,而不仅仅是读取它。例如,也许你想存储它并开始对其进行一些计算。不幸的是,原始的“行”数据不足以让你进行操作。例如,即使是简单的数学计算也无法进行:
>>> row = ['AA', '100', '32.20']
>>> cost = row[1] * row[2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type'str'
>>>
为了进行更多操作,你通常需要以某种方式解释原始数据,并将其转换为更有用的对象类型,以便稍后使用。两个简单的选择是元组或字典。
在交互式提示符下,创建以下元组,它表示上述行,但将数字列转换为适当的数字:
>>> t = (row[0], int(row[1]), float(row[2]))
>>> t
('AA', 100, 32.2)
>>>
使用这个元组,现在你可以通过将股票数量和价格相乘来计算总成本:
>>> cost = t[1] * t[2]
>>> cost
3220.0000000000005
>>>
Python中的数学运算出错了吗?为什么答案是3220.0000000000005 ?
这是你计算机上的浮点硬件的产物,它只能精确表示二进制中的小数,而不是十进制中的小数。即使是涉及十进制小数的简单计算,也会引入小误差。这是正常的,不过如果你以前没见过,可能会有点惊讶。
在所有使用浮点小数的编程语言中都会发生这种情况,但在打印时通常会被隐藏起来。例如:
>>> print(f'{cost:0.2f}')
3220.00
>>>
元组是只读的。通过尝试将股票数量改为75来验证这一点。
>>> t[1] = 75
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>>
虽然你不能更改元组的内容,但你总是可以创建一个全新的元组来替换旧的元组。
>>> t = (t[0], 75, t[2])
>>> t
('AA', 75, 32.2)
>>>
每当你像这样重新赋值一个现有变量名时,旧值就会被丢弃。虽然上述赋值看起来像是在修改元组,但实际上你是在创建一个新的元组并扔掉旧的元组。
元组通常用于将值打包和解包到变量中。试试以下操作:
>>> name, shares, price = t
>>> name
'AA'
>>> shares
75
>>> price
32.2
>>>
将上述变量再打包回一个元组
>>> t = (name, 2*shares, price)
>>> t
('AA', 150, 32.2)
>>>
元组的另一种替代方案是创建一个字典。
>>> d = {
'name' : row[0],
'shares' : int(row[1]),
'price' : float(row[2])
}
>>> d
{'name': 'AA','shares': 100, 'price': 32.2 }
>>>
计算这种持仓的总成本:
>>> cost = d['shares'] * d['price']
>>> cost
3220.0000000000005
>>>
将此示例与上面涉及元组的相同计算进行比较。将股票数量改为75。
>>> d['shares'] = 75
>>> d
{'name': 'AA','shares': 75, 'price': 32.2 }
>>>
与元组不同,字典可以自由修改。添加一些属性:
>>> d['date'] = (6, 11, 2007)
>>> d['account'] = 12345
>>> d
{'name': 'AA','shares': 75, 'price':32.2, 'date': (6, 11, 2007), 'account': 12345}
>>>
如果你将一个字典转换为列表,你会得到它的所有键:
>>> list(d)
['name','shares', 'price', 'date', 'account']
>>>
同样地,如果你使用 for
语句在字典上进行迭代,你会得到键:
>>> for k in d:
print('k =', k)
k = name
k = shares
k = price
k = date
k = account
>>>
试试这个同时进行查找的变体:
>>> for k in d:
print(k, '=', d[k])
name = AA
shares = 75
price = 32.2
date = (6, 11, 2007)
account = 12345
>>>
你也可以使用 keys()
方法获取所有的键:
>>> keys = d.keys()
>>> keys
dict_keys(['name','shares', 'price', 'date', 'account'])
>>>
keys()
有点不同寻常,因为它返回一个特殊的 dict_keys
对象。
这是原始字典的一个覆盖层,它总是会给出当前的键 —— 即使字典发生了变化。例如,试试这个:
>>> del d['account']
>>> keys
dict_keys(['name','shares', 'price', 'date'])
>>>
仔细注意,即使你没有再次调用 d.keys()
,'account'
也从 keys
中消失了。
一种更优雅的同时处理键和值的方法是使用 items()
方法。这会给你 (键, 值)
元组:
>>> items = d.items()
>>> items
dict_items([('name', 'AA'), ('shares', 75), ('price', 32.2), ('date', (6, 11, 2007))])
>>> for k, v in d.items():
print(k, '=', v)
name = AA
shares = 75
price = 32.2
date = (6, 11, 2007)
>>>
如果你有像 items
这样的元组,你可以使用 dict()
函数创建一个字典。试试看:
>>> items
dict_items([('name', 'AA'), ('shares', 75), ('price', 32.2), ('date', (6, 11, 2007))])
>>> d = dict(items)
>>> d
{'name': 'AA','shares': 75, 'price':32.2, 'date': (6, 11, 2007)}
>>>
恭喜你!你已经完成了数据类型和数据结构实验。你可以在LabEx中练习更多实验来提升你的技能。