数据结构
简单介绍Python中常用的几种数据结构。
1. 列表 list
列表类似于其它编程语言里的可变数组。
标准库参考:“列表是可变序列,通常用于存放同类项目。”
1.1 列表的创建
- • 使用方括号创建空列表:
[]
- • 使用方括号,里面的项用
,
隔开:[a,b,c]
- • 使用列表推导式:
[x for x in iterable]
- • 使用构造器:
list()或list(iterable)
构造器会返回一个列表,其中的项与iterable中的项值和顺序都相同。iterable是一个可迭代对象。
1.2 列表的操作
列表是可变序列,因此它支持通用序列操作,可变序列操作。
通用序列操作:支持判断,求值等操作,但不可修改序列内容。
可变序列操作:除了通用序列操作,还支持对序列元素赋值、删除等修改操作。
列表额外方法
sort(*, key=None, reverse=False)
就地排序列表中的元素。key是有一个参数的函数,用来生成用于比较的键;reverse是True或False,表示是否反转。*
用来限定后面的参数仅能通过关键字方式传递。
lst1 = [1,2,3,7,3,4]
lst1.sort()
print(lst1)
key参数很适合用lambda表达式:
代码语言:javascript复制scores = [('a', 99), ('b', 66), ('c', 77), ('d', 88)]
scores.sort(key=lambda x: -x[1])
print(scores)
使用列表实现堆栈、队列
堆栈是一种后进先出的数据结构。可以将堆栈想象成一口井。
(堆栈:进的顺序是1,2,3,4。出的顺序是4,3,2,1。)
使用列表实现堆栈非常容易,用append()模拟进栈,pop()模拟出栈。
代码语言:javascript复制stack = [1, 2, 3]
stack.append(4)
stack.append(5)
print(stack)
stack.pop()
print(stack)
stack.pop()
stack.pop()
print(stack)
队列是一种先进先出的数据结构。相当于排队。
(队列:进的顺序1,2,3,4.出的顺序也是1,2,3,4)
可以使用append()模拟入队,pop(0)模拟出队,但是时间效率低。
一般用collections.deque
实现。append()模拟入队,popleft()模拟出队。
from collections import deque
queue = deque(["Eric", "John", "Michael"])
queue.append("Terry") # Terry arrives
queue.append("Graham") # Graham arrives
queue.popleft() # The first to arrive now leaves
queue.popleft() # The second to arrive now leaves
queue # Remaining queue in order of arrival
2. 元组
元组是不可变序列,通常用于存储多项集。或用于需要数据不可变的情况(如存储到set中)。
2.1 元组的创建
可以用多种方式构建元组:
- • 使用一对圆括号来表示空元组:
()
- • 使用一个后缀的逗号来表示单元组:
a,
或(a,)
- • 使用以逗号分隔的多个项:
a, b, c
or(a, b, c)
- • 使用内置的
tuple()
:tuple()
或tuple(iterable)
请注意决定生成元组的其实是逗号而不是圆括号。圆括号只是可选的,生成空元组或需要避免语法歧义的情况除外。例如,f(a, b, c)
是在调用函数时附带三个参数,而 f((a, b, c))
则是在调用函数时附带一个三元组。
2.2 元组的操作
元组是不可变序列,实现了所有通用序列的操作。
2.3 扩展内容:命名元组
通过名称访问相比通过索引访问更清晰,collections.namedtuple()
提供了命名元组的方法。
collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)
返回一个新的元组子类,名为 typename 。这个新的子类用于创建类元组的对象,可以通过字段名来获取属性值,同样也可以通过索引和迭代获取值。
子类实例同样有文档字符串(类名和字段名)。另外一个有用的 __repr__()
方法,以 name=value
格式列明了元组内容。
field_names 是一个像 [‘x’, ‘y’]
一样的字符串序列。 field_names 也可以是一个纯字符串,用空白或逗号分隔开元素名,比如 'x y'
或者 'x, y'
。
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y']) #namedtuple('Point', 'x, y')
p = Point(1, 2)
print(p[0] p[1])
print(p.x p.y)
命名元组尤其有用于赋值 csv
sqlite3
模块返回的元组
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
除了继承元组的方法,命名元组还支持三个额外的方法和两个属性。为了防止字段名冲突,方法和属性以下划线开始。
三个方法:
classmethod somenamedtuple._make
(iterable)
类方法从存在的序列或迭代实例创建一个新实例。
代码语言:javascript复制t = [11, 22]
Point._make(t)
somenamedtuple._asdict
()
返回一个新的 dict
,它将字段名称映射到它们对应的值:
p = Point(x=11, y=22)
p._asdict()
#{'x': 11, 'y': 22}
somenamedtuple._replace
(**kwargs)
返回一个新的命名元组实例,并将指定域替换为新的值
代码语言:javascript复制p = Point(x=11, y=22)
p._replace(x=33)
两个属性:
somenamedtuple._fields
字符串元组列出了字段名。用于提醒和从现有元组创建一个新的命名元组类型。
代码语言:javascript复制p._fields # view the field names
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields Color._fields)
Pixel(11, 22, 128, 255, 0)
somenamedtuple._field_defaults
字典将字段名称映射到默认值。
代码语言:javascript复制Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
Account._field_defaults
# {'balance': 0}
Account('premium')
# Account(type='premium', balance=0)
要获取这个名字域的值,还可以使用 getattr()
函数 :
getattr(p, 'x')
转换一个字典到命名元组,使用 ** 两星操作符
代码语言:javascript复制d = {'x': 11, 'y': 22}
Point(**d)
命名元组是一个正常的Python类,它可以很容易通过子类更改功能。
代码语言:javascript复制class Point(namedtuple('Point', ['x', 'y'])):
__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)
for p in Point(3, 4), Point(14, 5/7):
print(p)
通过直接赋值给 __doc__
属性,更改文档字符串。
Book = namedtuple('Book', ['id', 'title', 'authors'])
Book.__doc__ = ': Hardcover book in active collection'
Book.id.__doc__ = '13-digit ISBN'
Book.title.__doc__ = 'Title of first printing'
Book.authors.__doc__ = 'List of authors sorted by last name'