Python学习笔记2

Python学习笔记–2.函数和高级特性

MrZigZag@Peking University

2015-07-12

1.函数

数据类型转换函数int(), float(), str(), unicode(), bool()

函数名实际上就是函数对象的引用,因此可以给函数复制给一个变量然后通过这个变量调用。相当于给函数起了个别名。

>>> a = abs
>>> a(-1)
1

自定义函数def,作为占位符可以用pass

1
2
3
4
5
6
7
def my_abs(x):
if x >= 0:
return x
else:
return -x
def my_abs2(x):
pass

参数检查可以用内置函数isinstance实现。

1
2
3
4
5
6
7
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x

返回多个值,直接在return后面加入多个值即可,实际上返回的是一个Tuple。

1
2
def move(x, y):
return 2 * x, y / 2

参数

默认参数可以简化函数调用。必选参数在前,默认参数在后,并且变化大的默认参数尽量靠前。不按顺序提供默认参数时需要把参数名写上。

def enroll(name, gender, age = 6, city = 'Beijing'):
    #do something
    pass

>>> enroll('Bob', 'M')
>>> enroll('Bob', 'M', city = 'Tianjin')

值得注意的是,默认参数有时候会让人掉坑里,例如

def add_end(L = []):
    L.append('END')
    return L

>>> add_end()
['END']
>>> add_end()
['END', 'END']

Python函数定义的时候默认参数L就被计算出来了,默认参数L是一个变量,指向[],因此每一调用就改变了[],下次调用还是指向这个位置,但是内容已经发生改变。因此,默认参数必须指向不变对象。以上例子可以用None这个不变对象来实现。

def add_end(L = None):
    if L is None:
        L = []
    L.append('END')
    return L

可变参数*标记,可以将参数组成一个tuple然后传进去,如果参数本身是一个tuple或者list,只需在变量名前加一个*

def calc(*numbers):
    sum = 0
    for x in numbers
        sum = sum + x * x
    return sum

>>> calc(1, 2, 3)
14
>>> nums = [1, 2, 3]
>>> calc(*nums)
14

关键字参数,Python允许传入0个或者多个带参数名的参数,这些参数在函数内部会被自动组装成一个dict。关键字参数的标记符是**

def person(name, age, **kw):
    print 'name:', name, 'age:', age, 'other:', kw

>>> person('Bob', 30)
name: Bob age: 30 other: {}
>>> person('Alice', 25, city = 'Beijing', gender = 'F')
name: Alice age: 30 other: {'city':'Beijing', 'gender':'F'}

关键字参数可以扩展函数的功能。

参数组合:参数定义的顺序:必选参数,默认参数,可变参数和关键字参数。对于任意函数,无论它的参数是如何定义的,均可以通过类似func(*args, **kw)的形式调用它。

def func(a, b, c = 0, *args, **kw):
    print 'a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw

>>> func(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> func(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> args = (1, 2, 3, 4)
>>> kw = {'x': 99}
>>> func(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'x': 99}

2.切片Slice

切片可以将按照不同的间隔将一个list或者tuple切成多段,是批量操作元素的手段。类似于Matlab中的用法。

L[0:3]表示从0开始到3为止,但是不包含3,因此有3-0=3个元素。第一个元素是0时可以忽略。L[:3]

倒数元素也支持切片,如L[-3:-1],或者L[-3:]

默认间隔是1,也可以修改成其他间隔。L[:10:2]甚至L[::2]。什么都不写时表示直接复制,如L[:]

对Tuple做切片之后得到的仍然是tuple。

有了切片,很多循环都可以直接用切片来完成。

3.迭代

任何可迭代对象都可以用for循环,包括我们自定义的类型。

对dict的迭代,直接用for key in d迭代key,如果要迭代value,用for value in d.itervalues(),一起则用for key, value in d.iteritems()

对字符串也可以迭代。for ch in 'ABC'

判断是否可迭代,用collections模块的Iterable类型来判断。

from collections import Iterable
isinstance('abc', Iterable)

enumerate(li)可将一个list转换成一个索引-元素对。这样就可以用下标进行索引。

for i, value in enumerate(['A', 'B', 'C']):
    print i, value

4.列表生成式

可以快速生成一个list,或者由一个list导出另一个list,代码简洁易懂。

最简单的列表生成方法是range(a, b)方法。但是复杂的生成式要用for循环。

>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

for之后还可以加入if进行条件判断。

>>> [x * x for x in range(1, 11) if x % 2]
[1, 9, 25, 49, 81]

还可以直接多层循环。

>>> [x + y for x in 'ABC' for y in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
>>> L = ['Hello', 'World', 'IBM']
>>> [ch for word in L for ch in word]
['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', 'I', 'B', 'M']

5.生成器Generator

类似于列表生成式,但是一边运算一边生成元素。不必一下子生成一整个list,可以节约大量的空间。

生成器的构造方法类似于列表生成器,只需将[]改成()。调用下一个元素可以用g.next(),但是因为生成器是可迭代的,一般都直接用for。

如果推算算法比较复杂还可以直接用函数来实现,具体的细节是在返回的地方加入field,运行到此处会返回一个数作为输出,下次调用.next()时直接回到field处继续执行。

1
2
3
4
5
6
def fib(num):
n, a, b = 0, 1, 1
while n < num:
yield b
a, b = b, a + b
n = n + 1