python语法(2)

map/reduce

map()函数接收两个参数,一个是函数,一个是Iterable,

map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

1
2
3
4
5
6
>>> def f(x):
... return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)#将惰性序列转换成list
[1, 4, 9, 16, 25, 36, 49, 64, 81]

reduce的用法。

reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,

这个函数必须接收两个参数:函数还有被作用的序列

reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

1
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

比方说对一个序列求和,就可以用reduce实现:

1
2
3
4
5
6
>>> from functools import reduce
>>> def add(x, y):
... return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

filter过滤函数

filter()接收一个函数和一个序列。

把传入的函数依次作用于每个元素,

然后根据返回值是True还是False决定保留还是丢弃该元素

1
2
3
4
5
def not_empty(s):
return s and s.strip()

list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
# 结果: ['A', 'B', 'C']

筛素数的方法,惰性筛选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def primes():
yield 2
it = _odd_iter() # 初始序列
while True:
n = next(it) # 返回序列的第一个数
yield n
it = filter(_not_divisible(n), it) # 构造新序列
#本质是每次it都叠加新的过滤规则,next出数之前都过滤
def _odd_iter():
n = 1
while True:
n = n + 2
yield n

def _not_divisible(n):
return lambda x: x % n > 0

迭代器后面的数根本没筛。

只是把“筛选规则”保存下来了。

等以后某个数字真正被生成时,再让它依次经过这些筛选规则。

例题,筛选回文数:

1
2
3
def is_palindrome(n):
s = str(n)
return s == s[::-1]#-1是倒序切片,s[::-1]表示将字符串s倒序排列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def int2list(n):
list = []
while n > 0:
list.append(n % 10)
n //= 10 #整除符号
return list

def is_palindrome(n):
list = int2list(n)
if len(list) == 1 :
return True

for i in range(len(list) // 2):#整除到中间即可
if list[i] != list[-i - 1]:#0与-1比较
return False

return True

sort()

sorted()函数接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

1
2
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。

1
2
3
list = [36, 5, -12, 9, -21]

keys = [36, 5, 12, 9, 21]

并按照对应关系返回list相应的元素:

1
result sort = [5, 9, -12, -21, 36]

要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True

返回函数与闭包

注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用。

另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行。

返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

如果一定要引用循环变量,

方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,

1
2
3
4
5
6
7
8
9
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs

nonlocal

内层函数引用外层函数局部变量

只读则调用正常

赋值改写则会报错,要加nonlocal x声明

使用闭包时,对外层变量赋值前,需要先使用nonlocal声明该变量不是当前函数的局部变量。

匿名函数(lambda)

1
2
3
4
5
6
def f(x):
return x * x

lambda x: x * x

#lambda后面是参数,:后面是函数。只能有一个表达式,没用return,返回值就是表达式结果

匿名函数也可以作为返回值返回

装饰器Decorator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import functools

def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper

@log
def now():
print('2015-3-25')

now()#相当于先调用wrapper里的打印日志,然后返回函数即now,然后执行

#输出
call now():
2015-3-25

三层嵌套,针对装饰器带参数的

1
2
3
4
5
6
7
8
9
10
import functools

def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@log("execute")
def now():
...

↓ 等价于

now = log("execute")(now)


第一层
log("execute")
│
│ text = "execute"
↓
返回 decorator
│
│
第二层 │ decorator(now)
│ func = 原来的 now
↓
返回 wrapper
│
│
↓
now = wrapper


之后调用:

now()
↓
wrapper()
│
├── 使用 text = "execute"
│
├── 使用 func = 原来的 now
│
└── func(*args, **kw)
↓
原来的 now()

经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'

1
2
>>> now.__name__
'wrapper'

所以要加@functools.wraps(func)

偏函数

就是制作了一个有其他默认参数的函数

1
int2 = functools.partial(int, base=2)#默认转二进制

创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数

如果不些命名参数则就是位置参数

当传入:

1
max2 = functools.partial(max, 10)

实际上会把10作为*args的一部分自动加到左边,也就是:

1
max2(5, 6, 7)

相当于:

1
2
args = (10, 5, 6, 7)
max(*args)

结果为10。

模块

和java差不多,每一个包目录下面都会有一个__init__.py的文件

要注意:

  • 模块名要遵循Python变量命名规范,不要使用中文、特殊字符;
  • 模块名不要和系统模块名冲突,最好先查看系统是否已存在该模块,检查方法是在Python交互环境执行import abc,若成功则说明系统存在此模块。

作用域

类似__xxx__这样的变量是特殊变量,比如上面的__author__,__name__

类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc等;

外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。