第 5 章 结构化类型、可变性与高阶函数
5 STRUCTURED TYPES, MUTABILITY, AND HIGHER ORDER FUNCTIONS
曲政 / 2018-04-16
5.1 Tuples
为什么说 tuples 更像 string,而不是 list?
tuple 和 string 都是
- 不可更改的
- 有序的
- 元素序列
tuple 与 string 的区别仅仅在于
- tuple 的元素可以是任何类型
- string 的元素只可以是 char
tuple 与 list 的相同点
- 有序的
- 元素序列
- 元素可以是任何类型
tuple 与 list 的区别在于
- tuple 的元素不可变更
- list 的元素可以变更
相比于元素类型,是否可变更这个属性更重要。
单个元素的 tuple 形式上怎么写?
为了与 (1)
区分,写成 (1,)
。
python 的发明人说,(1)
只是对整数 1 的废话描写,这了的括号是表达计算的先后顺序。加了逗号才是 tuple 的定义符号。
tuple 与多元素赋值相结合,用在哪里?
1 拆分绑定
a, b, c = 'xyz'
2 函数返回值
调用函数是一个 expression,只能 evaluate 成一个 object,所以打包成 tuple 类型。
def somefunction:
return (minVal, maxVal)
5.2 Ranges
range 只有一个参数时怎么理解?
当作 stop,它不可缺省。
range 与 tuple 有什么异同?
同:都 immutable。
异:range 占用空间与长度无关,只由 `start, stop, step 所定义,只占很小的空间。
range 的应用场景?
最常用在 for
语句中。
for i in range (3, 20, 5):
...
也可以用在其他需要整数序列的代码中。
5.3 List and Mutability
list 的 []
可能有歧义吗?要紧吗?
式 [1,2,3,4][1:3][1]
中的 []
分别是三个含义:
- 定义 list
- 提取 slice
- index 元素
不要紧,因为通常情况下,list 都是增量定义使用,很少有形式上一次定义完整。
两种 equality?
- value equality
print (Univs == Univs1)
- object equality
print (id (Univs) == id (Univs1))
The sementics of Python says that no twe objects have the same identifier.
什么是 mutablity 和 side effect?
list 的元素可以被改变,有时是被某个操作所改变,这种性质被称作是 mutability。
并不是将改变之后的内容创建为一个新对象返回,而是直接更改原始对象,这种操作被称为有 side effect。
['MIT', 'Caltech'].append ('RPI')
而 +
就没有 side effects,它会创建一个新 list。
什么是 aliasing 别名使用?
同一个对象,有多个 varialbe 指向途径。
这个程序为什么有 semantic 错误?
def remove_duplicates (L1, L2):
"""Assumes that L1 and L2 are lists.
Removes any element from L1 that also occurs in L2."""
for e1 in L1:
if e1 in L2:
L1.remove (e1)
def test_remove_duplicates ():
L1 = [1, 2, 3, 4]
L2 = [1, 2, 5, 6]
remove_duplicates (L1, L2)
print ("L1 =", L1)
test_remove_duplicates ()
结果不是
L1 = [3, 4])
而是
L1 = [2, 3, 4])
因为for e1 in L1
是按 L [0] L [1] L [2] L [3] 的顺序来提取 L1 中的元素,赋给 e1。但是当 L1 的第一个元素被删除,2 成为 L [0] 之后,for 语句仍然提取 L [1],那是“3”。
怎么办呢?
给 L1 做个 clone,让 for 语句从 L1 的不变 clone 里面提取元素。
有三种写法 - cloneL1 = L1 [:] - cloneL1 = list (L1) - cloneL1 = copy.deepcopy (L1) 当 L1 中元素 mutable,也需要 clone 的时候。
然后写
for e1 in cloneL1:
什么是 list comprehension?
把 list 中的每个元素都做一个操作或者筛选,写在一句话里。
比如:
L = [x**2 for x in range (1, 7)]
print (L)
mixed_list = [1, 2, 'a', 3, 4.0]
print ([x**2 for x in mixed_list if type (x) == int])
为什么提倡慎用 list comprehension 这种聪明?
in marvelous and subtle ways
别人还要读呢,“显得聪明” 不是目的。
5.4 Functions as Objects
function 也是对象吗?
是头等对象,first-class objects。
有自己的类型 <type 'built-in_function_or_method'>
。
可以像其他类型一样,用在各种地方。
function 作为 arguments 有什么特别称呼?
higher-order programming
采用 function 作为 arguments 的函数,被称为 higher-order,因为它的一个参数本身就是函数。
举个例子,类似于内置函数 map
import em_4_3_factorial
import em_4_3_fibonacci
def apply_to_each (l, f):
"""Assumes l is a list, f a function.
Mutates l by replacing each element, e, of l by f (e)"""
for i in range (len (l)):
l [i] = f (l [i])
def test_apply_to_each ():
l = [1, -2, 3.33]
print ('l =', l)
print ('Apply abs to each element of l.')
apply_to_each (l, abs)
print ('l =', l)
print ('Apply int to each element of l.')
apply_to_each (l, int)
print ('l =', l)
print ('Apply factorial to each element of l.')
apply_to_each (l, em_4_3_factorial.factRecursion)
print ('l =', l)
print ('Apply Fibonnaci to each element of l.')
apply_to_each (l, em_4_3_fibonacci.fib)
print ('l =', l)
lambda expression 的用武之地?
作为高阶函数的 argument,用 lambda 表达式,构建一个未命名函数。如下例所示。
li = []
for i in map (lambda x, y: x**y, [1, 2, 3, 4], [3, 2, 1, 0]):
li.append (i)
print (li)
结果是:
[1, 4, 3, 1]
5.5 Strings, Tuples, Ranges, and Lists
Strings, Tuples, Ranges, and Lists 的异同之处
相同之处:都是有序集合,可以做下列操作。
seq [i]
len (seq)
seq1 + seq2
n*seq
seq [start:end]
e in seq
e not in seq
for e in seq
类似与不同之处
Type | Type of elements | Examples of literals | Mutable |
---|---|---|---|
str | characters | '', 'a', 'abc' |
No |
tuple | any type | (), (3,), ('abc', 4) |
No |
range | integers | range (10), range (1, 10, 2) |
No |
list | Any type | [], [3], ["abc", 4] |
Yes |
list 与 tuple 相比,各自优点?
list 可以变更,方便追加元素。
tuple 不可变更,就不必担心 aliasing,还可以作为 dict 的 key。
string 的好处?
虽然不像 list 和 tuple 那样灵活,但是有很多 method 处理 string,让生活更美好。况且他们都没有 side effect,他们都有返回值。
s.count (s1)
s.find (s1) # return -1, if s1 not in s.
s.rfind (s1)
s.index (s1) # raise an exception, if s1 not in s.
s.rindex (s1)
s.lower ()
s.replace (old, new)
s.rstrip ()
s.split (d) # default with arbitary strings of whitespace characters.
5.6 Dictionaries
dict 与 list 有什么异同?
dict 类似于 list,values 可以是任何类型。
dict 通过 keys 索引,list 通过 index 索引。
dict 查找不需要遍历,与容量无关。
dict 的 keys 是 hashtable type 的对象,必须满足哪两点?
- 这个对象可以用__hash__方法映射到一个整数对象,在它的整个生命周期里,__hash__返回的值都不变。
- 这个对象可以用__eq__验证唯一性。
所有 Python 内置类型中,immutalbe 都是 hashtable,mutable 都不是 hashtable。
d.keys () d.values () 返回的是什么对象?
a view object, 是 dict_keys 和 dict_values 类型。
动态的,原始对象变了,它也有所显示。
常用 dict 操作?
len(d)
d.keys()
d.values()
k in d
d[k]
d.get(k, v) # returns d [k] if k in d, and v otherwise.
d[k] = v
del d[k]
for k in d