Loading

3 第三章 内建数据结构、函数及文件

Python编程:从入门到实践

元组

可以使用tuple函数将任意序列或迭代器转换为元组;
可以使用+号连接元组来生成更长的元组;
将元组乘以整数,则会生成含有多份拷贝的元组

元组拆包

In[15]: tup = (4, 5, 6)
In [16]: a, b, c = tup
In[17]: b
0ut[17]: 5

交换变量名:

In[21]:a, b = 1, 2
In [24]:b, a = a, b

遍历元组或列表组成的序列:

seq = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
for a, b, c in seq:
    print(f'a={a}, b={b}, c={c}')

多个元素:

values = 1, 2, 3, 4, 5
a, b, *rest = values
a
b
rest

Python编程者会使用下划线来表示不想要的变量:

a, b, *_ = values

一个常见的有用方法是count(列表中也可用),用于计量某个数值在元组中出现的次数:

a = (1, 2, 2, 2, 3, 4, 2)
a.count(2)

列表

list函数在数据处理中常用于将迭代器或者生成器转化为列表:

gen = range(10)
gen
list(gen)

与元组类似,两个列表可以使用+号连接:

[4, None, "foo"] + [7, 8, (2, 3)]

可以用extend方法向原列表添加多个元素:

x = [4, None, "foo"]
x.extend([7, 8, (2, 3)])
x

在你需要构建一个大型列表时,使用extend将元素添加到已经存在的列表是更好的方式。
soxt有一些选项偶尔会派上用场。
其中一项是传递一个二级排序key一个用于生成排序值的函数。
例如,我们可以通过字符串的长度进行排序:

b = ["saw", "small", "He", "foxes", "six"]
b.sort(key=len)
b

bisect.bisect会找到元素应当被插入的位置,并保持序列排序;
bisect.insort将元素插入到相应位置:

import bisect
c = [1, 2, 2, 2, 3, 4, 7]
bisect.bisect(c,2)
bisect.bisect(c, 5)
bisect.insort(c, 6)
c

切片:
切片可以将序列赋值给变量:

seq[3:5] = [6, 3]
seq
# 将位置为3处的值换为6, 3

元素的数量是stop-start
步进值step可以在第二个冒号后面使用,意思是每隔多少个数取一个值:

seq[::2]

当需要对列表或元组进行翻转时,可将步进值设置为-1:

seq[::-1]

内建序列函数

enumerate

索引, 值

some_list = ['foo', 'bar', 'baz']
mapping = {}
for i,v in enumerate(some_list):
    mapping[v] = i
mapping

sorted

sorted([7, 1, 2, 6, 0, 3, 2])
sorted('horse race')

zip

zip将列表、元组或其他序列的元素配对,新建一个元组构成的列表:

seq1 = ["foo", "bar", "baz"]
seq2 = ["one", "two", "three"]
zipped = zip(seq1, seq2)
list(zipped)

output:[('foo', 'one'), ('bar', 'two'), ('baz', 'three')]

zip可以处理任意长度的序列,它生成列表长度由最短的序列决定
zip的常用场景为同时遍历多个序列,有时候会和enumerate同时使用:

seq1 = ["foo", "bar", "baz"]
seq2 = ["one", "two", "three"]
for index, (a, b) in enumerate(zip(seq1, seq2)):
    print(f"{index}: {a}, {b}")

output:
0: foo, one
1: bar, two
2: baz, three

将行的列表转换为列的列表:

pitchers = [('Nolan','Ryan'),('Roger','Clemens'),
            ('Schilling','Curt')]
first_names,last_names = zip(*pitchers)

first_names
output: ('Nolan', 'Roger', 'Schilling')
last_names
output: ('Ryan', 'Clemens', 'Curt')

reversed

reversed函数将序列的元素倒序排列:

list(reversed(range(10)))

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

字典

dict(字典)的常用的名字是 哈希表 或者 关联数组
可以使用update方法将两个字典合并:

d1 = {"a": "some value", "b": [1, 2, 3, 4]}
d1.update({"b": "foo", "c": 12})
d1

若有相同的键,则原有的值会被覆盖

从序列生成字典, 可向字典传递元组:

tuples = zip(range(5), reversed(range(5)))
list(tuples)
mapping = dict(tuples)
mapping

默认值

words = ["apple", "bat", "bar", "atom", "book"]
by_letter = {}

for word in words:
    letter = word[0]
    if letter not in by_letter:
        by_letter[letter] = [word]
    else:
        by_letter[letter].append(word)

by_letter

可使用字典的setdefault方法替换:

words = ["apple", "bat", "bar", "atom", "book"]
by_letter = {}
for word in words:
    letter = word[0]
    by_letter.setdefault(letter, []).append(word)
by_letter

还可使用defaultdict类:

from collections import defaultdict
by_letter = defaultdict(list) # 传入类型
words = ["apple", "bat", "bar", "atom", "book"]
for word in words:
    by_letter[word[0]].append(word)

有效的字典键类型

字典中的键必须是不可变的对象,比如标量类型(整数、浮点数、字符串)或元组(且元组内对象也必须是不可变对象);
通过hash函数可以检查一个对象是否可以哈希化(即是否可以用作字典的键):
img
为了将列表作为键,一种方式就是将其转换为元组

集合

集合是一种无序且元素唯一的容器。

set([2, 2, 2, 1, 3, 3])
{2, 2, 2, 1, 3, 3}

集合支持数学上的集合操作,例如联合、交集、差集、对称差集。
并集:

a.union(b)
a | b

交集:

a.intersection(b)
a & b

