John | 曲

Reflection in Transition

第 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 equalityprint (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