今日内容:
1、 有参装饰器
2、 三元表达式,列表生成式,字典生成式
3、 函数的递归调用,二分法
4、 匿名函数lambda+内置函数
5、 模块的使用
6、 软件开发的目录规范
上节课复习:
1、 函数的对象
函数可以被当着参数去处理
2、 函数嵌套
嵌套调用:在调用一个函数时,函数体又调用了其他函数
嵌套定义:在一个函数内部又定义了另外一个函数
def foo()
def inner():
pass
return inner
f=foo()
3、 名称空间与作用域
名称空间:存放名字和值的内存地址绑定关系的地方
内置名称空间
全局名称空间
局部名称空间
查找关系:当前所在的位置往上依次查找
全局作用范围:
全局存活,全局有效
局部作用范围:
临时存活,局部有效
强调:作用域关系在函数定义阶段已经固定了,与调用位置无关
4、 闭包函数
闭,封闭在函数内部,即定义在函数内部的函数
包:改内部包含对外部函数作用域名字的引用
# def outter():
# x=11
# def inner():
# x
# return inner
# f=outter()
# def foo(name):
# print(name)
# foo('frank')
#
# def outter(name):
# def foo():
# print(name)
# return foo
# f=outter('frank')
装饰器
1. 什么是装饰器
器指的是工具,装饰是为被装饰对象添加新功能
装饰器即是为被装饰的对象添加新的功能的工具
装饰器本身可以是任意可调用的对象
被装饰对象本身也可以是任意可调用的对象
2.开放封闭原则:
软件一旦上线后,就应该修改封闭(源代码+调用方式),对扩展开放的
装饰器的实现就是要在遵循1和2原则的前提下为被装饰的对象添加新功能
1、 不修改被装饰对象的源代码
2、 不修改被装饰对象的调用方式
3.如何实现
# import time
# def timmer(func):
# def wrapper(*args,**kwargs):
# start=time.time()
# res=func(*args,**kwargs)
# stop=time.time()
# print('run time is %s' %(stop - start))
# return res
# return wrapper
#
# @timmer #index=timmer(index)
# def index():
# print('welcome to index page')
# time.sleep(0.5)
#
# @timmer #home=timmer(home)
# def home(name):
# print('welcome %s' %name)
# time.sleep(2)
# index()
# home('frank')
#注释:
# f=timmer(index) #timmer()=wrapper()
# index=timmer(index)
# index()
# f=timmer(home)
# home=timmer(home)
# home('frank') #wrapper('frank')
执行结果:
装饰器模板:
# def outter(func):
# def inner(*args,**kwargs):
# res=func(*args,**kwargs)
# return res
# return inner
#如果我们的需求是
#需要将外层的函数参数格式原封不动转嫁给内部调用函数,需要使用到下面形式
# def index(name,age,sex):
# print('name:%s age:%s sex:%s' %(name,age,sex))
#
# def wapper(*args,**kwargs): #注释args=('frank') kwargs={'sex':'male','age':18}
# index(*args,**kwargs)
# # 注释:
# # index(*('frank'),**{'sex':'male','age':18})
# # index('frank',sex='male',age=18)
# wapper('frank',sex='male',age=18)
执行结果:
用户认证功能:
#current_info={'user':None}
# def timmer(func):
# def wrapper(*args,**kwargs):
# if current_info['user']:
# return func(*args,**kwargs)
# uname=input('you uname:').strip()
# pwd=input('you password:').strip()
# if uname=='frank'and pwd=='123':
# print('you are login...')
# #保存登录状态
# current_info['user']=uname
# res=func(*args,**kwargs)
# return res
# else:
# print('user or password err')
# return wrapper
#
# @timmer #index=timmer(index)
# def index():
# print('welcome to index page')
# @timmer #home=timmer(home)
# def home(name):
# print('welcome %s' %name)
#
# index()
# home('frank')
执行结果:
添加多个装饰器:
# import time
# current_info={'user':None}
#
# def outter(func): #func=wrapper2
# def wrapper1(*args,**kwargs):
# print('wrapper1....')
# if current_info['user']:
# return func(*args,**kwargs)
# uname=input('you uname:').strip()
# pwd=input('you password:').strip()
# if uname=='frank'and pwd=='123':
# print('you are login...')
# #保存登录状态
# current_info['user']=uname
# res=func(*args,**kwargs) #调用原始的index
# return res
# else:
# print('user or password err')
# return wrapper1
#
# def timmer(func): #func=最原始的index指向的内存地址
# def wrapper2(*args,**kwargs):
# print('wrapper2...')
# start=time.time()
# res=func(*args,**kwargs)
# stop=time.time()
# print('run time is %s' %(stop - start))
# return res
# return wrapper2
#
# #解释语法的时候自下而上
# #执行时则自上而下
# #可以连续写多个装饰器,处于最顶层的装饰器先执行
#
#
# @outter #index=outter(wrapper2)====》wrapper1 index=wrapper1
# @timmer #timmer(最原始的index指向的内存地址)===》wrapper2
# def index():
# print('welcome to index page')
# time.sleep(1)
# index()
执行结果:
有参装饰器
current_info={'user':None}
#
# def auth(engine='file'):
# def timmer(func): #func=最原始的index
# def wrapper(*args,**kwargs):
# if engine=='file':
# if current_info['user']:
# return func(*args,**kwargs)
# uname=input('you uname:').strip()
# pwd=input('you password:').strip()
# if uname=='frank'and pwd=='123':
# print('you are login...')
# #保存登录状态
# current_info['user']=uname
# res=func(*args,**kwargs)
# return res
# else:
# print('user or password err')
# elif engine == 'mysql':
# print('mysql的认证机制')
# elif engine == 'ldap':
# print('ldap的认证机制')
# else:
# print('不支持该认证机制')
# return wrapper
# return timmer
# @auth(engine='ldap') #index=timmer(index) index=wrapper
# def index():
# print('welcome to index page')
#
# index()
#
# @auth(engine='mysql') #home=timmer(home)
# def home(name):
# print('welcome %s' %name)
# home('frank')
执行结果:
wraps装饰器
通过from functools import wraps和@wraps(func)功能把index装饰后的注释伪装装饰前注释
# import time
# from functools import wraps
# def timmer(func):
# @wraps(func)
# def wrapper(*args,**kwargs):
# start=time.time()
# res=func(*args,**kwargs)
# stop=time.time()
# print('run time is %s' %(stop - start))
# return res
# return wrapper
#
# @timmer #index=timmer(index)
# def index():
# '''
# 这个是index函数
# :return:
# '''
# print('welcome to index page')
# time.sleep(0.5)
#
# index()
# print(help(index))
# print(index.__name__)
三元表达式
# 语法:
# res=条件成立时的返回值if 条件 else条件不成立时的返回值
# x=10
# y=20
# res=x if x>y else y
# print(res)
# res=True if x>y else False
# print(res)
列表生成式
# l=[]
# names=['frank','sunny','franksunny']
# for name in names:
# if name !='frank':
# l.append(name+'Happy')
# print(l)
# names=[name+'Happy' for name in names if name !='frank']
# l=[]
# names=['frank','sunny_happy','franksunny_happy']
# for name in names:
# if name.endswith('happy'):
# l.append(name.upper())
# names=l
# print(names)
# names=[name.upper() for name in names if name.endswith('happy')]
# print(names)
字典生成式
# s={i:i for i in range(10)if i>1}
# print(s)
# info=[
# ['name','frank'],
# ('age',18),
# ['sex','male']
# ]
# d={}
# for item in info:
# # print(item[0],item[1])
# d[item[0]]=item[1]
# print(d)
# d={item[0]:item[1] for item in info}
# print(d)
#d={
# 'name':'frank',
# 'age':18,
# 'sex':'male'
# }
# d={k.upper():v for k,v in d.items()}
# print(d)
函数的递归调用
1. 函数递归
函数递归调用,在调用一个函数的过程中又直接或间接调用自己称之为函数的递归调用
本质是一个重复的过程,每一次重复问题的规模都应该有所减少
递归必须满足连个阶段
#1、回溯:一层一层地递归调用下去
#2、递推:递归必须有一个明确的结束条件,在满足该条件情况下会终止递归
往回一层一层结束调用
# 递归vs while循环
# 递归只需要把控结束或进入递归的条件即可,至于循环无需考虑
#直接递归调用
# def foo():
# print('from to foo')
# foo()
#
# foo()
#间接
# def bar():
# print('from to bar')
# foo()
#
# def foo():
# print('from to foo')
# bar()
# foo()
#递归在哪里停止
# def foo(n):
# print('from to foo',n)
# foo(n+1)
# foo(0)
#查看递归的限制
# import sys
# print(sys.getrecursionlimit())
# def age(n):
# if n == 1:
# return 18
# return age(n-1)+2
# print(age(5))
递归使用:
# l=[1,[2,[3,[4,[5,]]]]]
#
# def tell(l):
# for item in l:
# if type(item) is not list:
# print(item) #item是单独的元素
# else:
# tell(item) #item是列表,再次调用本身的逻辑,传入item
# tell(l)
执行结果:
二分法函数递归使用(列表按从小到大元素排列)
#nums=[1,22,35,36,43,56,78,88,100]
# def binary_search(nums,find_num):
# print(nums)
# if len(nums)==0:
# print('not exists')
# return
# mind_index=len(nums)//2
# if find_num>nums[mind_index]:
# nums=nums[mind_index+1:]
# binary_search(nums,find_num) #重复调用本身逻辑,传入新的nums
# #in the right
# elif find_num<nums[mind_index]:
# nums=nums[:mind_index]
# binary_search(nums,find_num) #重复调用本身逻辑,传入新的nums
# #in the left
# else:
# print('find it')
# binary_search(nums,100)
执行结果:
匿名函数
#有名函数:可用通过函数重复使用
# def foo():
# print('from to foo')
# foo()
#匿名函数:只是使用一次,后面不会再使用
# def sum2(x,y):
# return x+y
# sum2=lambda x,y:x+y
# res=sum2(1,2)
# print(res)
# print(lambda x,y:x+y)
#定义匿名函数就是定义一个函数的内存地址
# print((lambda x,y:x+y)(1,2))
取出数字最大的人
# salaries={
# 'frank':1000,
# 'sunny':2000,
# 'apple':3000
# }
# def func(k):
# return salaries[k] #func的返回值当做比较依据
# print(max(salaries,key=func))
# print(max(salaries,key=lambda x:salaries[x]))
执行结果:
#按照薪资高低排序
# print(sorted(salaries, key=lambda x: salaries[x]))
执行结果:
排序
# nums=[1,8,3,5,9]
# l1=sorted(nums,reverse=True)#默认从大到小
# l2=sorted(nums)#默认从小到大
# print(l1,l2)
执行结果:
map 映射
# names=['frank','suuny','franksunny']
# chicken=map(lambda x:x+'sunny',names)
# print(list(chicken))
# l=[name+'sunny' for name in names]
# print(l)
reduce 合并
from functools import reduce
#
# l=['a','b','c','d']
# res=reduce(lambda x,y:x+y,l)
# print(res)
#
# res=reduce(lambda x,y:x+y,range(0,101))
# print(res)
#
# print(sum(range(0,101)))
filter 过滤
# names=['frank_a','sunny_a','franksunny']
# l=filter(lambda x:x.endswith('_a'),names) #filter会for循环names,取出每一个名字,然后传给指定函数
# l=[name for name in names if name.endswith('_a')]
# print(list(l))
执行结果:
模块的介绍:
1、什么是模块
模块就是一些功能的集合体
模块分为三大类:
1、自定义模块
2、内置模块;time,sys
3、第三方模块
模块的表现形式:使用python编写的.py文件;
把一系列的模块组织到一起的文件夹(注:文件夹下有一个__int__.py,改文件称之为包)
2、为何要用模块
1、可以拿来内置、或者第三方的模块,然后直接使用,提高开发效率
2、将程序中共用一些功能组织到一个文件中,程序各部分组件可以重用该文件功能
优点:减少代码冗余,组织结构性清晰
3、为何用模块
一个py文件就是一个模块,文件名为spam.py,模块名则spam
强调:模块的使用必须要搞清楚谁是执行文件,谁是被导入的文件
模块的使用值import
#执行文件run.py
#被导入文模块是:spam.py
#首次导入模块会发生三件事:
#1、创建一个模块spam.py的名称空间
#2、执行模块对应文件spam.py,将产生的名字丢到模块名称空间
#3、在当前执行文件的名称空间中拿到一个spam,该名字就是指向模块spam.py的名称空间
#spam=spam.py名称空间的内存地址
#后续的导入执行引用之前导入的结果
import spam
#在当前执行文件中引用模块中的名字语法:spam.名字,必须加上spam.作为前缀
#spam.名字相当于指名道姓跟一个名称空间要名字,根本不会与当前文件名字冲突
print(spam.money)
模块的使用之from …import…
#首次导入模块会发生三件事:
#1、创建一个模块spam.py的名称空间
#2、执行模块对应文件spam.py,将产生的名字丢到模块名称空间
#3、在当前执行文件的名称空间中拿到一个名字money,该名字就是指向模块spam.py的名称空间那个money
# from spam import money
# print(money)
# 两种导入方式对比
# 相同点:函数的作用域的关系在定义阶段已经规定死了,与调用位置无关
#from import
# 优点:可以不用加前缀可以直接引用名字,更简洁
# 缺点:容易与当前执行文件中的名字冲突
#import
#优点:指名道姓和某一个名称空间要名字,肯定不会和当前名称空间的名字冲突
#缺点:必须加上前缀
# from spam import * #*会检索导入模块中的__all__指定的名字,如果没有改变量默认导入所有
Spam写入方式:__all__=['money','read1']
# from spam import money as my
模块循环导入问题
模块循环/嵌套导入抛出异常的根本原因是由于在python中模块被导入一次之后,就不会重新导入,只会在第一次导入时执行模块内代码
在我们的项目中应该尽量避免出现循环/嵌套导入,如果出现多个模块都需要共享的数据,可以将共享的数据集中存放到某一个地方
在程序出现了循环/嵌套导入后的异常分析、解决方法如下
#示范文件内容如下
#m1.py
print('正在导入m1')
x='m1'
from m2 import y
#m2.py
print('正在导入m2')
y='m2'
from m1 import x
#run.py
import m1
区分python文件的两种用途:
一个python文件有两种用途
1、 可以直接运行:__name__==’__main__’
2、 可以被当做模块导入__name__==’模块名’
调用模块
m1.py
# def f1():
# print('f1')
#
# def f2():
# print('f2')
#
# def f3():
# print('f3')
#
# if __name__ == '__main__':
# f1()
# f2()
# f3()
执行文件:
# import m1
# m1.f1()
模块搜索路径:
模块的搜索路径的优先级
1、 内存
run.py
# import time
# import spam
# time.sleep(8)
# import spam
# spam.f1()
2、 内置的模块
3、sys.path
# import sys
# print(sys.path)
# # sys.path
# import sys
# sys.path.append(r'E:\SH_weekend_s2\day5\14.模块路径搜索\dir')
# # print(sys.path)
#
# import spam
# spam.f1()
软件开发目录规范