Python集合操作:
img
img
集合的元素必须是不可变的,如果想要包含列表型的元素,必须先转换为元组。
检查一个集合是否是另一个结合的子集(包含于)或超集(包含):

a_set = {1, 2, 3, 4, 5}
{1, 2, 3}.issubset(a_set)
a_set.issuperset({1, 2, 3})

当且仅当两个集合的内容一模一样时,两个集合才相等:

{1, 2, 3} == {3, 2, 1}

列表、集合和字典的推导式

给定一个字符串列表,我们可以过滤出长度大于2的,并且将字母改为大写:

strings = ["a", "as", "bat", "car", "dove", "python"]
[x.upper() for x in strings if len(x) > 2]

如果有一个字符串的列表,假设我们想要一个集合,集合里包含列表中字符串的长度,我可以通过集合推导式很方便地实现:

unique_lengths = {len(x) for x in strings}
unique_lengths

也可以使用map函数:

strings = ["a", "as", "bat", "car", "dove", "python"]
set(map(len, strings))

创建一个将字符串与其位置相匹配的字典:

strings = ["a", "as", "bat", "car", "dove", "python"]
loc_mapping = {value: index for index, value in enumerate(strings)}
loc_mapping

嵌套列表推导式

想要获得一个列表包含所有含有2个以上字母的名字:
for循环:

all_data = [["John", "Emily", "Michael", "Mary", "Steven"],
            ["Maria", "Juan", "Javier", "Natalia", "Pilar"]]
names_of_interest = []
for names in all_data:
    enough_as = [name for name in names if name.count("a") >= 2]
    names_of_interest.extend(enough_as)
names_of_interest

可使用嵌套列表推导式替换:

all_data = [["John", "Emily", "Michael", "Mary", "Steven"],
            ["Maria", "Juan", "Javier", "Natalia", "Pilar"]]
result = [name for names in all_data for name in names
          if name.count("a") >= 2]
result

将含有整数元组的列表扁平化为一个简单的整数列表:

some_tuples = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
flattened = [x for tup in some_tuples for x in tup]
flattened

写开之后:

flattened = []

for tup in some_tuples:
    for x in tup:
        flattened.append(x)

创建了一个包含列表的列表:

some_tuples = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
[[x for x in tup] for tup in some_tuples]

函数

返回多个值

实质上是返回了一个元组,而元组之后又被拆包为多个结果变量:

def f():
    a = 5
    b = 6
    c = 7
    return a,b,c

a, b, c = f()
def f():
    a = 5
    b = 6
    C = 7
    return {'a':a, 'b':b, 'c':c}

函数是对象

去除空格,移除标点符号,调整适当的大小写:

states = ["   Alabama ", "Georgia!", "Georgia", "georgia", "FlOrIda",
          "south   carolina##", "West virginia?"]

import re

def clean_strings(strings):
    result = []
    for value in strings:
        value = value.strip()
        value = re.sub("[!#?]", "", value)
        value = value.title()
        result.append(value)
    return result

clean_strings(states)

将特定的列表操作应用到某个字符串的集合上:

states = ["   Alabama ", "Georgia!", "Georgia", "georgia", "FlOrIda",
          "south   carolina##", "West virginia?"]

def remove_punctuation(value):
    return re.sub("[!#?]", "", value)

clean_ops = [str.strip, remove_punctuation, str.title]

def clean_strings(strings, ops):
    result = []
    for value in strings:
        for func in ops:
            value = func(value)
        result.append(value)
    return result

clean_strings(states, clean_ops)

可将函数作为一个参数传给其他的函数,比如内建的map函数,它会将一个函数应用到一个序列上:

states = ["   Alabama ", "Georgia!", "Georgia", "georgia", "FlOrIda",
          "south   carolina##", "West virginia?"]

def remove_punctuation(value):
    return re.sub("[!#?]", "", value)

for x in map(remove_punctuation, states):
    print(x)

匿名(Lambda)函数

def short_function(x):
    return x * 2

equiv_anon = lambda x: x * 2

# 根据字符串中的不同字母个数进行排序
strings = ["foo", "card", "bar", "aaaa", "abab"]
strings.sort(key=lambda x: len(set(x)))
strings

柯里化:部分参数应用

def add_numbers(x,y):
    return x +y

add_five = lambda y: add_numbers(5,y)

add_five(10)
# functools模块可以使用pratial函数简化这种处理:
def add_numbers(x,y):
    return x +y
    
from functools import partial
add_five partial(add_numbers,5)

生成器

def squares(n=10):
    print(f"Generating squares from 1 to {n ** 2}")
    for i in range(1, n + 1):
        yield i ** 2

gen = squares()
gen

for x in gen:
    print(x, end=" ")

生成器表达式

gen = (x ** 2 for x in range(100))
gen

itertools模块

groupby可以根据任意的序列和一个函数,通过函数的返回值对序列中连续的元素进行分组:

import itertools
def first_letter(x):
    return x[0]

names = ["Alan", "Adam", "Wes", "Will", "Albert", "Steven"]

for letter, names in itertools.groupby(names, first_letter):
    print(letter, list(names)) # names is a generator

img

错误和异常处理

# 可以通过将多个异常类型写成元组的方式同时捕获多个异常(小括号是必不可少的):
def attempt_float(x):
    try:
        return float(x)
    except (TypeError, ValueError):
        return x

文件与操作系统

Python文件模式:
img
重要的Python文件方法或属性:
img
img
Python官方文档

posted @ 2023-05-05 13:59  Artwalker  阅读(8)  评论(0编辑  收藏  举报
Live2D