Python学习之四 装饰器
1. 装饰器:
2. 本质是函数 ,功能(装饰其他函数)就是为其他函数添加附加功能
3. 原则
1. 不能修改被装饰得函数的源代码
2. 不能修改被装饰的函数的调用方式
4 实现装饰器知识储备:
1.函数即变量
2.高阶函数
3.嵌套函数
高阶函数+嵌套函数= 装饰器
在函数体内用def去声明一个新的函数而不是调用
函数即变量
def bar():
print('in the bar')
def foo():
print('in the foo')
bar()
foo()
def foo():
print('in the foo')
bar()
def bar():
print('in the bar')
foo()
高阶函数
a: 把一个函数名当做实参传给另一个函数(不修改被装饰函数源代码的情况下为其添加功能)
b: 返回值中包含函数名(不修改函数的调用方式)
import time
def bar():
time.sleep(2)
print(' in the >>> bar')
def test1(func):
star_time = time.time()
print(func)
func()
stop_time = time.time()
print('the func run time is %s' %(stop_time-star_time))
test1(bar)
b: 返回值中包含函数名(不修改函数的调用方式)
def bar():
time.sleep(2)
print('in the bar')
def test2(func):
print(func)
return func
bar = test2(bar)
bar()
嵌套函数
def foo():
print('in the bar')
def bar():
print('in the bar')
bar()
foo()
装饰器(1)
user,passwd = 'scott','abc123'
def auth(func): # 装饰
def wrapper(*args, **kwargs): #内嵌
print('wrapper func args:', *args, **kwargs)
username = input('username:').strip()
password = input('password').strip()
if user == username and passwd == password:
print('\033[32;1m user has passed\033[0m')
res = func(*args, **kwargs)
print('----after---')
return res
else:
exit('\033[32;1m error \033[0m')
return wrapper
def index():
print('welcom to index page')
@auth
def home():
print('welcome to home')
return "from home"
@auth
def bbs():
print('welcom to bbs')
index()
print(home())
bbs()
装饰器(2
user,passwd = 'scott','abc123'
def auth(auth_type): # 装饰
print('auth func',auth_type)
def outer_wrapper(func): # 原来这里是第一层了 但是有了上一个 就往下移了一层
def wrapper(*args, **kwargs): # 内嵌
print('wrapper func args:', *args, **kwargs)
username = input('username:').strip()
password = input('password').strip()
if user == username and passwd == password:
print('\033[32;1m user has passed\033[0m')
res = func(*args, **kwargs)
print('----after---')
return res
else:
exit('\033[32;1m error \033[0m')
return wrapper
return outer_wrapper
def index():
print('welcom to index page')
@auth(auth_type='local') # (auth_type='ldap')这里的参数直接传给auth(auth_type)
def home():
print('welcome to home')
return "from home"
@auth(auth_type='ldap') # (auth_type='ldap')这里的参数直接传给auth(auth_type)
def bbs():
print('welcom to bbs')
index()
print(home())
bbs()
装饰器(3)
user,passwd = 'scott','abc123'
def auth(auth_type): # 装饰
print('auth func',auth_type)
def outer_wrapper(func): # 原来这里是第一层了 但是有了上一个 就往下移了一层
def wrapper(*args, **kwargs): # 内嵌
print('wrapper func args:', *args, **kwargs)
if auth_type == 'local':
username = input('username:').strip()
password = input('password').strip()
if user == username and passwd == password:
print('\033[32;1m user has passed\033[0m')
res = func(*args, **kwargs)
print('----after---')
return res
else:
exit('\033[32;1m error \033[0m')
elif auth_type == 'ldap':
print('buhui')
return wrapper
return outer_wrapper
def index():
print('welcom to index page')
@auth(auth_type='local') # (auth_type='ldap')这里的参数直接传给auth(auth_type)
def home():
print('welcome to home')
return "from home"
@auth(auth_type='ldap') # (auth_type='ldap')这里的参数直接传给auth(auth_type)
def bbs():
print('welcom to bbs')
index()
print(home())
bbs()
迭代器和生成器
列表生成式 使代码更简洁
a = [1,2,3]
a = []
for i in range(10):
a.append(i*2)
a = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 这种方式直接生成到内存里面
[ i*2 for i in range(10)] 一句顶三句
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
只有调用的时候才会生成相应的数据 不使用就不会生成数据 不能使用切片,下标的方式取数据 只能一个一个的取
b = ( i*2 for i in range(100000000))
for i in b:
print(i)
可以使用__next__() 方法取值 只记住当前位置 只保留一个位置,只能向后走不能向前回去
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,
创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,
那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b # a = b b=a + b
n = n + 1
return 'done'
fib(10)
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,
推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
# print(b)
yield b
a, b = b, a + b # a = b b=a + b
n = n + 1
return 'done'
f = fib(10)
print(f.__next__())
print(f.__next__())
print("=====start loop====")
for i in f:
print(i)
可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator
function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。 可循环的对象
可以使用isinstance()
判断一个对象是否是Iterable对象:
from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用
并不断返回下一个数据,直到没有数据时抛出StopIteration错误。
可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,
只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,
只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
f.readlines 一行一行的读,把每一行当做一个列表
for line in f # 每一次print line就是取迭代一次next方法
josn
import json
把字典以json的方式存到test文件里面 内容为{"name": "scott", "age": 22}
info = {
'name' : 'scott',
'age' : 22
}
f = open('test','w')
print()
f.write(json.dumps(info))
f.close()
读取test文件里面的字典内容 结果会输出 22
import json
f = open('test','r')
date = json.loads(f.read())
print(date['age'])
import pickle
def sayhi(name):
print("hello,", name)
info = {
'name': 'scott',
'age': 22,
'func': sayhi
}
f = open("test.text", "wb")
pickle.dump(info, f) # f.write( pickle.dumps( info) ) 是一样的
f.close()
import pickle
def sayhi(name):
print("hello2,", name)
f = open("test.text", "rb")
data = pickle.load(f) # data = pickle.loads(f.read())
print(data["func"]("scott"))
3.0 能dump好多次
但是不能load多次 只能是一次
所以以后使用的时候要做到 dump一次load一次
#import json
import pickle
def sayhi(name):
print("hello,",name)
info = {
'name': 'scott',
'age': 22,
'func': sayhi
}
f = open("test.text","wb")
# print(json.dumps(info)) 使用json只能处理简单的数据类型 列表,字典,字符串 所以无法处理函数只能使用pickle
f.write(pickle.dumps(info))
f.close()
import pickle # pickle只能序列化Python 其他的不行比如Java 它只认识json
def sayhi(name):
print("hello2,",name)
f = open("test.text","rb")
data = pickle.loads(f.read())
print(data["func"]("scott"))

浙公网安备 33010602011771号