Python学习笔记(6)

装饰器

原始的装饰器模式

  • 下面的实例是在函数 f1 执行前打印一个时间
1
2
3
4
5
6
7
8
9
10
def decorator(func):
def wrapper():
print(time.time())
func()
return wrapper

def f1():
print('hello world')

decorator(f1)()

Python 中对于装饰器的语法糖

1
2
3
4
5
6
7
8
9
10
11
def decorator(func):
def wrapper():
print(time.time())
func()
return wrapper

@decorator
def f1():
print('hello world')

f1()

带参数的装饰器

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
41
42
43
44
45
46
47
def decorator(func):
def wrapper(func_name):
print(time.time())
func(func_name)
return wrapper

@decorator
def f1(func_name):
print('hello world' + func_name)

f1("ljl")

# 支持不同参数个数
import time

def decorator(func):
def wrapper(*args):
print(time.time())
func(*args)
return wrapper

@decorator
def f1(func_name):
print('hello world' + func_name)

@decorator
def f2():
print('hello world')

f1("ljl")
f2()

# 带关键字参数
def decorator(func):
def wrapper(*args, **kw):
print(time.time())
func(*args, **kw)
return wrapper

@decorator
def f3(func_name, **kw):
print('hello world' + func_name)
print(kw)

f1("ljl")
f2()
f3("ljl", a = 1, b = 2, c = 'ljl')
  • 调用一个函数,如果不知道函数的参数,都可以用func(*args, **kw)这种形式调用,因此为了通用,装饰器的内部函数wrapper的参数就可以为这种形式

装饰器带有参数

  • 如果装饰器带有参数,可以再在外面套一层函数
1
2
3
4
5
6
7
8
9
10
11
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator

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

Python 的其他知识

列表推导式

  • 列表推导式类似 map 或 filter 函数,是 Python 特有的语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
a = [1, 2, 3, 4, 5, 6, 7, 8]
ret1 = [i * i for i in a]
print(ret1) # [1, 4, 9, 16, 25, 36, 49, 64]
ret2 = [i * i for i in a if i >= 5]
print(ret2) # [25, 36, 49, 64]
a1 = {1, 2, 3, 4}
ret3 = {i * i for i in a1}
print(ret3) # {16, 1, 4, 9}

students = {
'ljl': 12,
'lyb': 20,
'aaa': 11
}
ret4 = [key for key, value in students.items()]
print(ret4) # ['ljl', 'lyb', 'aaa']
ret5 = {value: key for key, value in students.items()}
print(ret5) # {12: 'ljl', 20: 'lyb', 11: 'aaa'
ret6 = (key for key, value in students.items()) # 得到的是一个generator

迭代器与生成器

迭代器

  • 可迭代对象,可以被 for-in 遍历的对象,list, set 等
  • 迭代器,是一个对象
  • 迭代器有一次性的特征,只能遍历一次
  • 迭代器一定是一个可迭代对象,但是可迭代对象不一定是迭代器,例如 list 是可迭代对象,但 list 不是迭代器,因为 list 可以重复遍历
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
# BookCollection就是一个自定义的可迭代对象
class BookCollection:
def __init__(self):
self.data = ["aaa", "bbb", "ccc"]
self.cur = 0

def __iter__(self):
return self

def __next__(self):
if self.cur >= len(self.data):
raise StopIteration()
r = self.data[self.cur]
self.cur += 1
return r

books = BookCollection()
for b in books:
print(b)

for b in books:
print(b)

# 只会打印一次,第二次遍历无效,解决方法:
# 1. 重新创建一个BookCollection对象
# 2. copy

解决只能遍历一次的问题

1
2
3
4
5
6
7
8
9
10
11
12
import copy
books_copy = copy.copy(books) # 浅复制
books_copy2 = copy.deepcopy(books) # 深复制

for b in books:
print(b)

for b in books_copy:
print(b)

for b in books_copy2:
print(b)

生成器

  • 生成器是一个函数,主要是为了解决遍历时内存消耗过大的问题
1
2
3
4
5
6
7
8
9
10
11
def gen(max):
n = 0
while n <= max:
n += 1
yield n # 返回n,每次调用next接着这里执行

g = gen(10000)
print(next(g)) # 1
print(next(g)) # 2
print(next(g)) # 3
print(next(g)) # 4

None

  • None 表示空,不等于空字符串,空列表,false,0,如果是从类型还是比较运行算上都不相等
  • None 在作为条件判断时会转为 False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = []
b = False
c = 0
print(None == a) # False
print(None == b) # False
print(None == c) # False
print(a is None) # False
print(b is None) # False
print(c is None) # False

# 判断值为空
if a:
pass

if not a:
pass
  • 自定义对象参与条件判断与内置的__len____bool__方法有关
  • 不存在__bool__时会调用__len__来判断对象时 True 还是 False,__len__返回 0 或 False,则对象为 False,否则对象为 True
  • 全局 len 函数就是调用对象的__len__
  • 如果有__bool__方法,则由__bool__方法来控制对象时 True 还是 False,__bool__只能返回 Bool 类型,__len__不再被调用

装饰器的副作用

  • 添加装饰器后,函数的名字__name__会被改变
1
2
3
4
5
6
7
8
9
10
11
12
13
import time

def decorator(func):
def wrapper():
print(time.time())
func()
return wrapper

@decorator
def f1():
print(f1.__name__) # wrapper

f1()

解决办法: 使用 wraps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import time
from functools import wraps

def decorator(func):
@wraps(func)
def wrapper():
print(time.time())
func()
return wrapper

@decorator
def f1():
print(f1.__name__) # f1

f1()

错误处理

Python 中的异常

  • Exception
  • AttributeError
  • IndexError
  • KeyError
  • NameError
  • SyntaxError
  • TypeError
  • ValueError
  • ZeroDivisionError

错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
try:
a = 3 / 0
fn()
except ZeroDivisionError:
print('Division by zero')
except NameError:
print('Invalid Name')
except:
printn('Defalut handler')
else:
# 没有错误时会调用
print('No errors')
finally:
print('Clean up actions')