1.生成式:
python的生成式在一些类型相互转换的时候可以写出十分优雅的代码,如列表转换成另一个列表、字典、或元组,并且代码的执行效率也比使用for…in…循环高。
列表生成式即生成列表的生成式,可以将多行代码融合成一行。主要的作用是将其他对象转换成列表或对原来的列表进行过滤。
列表生成式的代码效率是高于多行循环结构的,原因是将原本多行代码融合一行,解释加快。
# 需求: 生成100个验证码(4个字母组成的验证码)
import string
import random
codes = []
for count in range(100):
code = "".join(random.sample(string.ascii_letters, 4))
codes.append(code)
print(codes)
# 列表生成式优化版
codes = ["".join(random.sample(string.ascii_letters, 4)) for i in range(100)]
print(codes)
# 需求: 找出1-100之间可以被3整除的数。
nums = []
for num in range(1, 101):
if num % 3 == 0:
nums.append(num)
print(nums)
# 优化版
nums = [num for num in range(1, 101) if num % 3 == 0]
print(nums)
# 集合生成式
result = {i**2 for i in range(0, 10)}
print(result)
# 字典生成式
result = {i:i**2 for i in range(10)}
print(result)
2:生成器:
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
生成器的实现有两种方法:
# 生成器实现的第一种方法: 将生成式改写成生成器(外层括号改为圆括号)
nums = (i**2 for i in range(10000))
# 生成器实现的第2种方法:yield关键字
# return: 函数遇到return就返回,return后面的代码并不会执行。
# yield:遇到yield则停止执行代码, 当再次调用next方法时,会从上次停止的地方继续执行,遇到yield停止。。。。
def login():
print('step 1') # 'step 1'
yield 1 # output 1
print('step 2')
yield 2
print('step 3')
yield 3
print('step 4')
yield 4
# 如果函数里面有yield关键字,函数的返回值就是一个生成器
g = login()
print(next(g)) #step 1 1
print(next(g)) #step 2 2
#如果认为print(next( ))比较慢,也可以通过遍历的方式解决:
# for i in range(4):
# print(next(g))
3.闭包与装饰器:
3-1:
关于闭包的三个条件:
- 函数里面嵌套函数
- 外部函数的返回值是内部函数的引用
- 内部函数可以使用外部函数的变量
示例:
def timeit(name):
def wrapper():
print('wrapper ' + name)
print('timeit')
return wrapper
in_fun = timeit(name = 'westos') # wrapper函数, in_fun实质上就是wrapper函数
in_fun() # timeit
# wrapper westos
时间戳的概念:
#import time
# start_time = time.time() # 时间戳:从1970年1.1到现在经历的秒数
# time.sleep(2)
# end_time = time.time() # 时间戳:从1970年1.1到现在经历的秒数
# print(end_time-start_time)
# print(time.time()) #1614523628.608633
3-2:
装饰器指的是为被装饰器对象添加额外功能的工具/函数。
- 装饰器: 用来装饰函数的工具。
- 功能: 在不改变源代码的情况下, 添加额外功能(eg: 计算运行时间, 记录日志,权限判断)的工具.
- 如何实现装饰器: 基于闭包
以下示例为:不改变add函数的内容,并为其增加显示函数运行时间的功能
import time
def timeit(f): # f=add
def wrapper(x, y):
start = time.time()
result = f(x, y) # f实质上是add函数
end = time.time()
print("函数运行的时间为: %.4f" %(end-start))
return result
return wrapper
@timeit # 语法糖, add=timeit(add)
def add(x, y):
return x + y
result = add(1, 3)
print(result)
装饰器模板示例:
"""
装饰器的万能模板:
from functools import wraps
def 装饰器名称(f):
@wraps(f) # 保留被装饰函数的属性信息和帮助文档
def wrapper(*args, **kwargs):
# 执行函数之前做的事情
result = f(*args, **kwargs)
# 执行函数之后做的事情
return result
return wrapper
"""
装饰器作用演示:
# 需求: 计算函数的运行时间
import time
from functools import wraps #默认情况下,有装饰器的函数在查看帮助时会显示装饰器的帮助信息,导入此模块让print()能够看见原函数的帮助信息
def timeit(f):
"""计时器的装饰器"""
@wraps(f) # 保留被装饰函数的属性信息和帮助文档
def wrapper(*args, **kwargs):
"""wrapper内部函数"""
start = time.time()
result = f(*args, **kwargs)
end = time.time()
print(f"函数{f.__name__}运行时间为{end-start}秒")
return result
return wrapper
@timeit
def login():
"""login desc"""
print('login....')
#
@timeit
def crawl():
import requests
url = 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Python.svg/1200px-Python.svg.png'
content = requests.get(url).content
with open('doc/python.png', 'wb') as f:
f.write(content)
print("下载图片成功")
# print(help(login))
# login()
crawl()
3-3:含参数的装饰器和多装饰器:
含参数的装饰器:在函数中嵌套两个内层函数,让装饰器可以传参数:
此时需要注意语法糖的过程: 先调用装饰器,遇到一个返回值后 让 login = desc(login)
import time
from functools import wraps
def timeit(args='seconds'):
def desc(f):
"""计时器的装饰器"""
@wraps(f) # 保留被装饰函数的属性信息和帮助文档
def wrapper(*args, **kwargs):
"""wrapper内部函数"""
start = time.time()
result = f(*args, **kwargs)
end = time.time()
if args == 'seconds':
print(f"函数{f.__name__}运行时间为{end-start}秒")
elif args == 'minutes':
print(f"函数{f.__name__}运行时间为{(end-start)/60}秒")
return result
return wrapper
return desc
@timeit(args='minutes') # timeit() @desc===> login=desc(login)
def login():
"""login desc"""
print('login....')
# login()
多装饰器:
需要注意:装饰器执行的顺序是由上到下,被装饰的过程是由下到上:即:
输出结果为:
is_login, 用户是否登录
is_permission, 用户是否有权限
显示所有的云主机
from functools import wraps
def is_login(f):
# @wraps(f)
def wrapper1(*args, **kwargs):
print('is_login, 用户是否登录')
result = f(*args, **kwargs)
return result
return wrapper1
def is_permission(f):
# @wraps(f)
def wrapper2(*args, **kwargs):
print('is_permission, 用户是否有权限')
result = f(*args, **kwargs)
return result
return wrapper2
# 规则: 执行装饰器内容是从上到下。 被装饰的顺序是从下到上。
@is_login # show_hosts=is_login(wrapper2) show_hosts=wrapper1
@is_permission # show_hosts = is_permission(show_hosts) show_hosts=wrapper2
def show_hosts():
print("显示所有的云主机")
"""
--: show_hosts()
1). wrapper1()
2). wrapper2()
3). show_hosts()
"""
show_hosts()
4:内置高阶函数:
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式
4-1 :
map()是 python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的object并返回
注意:map函数类似于生成器,一边循环一边计算,比较节省资源,因此其结果只保留一次;
4-2:
reduce把一个函数作用在一个序列[x1, x2, x3…]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
# 1. map函数
result = map(lambda x: x ** 2, [1, 2, 4, 5])
print(list(result)) #[1, 4, 16, 25]
result = map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6])
print(list(result)) # [5, 7, 9]
# 2. reduce函数
from functools import reduce
# (((1+2)+3)+4)+5=reduce result
result = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])
print(result) # 15
# 练习: 求1*2*..10的结果, 用reduce和匿名函数实现
result = reduce(lambda x,y: x*y, range(1, 11))
print(result)
# 3. filter:筛选
# 筛选所有的偶数
result = filter(lambda x: x % 2 == 0, [1, 2, 4, 5, 8])
print(list(result))
# 筛选所有的奇数
result = filter(lambda x: x % 2 != 0, [1, 2, 4, 5, 8])
print(list(result))
# 4. sorted:
result = sorted([1, 29, 2, 3])
print(result)
result = sorted([0, 29, 2, 0], reverse=True)
print(result)
result = sorted([0, 8, 9, 0, 16], key=lambda x:0 if x==0 else 1)
print(result)