Python高级特性
1.列表生成式
列表生成式就是一个用来生成列表的特定语法形式的表达式。
是Python提供的一种生成列表的简洁形式, 可快速生成一个新的list。
普通的语法格式:[exp for iter_var in iterable]
带过滤功能语法格式: [exp for iter_var in iterable if_exp]
循环嵌套语法格式: [exp for iter_var_A in iterable_A for iter_var_B in iterable_B]
2.列表生成式实例
1). 求1-50所有数的平方
square = [(i + 1) ** 2 for i in range(50)]
print(square)
2). 生成一个2n+1的数字列表,n为从3到11的数字。
nums_list = [2 * n + 1 for n in range(3, 12)]
print(nums_list)
3). 求以r为半径的圆的面积和周长(r的范围从1到10)。
import math
circle = [(math.pi * (r ** 2), 2 * math.pi * r) for r in range(1, 11)]
print(circle)
3.集合生成式与字典生成式
1)集合生成式:用来快速生成集合。
2)字典生成式:用来快速生成字典。
生成器
生成器:Python中一边循环,一边计算的机制,被称为生成器。
问:什么时候需要生成器?
答:一般情况下我们不需要使用生成器,只有当我们因为性能限制才需要用到,比如我们使用python读取一个10g的文件,如果一次性将10g的文件加载到内存处理的话(read方法),内存肯定会溢出;这里如果可以使用生成器把读写交叉处理进行,比如使用(readline和readlines)就可以再循环读取的同时不断处理,这样就可以节省大量的内存空间。
1)如何创建生成器?
第一种:列表生成式的改写。(将生成式中的【】改为())
第二种:yield关键字。
2)如何打印生成器的每个元素呢?
通过for循环, 依次计算并生成每一个元素。
如果要一个一个打印出来,可以通过next()函数获得生成器的下一个返回值。
3)生成器的特点:
1.节约内存。2.迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的。
生成器实例:
1.斐波那契数列:
除第一个和第二个数外,任意一个数都可由前两个数相加得到.
1, 1, 2, 3, 5, 8, 13, 21, 34
def fib(n):
# a代表第一个数, b代表第2个数, 也就是要显示的数; count: 当前已经显示fib数列的个数;当前为0;
a, b, count = 0, 1, 0
# 0<5
while count < n:
# print(b)
yield b
# a, b = b, a+b
a, b = b, a+b
# 已经显示的次数加1
count += 1
# f是一个生成器(函数里面有yield)
f = fib(5)
while True:
try:
print(next(f))
except:
break
2.利用yield求平均值。
def averager():
# 所有数的和, 默认为0;
total = 0.0
# 数值的个数;
count = 0
# 平均值结果;
average = None
# 所有数值存储的容器(List);
all_items = []
while True:
# 函数包含yield关键字
new_item = yield average, all_items
all_items.append(int(new_item))
total += new_item
count += 1
average = total / count
def main():
# AVERAGER是个生成器;
AVERAGER = averager()
# 第一次调用next方法, 遇到yield停止,
next(AVERAGER)
# 死循环, 依次求解平均值;
while True:
new_num = input("请输入求平均值的数: ")
if new_num == 'q':
print("程序执行结束.....")
break
# 1). 通过send方法将求平均值的数值传到yield所在位置,(14行);
# 2). send方法的返回值是求平均值的列表和平均值结果;
average, all_items = AVERAGER.send(int(new_num))
print(all_items, "的平均值为:", average)
main()
迭代器
什么是迭代器?
迭代是访问容器元素的一种方式。迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
可迭代对象:可以直接作用于for循环的对象(如何判断是否可以迭代?)
一类是集合数据类型,如list, tuple,dict, set,str等;
一类是generator,包括生成器和带yield的generator function。
迭代器特点:
(1)可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
(2)生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
(3)把list、dict、str等Iterable变成Iterator可以使用iter()函数。
迭代器与生成器的区别:
闭包
什么是闭包?
1)闭包的概念就是当我们在函数内定义一个函数时,这个内部函数使用了外部函数的临时 变量,且外部函数的返回值是内部函数的引用时,我们称之为闭包。
2)闭包再理解 :内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。
3)nonlocal关键字:显式的指定变量不是闭包的局部变量
闭包的一个常用场景就是装饰器。
闭包的实际例子:
函数line与变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y=x+1和y=4x+5)。
优点:闭包也具有提高代码可复用性的作用。
装饰器
什么是装饰器?
答:装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的
前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,
比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。
为什么需要装饰器?
答:写代码要遵循 开放封闭 原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
1.封闭:已实现的功能代码块
2.开放:对扩展开发。
装饰器实例:动画片问题
运行结果为:‘开始播放动画片《喜羊羊和灰太狼》‘
装饰器的功能:
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
当有多个装饰器时:(以两个为例)
运行有两个装饰器的程序时可以分为有两个步骤:
1.装饰函数阶段:装饰函数时,先用第二个装饰器,再用第一个。
2.调用函数阶段:调用函数阶段,先执行第一个装饰器,再执行第二个装饰器。
多个装饰器应用实例:学生管理系统,需要判断用户是否登陆账号,以及判断账号有无权限执行操作。
#1.判断用户是否登录
#2.判断用户是否有权限
#3.系统中的用户信息
db = {
'root': {'name': 'root',
'passwd': 'westos',
'is_super': 0},
'admin': {'name': 'admin',
'passwd': 'westos',
'is_super': 1}
}
login_user_session = {}
#存储当前登录用户信息
def is_login(fun):
def wrapper1(*args, **kwargs):
if login_user_session:
result = fun(*args, **kwargs)
return result
else:
print("跳转登陆".center(50, '*'))
user = input('user:')
passwd = input('Passwd:')
if user in db:
if db[user]['passwd'] == passwd:
login_user_session['username'] = user
print("登陆成功")
result = fun(*args, **kwargs)
return result
else:
print("密码错误")
else:
print("该用户不存在")
return wrappe1
#判断是否有权限修改
def is_permisson(fun):
def wrapper2(*args, **kwargs):
print("判断是否有权限......")
current_user = login_user_session.get('username')
permission = db[current_user]['is_super']
if permission == 1:
result = fun(*args, **kwargs)
return result
else:
print("用户%s没有权限" % (current_user))
return wrapper2
@is_login
@is_permisson
def delete():
return '正在删除用户信息'
result = delete()
print(result)
**** 被装饰的过程:
1). delete = is_permission(delete) # delete = wrapper2
2). delete = is_login(delete) # delete = is_login(wrapper2) # delete = wrapper1
*******被调用的过程:
delete() ------> wrapper1() ---> wrapper2() ---> delete()
"""
练习部分
1.装饰器加日志并存入日志
import datetime
import os
import json
def rizhi(kan):
def zhuangshi(*args, **kwargs):
starttime = datetime.datetime.now()
hostname = os.getenv("computername")
file = open('rizhi.txt', 'a+')
json.dumps(str(starttime))
json.dumps(str(hostname))
file.write(str(starttime))
file.write(str(hostname))
file.close()
kan(*args, **kwargs)
return zhuangshi
@rizhi
def chakan():
result = 'you program is OK'
print("运行完成,函数结果为:%s" % result)
return result
2.斐波那契数列高速递归
import time
def num_catch(func):
list = []
def wapper1(*args):
if func(*args) not in list:
list.append(func(*args))
return func(*args)
else:
return func(*args)
return wapper1
def timeit(func):
def wapper2(*args, **kwargs):
start = time.time()
time0 = func(*args, **kwargs)
end = time.time()
print("执行时间为:%s" % (end - start))
return time0
return wapper2
@num_catch
@timeit
def fibonacci(n):
if (int(n) <= 2):
return 1
result = fibonacci(int(n) - 1) + fibonacci(int(n) - 2)
return result
print(fibonacci(10))
3.求微信好友省份前五
import itchat
itchat.auto_login()
friends = itchat.get_friends(update=True)
prov_dict = {}
for fri_info in friends[1:]:
prov = fri_info['Province']
if prov and prov not in prov_di**加粗样式**ct.keys():
prov_dict[prov] = 1
elif prov:
prov_dict[prov] += 1
prov_dict_top10 = sorted(prov_dict.items(),key=lambda x:x[1],reverse=True)[0:10]
print(prov_dict_top10)
模块与包
工具包的定义:模块就是工具包,想要使用这个工具包的工具就要导入这个模块
模块是非常简单的Python文件,一个python文件是一个python模块,两个python文件就是两个python模块。
模块导图:
如何导入模块?
答:当解释器遇到import语句时,如果模块在当前的搜索路径就会被导入。
为什么一定要加上模块名导入呢?
答:因为可能存在这样一种情况:在多个模块中含有相同名称的函数,如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名。
如果只需要用到模块中的某个函数/变量/类,如何导入呢?
答:通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块名,但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。