乐趣区

关于python:翻译实用的Python编程0202Containers

目录 | 上一节 (2.1 数据类型) | 下一节 (2.3 格式化)

2.2 容器

本节探讨列表(list),字典(dict)和汇合(set)。

概述

通常,程序必须解决许多对象。

  • 股票的投资组合
  • 股票价格表

这里有三种次要的抉择(译注:数据结构)能够应用:

  • 列表。有序的数据。
  • 字典。无序的数据。
  • 汇合。互异且无序的数据。

把列表当作容器

当数据程序很重要时,请应用列表。记住,列表能够存储任何类型的对象。例如,蕴含元组的列表:

portfolio = [('GOOG', 100, 490.1),
    ('IBM', 50, 91.3),
    ('CAT', 150, 83.44)
]

portfolio[0]            # ('GOOG', 100, 490.1)
portfolio[2]            # ('CAT', 150, 83.44)

列表构建

从零开始构建列表。

records = []  # Initial empty list

# Use .append() to add more items
records.append(('GOOG', 100, 490.10))
records.append(('IBM', 50, 91.3))
...

从文件读取记录的示例:

records = []  # Initial empty list

with open('Data/portfolio.csv', 'rt') as f:
    next(f) # Skip header
    for line in f:
        row = line.split(',')
        records.append((row[0], int(row[1]), float(row[2])))

把字典当作容器

如果要疾速随机查找(通过键名),那么字典很有用。例如,股票价格字典:

prices = {
   'GOOG': 513.25,
   'CAT': 87.22,
   'IBM': 93.37,
   'MSFT': 44.12
}

以下是一些简略的查找:

>>> prices['IBM']
93.37
>>> prices['GOOG']
513.25
>>>

字典构建

从零开始构建字典的示例:

prices = {} # Initial empty dict

# Insert new items
prices['GOOG'] = 513.25
prices['CAT'] = 87.22
prices['IBM'] = 93.37

从文件内容填充字典的示例:

prices = {} # Initial empty dict

with open('Data/prices.csv', 'rt') as f:
    for line in f:
        row = line.split(',')
        prices[row[0]] = float(row[1])

留神:如果是在 Data/prices.csv 文件上尝试此操作,会发现简直能够失常工作——然而,在开端有一个空行导致程序解体了。须要找出一些办法来批改代码以解决此问题(参见练习 2.6)。

字典查找

测试键是否存在:

if key in d:
    # YES
else:
    # NO

能够查找可能不存在的值,并在值不存在的状况下提供默认值。

name = d.get(key, default)

示例:

>>> prices.get('IBM', 0.0)
93.37
>>> prices.get('SCOX', 0.0)
0.0
>>>

组合键

在 Python 中,简直任何类型的值都能够用作字典的键。字典的键必须是不可变类型。例如,元组:

holidays = {(1, 1) : 'New Years',
  (3, 14) : 'Pi day',
  (9, 13) : "Programmer's day",
}

而后拜访:

>>> holidays[3, 14]
'Pi day'
>>>

列表,汇合或者其它字典都不能用作字典的键,因为列表和字典(译注:汇合也是应用哈希技术实现的)是可变的。

汇合

汇合是互异且无序的数据。

tech_stocks = {'IBM','AAPL','MSFT'}
# Alternative syntax
tech_stocks = set(['IBM', 'AAPL', 'MSFT'])

汇合对于成员关系测试很有用。

>>> tech_stocks
set(['AAPL', 'IBM', 'MSFT'])
>>> 'IBM' in tech_stocks
True
>>> 'FB' in tech_stocks
False
>>>

汇合对于打消反复也很有用。

names = ['IBM', 'AAPL', 'GOOG', 'IBM', 'GOOG', 'YHOO']

unique = set(names)
# unique = set(['IBM', 'AAPL','GOOG','YHOO'])

其它汇合操作:

names.add('CAT')        # Add an item
names.remove('YHOO')    # Remove an item

s1 | s2                 # Set union
s1 & s2                 # Set intersection
s1 - s2                 # Set difference

练习

在这些练习中,你开始构建的程序是本课程残余局部应用的次要程序之一。请在 Work/report.py 文件中工作。

练习 2.4:蕴含元组的列表

Data/portfolio.csv 文件蕴含投资组合中的股票列表。在 练习 1.30 中,你编写了一个读取该文件并执行简略计算的 portfolio_cost(filename) 函数。

代码看起来应该像上面这样:

# pcost.py

import csv

def portfolio_cost(filename):
    '''Computes the total cost (shares*price) of a portfolio file'''
    total_cost = 0.0

    with open(filename, 'rt') as f:
        rows = csv.reader(f)
        headers = next(rows)
        for row in rows:
            nshares = int(row[1])
            price = float(row[2])
            total_cost += nshares * price
    return total_cost

请应用这些代码作为领导,创立一个新文件 report.py。在 report.py 文件中,定义 read_portfolio(filename) 函数,该函数关上 Data/portfolio.csv 文件并将其读入到蕴含元组的列表中。为此,你须要对下面的代码做一些小批改。

首先,创立一个最后设为空列表的变量,而不是定义 total_cost = 0。例如:

portfolio = []

接着,把每一行精确地存储到元组中(就像在上次的练习中做的那样),而后把元组追加到列表中,而不是共计总的费用。

for row in rows:
    holding = (row[0], int(row[1]), float(row[2]))
    portfolio.append(holding)

最初,返回失去的 portfolio 列表。

请交互式地试验函数(揭示,要执行此操作,首先须要在解释器运行 report.py 程序)。

提醒:当在终端执行文件的时候,请应用 -i 参数。

>>> portfolio = read_portfolio('Data/portfolio.csv')
>>> portfolio
[('AA', 100, 32.2), ('IBM', 50, 91.1), ('CAT', 150, 83.44), ('MSFT', 200, 51.23),
    ('GE', 95, 40.37), ('MSFT', 50, 65.1), ('IBM', 100, 70.44)]
>>>
>>> portfolio[0]
('AA', 100, 32.2)
>>> portfolio[1]
('IBM', 50, 91.1)
>>> portfolio[1][1]
50
>>> total = 0.0
>>> for s in portfolio:
        total += s[1] * s[2]

>>> print(total)
44671.15
>>>

创立的蕴含元组的列表十分相似于二维(2-D)数组。例如,应用诸如 portfolio[row][column]rowcolumn 是整数)的查找来拜访特定的列和行。

也就是说,能够应用像上面这样的语句重写最初的 for 循环:

>>> total = 0.0
>>> for name, shares, price in portfolio:
            total += shares*price

>>> print(total)
44671.15
>>>

练习 2.5:蕴含字典的列表

应用字典(而不是元组)批改在练习 2.4 中编写的函数来示意投资组合中的股票。在字典中,应用字段名 “name”, “shares” 和 “price” 来示意输出文件中的不同列。

以与练习 2.4 中雷同的形式试验这个新的函数。

>>> portfolio = read_portfolio('Data/portfolio.csv')
>>> portfolio
[{'name': 'AA', 'shares': 100, 'price': 32.2}, {'name': 'IBM', 'shares': 50, 'price': 91.1},
    {'name': 'CAT', 'shares': 150, 'price': 83.44}, {'name': 'MSFT', 'shares': 200, 'price': 51.23},
    {'name': 'GE', 'shares': 95, 'price': 40.37}, {'name': 'MSFT', 'shares': 50, 'price': 65.1},
    {'name': 'IBM', 'shares': 100, 'price': 70.44}]
>>> portfolio[0]
{'name': 'AA', 'shares': 100, 'price': 32.2}
>>> portfolio[1]
{'name': 'IBM', 'shares': 50, 'price': 91.1}
>>> portfolio[1]['shares']
50
>>> total = 0.0
>>> for s in portfolio:
        total += s['shares']*s['price']

>>> print(total)
44671.15
>>>

在这里能够看到,每个条目标不同字段是通过键名来拜访的,而不是数字类型的列号。这通常是首选形式,因为这样失去的代码在当前易于浏览。

查看大型的字典或者列表可能会很凌乱。要使调试的输入变得整洁,能够思考应用 pprint() 函数。

>>> from pprint import pprint
>>> pprint(portfolio)
[{'name': 'AA', 'price': 32.2, 'shares': 100},
    {'name': 'IBM', 'price': 91.1, 'shares': 50},
    {'name': 'CAT', 'price': 83.44, 'shares': 150},
    {'name': 'MSFT', 'price': 51.23, 'shares': 200},
    {'name': 'GE', 'price': 40.37, 'shares': 95},
    {'name': 'MSFT', 'price': 65.1, 'shares': 50},
    {'name': 'IBM', 'price': 70.44, 'shares': 100}]
>>>

练习 2.6:把字典当作容器

在应用索引而不是数字查找某元素的中央,字典是一种用来跟踪元素的很有用的形式。在 Python shell 中,尝试应用字典:

>>> prices = { }
>>> prices['IBM'] = 92.45
>>> prices['MSFT'] = 45.12
>>> prices
... look at the result ...
>>> prices['IBM']
92.45
>>> prices['AAPL']
... look at the result ...
>>> 'AAPL' in prices
False
>>>

Data/prices.csv 文件蕴含一系列带有股票价格的行,看起来像上面这样:

"AA",9.22
"AXP",24.85
"BA",44.85
"BAC",11.27
"C",3.72
...

编写 read_prices(filename) 函数将诸如此类的价格汇合读取到字典中,字典的键代表股票的名字,字典的值代表股票的价格。

为此,从空字典开始,并且像下面做的那样开始插入值。然而,当初正在从从文件中读取值。

咱们将应用该数据结构疾速查找给定名称的股票的价格。

这部分须要一些小技巧。首先,确保像之前做的那样应用 csv 模块——无需在这里反复创造轮子。

>>> import csv
>>> f = open('Data/prices.csv', 'r')
>>> rows = csv.reader(f)
>>> for row in rows:
        print(row)


['AA', '9.22']
['AXP', '24.85']
...
[]
>>>

另外一个小麻烦是 Data/prices.csv 文件可能有一些空行在外面。留神下面数据的最初一行是一个空列表——象征在那一行没有数据。

这有可能导致你的程序因为异样而终止。酌情应用 tryexcept 语句捕捉这些异样。思考:应用 if 语句来防备谬误的数据是否会更好?

编写完 read_prices() 函数,请交互式地测试它并确保其失常工作:

>>> prices = read_prices('Data/prices.csv')
>>> prices['IBM']
106.28
>>> prices['MSFT']
20.89
>>>

练习 2.7:看看你是否能够退休

通过增加一些计算盈亏的语句到 report.py 程序,将所有的工作分割到一起。这些语句应该采纳在练习 2.5 中存储股票名称的列表,以及在练习 2.6 中存储股票价格的字典,并计算投资组合的以后值以及盈亏。

目录 | 上一节 (2.1 数据类型) | 下一节 (2.3 格式化)

注:残缺翻译见 https://github.com/codists/practical-python-zh

退出移动版