装饰器(难):
函数里面可以再嵌套一个函数
高阶函数
说白了就是函数嵌套+高阶函数
装饰器的作用就是在不改变原有函数的调用方式,入参的情况下,给函数添加新功能
偷偷摸摸的给函数加上新功能,但是不改变原来的函数
1)函数嵌套函数:
def a():
print(‘1‘)
def b():
print(‘2‘)
def c():
print(‘3‘)
a()
上述,b和c函数只有定义,没有执行,所以只会执行最外面的a函数,如果在每层def之后依次执行abc函数,则会输出‘1’‘2’‘3’
2)函数的作用域,就近原则,自己函数里有,就拿过来用,如果没有就去父级函数里面找
本级找不到变量name的话,自动取上一级(从里往外找),但是父级不可用子级的变量值
输出的值,不是根据print的顺序,是根据函数调用的顺序,必须得调用才能执行。
以上,a在调用后,先从name = ‘1’ 开始,然后b函数开始定义,在b执行之后,里面的内容才开始执行,从name=‘2’ 开始,先遇到了print(‘b的name是%s‘ % name),所以先输出,之后在c定义之后,先遇到了c执行,所以第二条是print(‘c的name是%s‘%name),最后才是print(‘a的name是%s‘%name)
原式子:
改进后的:
上图可以,但是对比之前的,run函数的调用已经从run()变更为run_time(run),调用方式改变了。
要完全实现装饰器的内容(标红部分是个装饰器),可以按下述条件来写:
import time
def run():
print(‘running‘)
time.sleep(1)
def timer(func):
def deco():
start_time = time.time() # 开始时间
func()#deco函数里面没有func这个函数,父级入参了func变量,子集取过来执行
end_time = time.time() # 结束时间
print(‘run函数运行是‘,end_time-start_time)
return deco#timer函数返回了一个函数名,这个函数存的是上面deco那段代码,deco未调用,没执行,此时什么都不会返回
run = timer(run) #run== deco,这里的run可以换成别的名字,包括改成deco或者其他值,只是一个变量名,如果换成run相当于替换了run里面的代码
#调用timer函数的时候,要传入一个方法名
# timer函数在函数内部定义了一个函数叫做deco
#又在deco函数内部调用了timer里面传入的方法
#run存的是deco,deco是一个函数,调用run就是调用deco
run()#deco是一个局部变量,但是run在返回后还有定义,所以run可以执行
#如果后续还有调用run的地方,就是在当前功能的基础上再添加代码,一直添加下去了。
上述式子改变格式:
import time
def timer(func):
def deco(*args,**kwargs):
start_time = time.time() # 开始时间
res = func(*args,**kwargs)#deco函数里面没有func这个函数,父级入参了func变量,子集取过来执行;func里面加上俩形参,用来接收传入函数的参数,完善逻辑
end_time = time.time() # 结束时间
print(‘runtime‘,end_time-start_time)
return res#防止函数有返回值接收不到,再加一个获取返回值
return deco
@timer #和“run = timer(run)” 意思相同,写在timer()定义的后面
def run():
print(‘running‘)
time.sleep(1)
run()#也可以去掉@timer,直接写成timer(run)(),会得到相同结果,但是这样写就改变原有调用方式了
@timer#装饰器可以在多个函数中用,谁需要在定义前加上即可
def run2(name):#run2里面传入了参数name时,上面的deco()定义里面如果不同步设置一个形参,就会报错。
print(name)
time.sleep(0.5)
run2(‘niuhanyang‘)
run()
内置函数:(标黑才是常用,其他知道即可)
print(all([1,2,3,4]))#判断可迭代的对象里面的值是否都为真
print(any([0,1,2,3,4]))#判断可迭代的对象里面的值是否有一个为真
print(bin(10))#十进制转二进制
print(bool(‘s‘))#把一个对象转换成布尔类型,还有int() float() str() dict() list() set() tuple(),元组值不能变,列表能变
print(callable(‘aa‘))#判断传入的对象是否可调用
print(chr(10))#打印数字对应的ascii
print(ord(‘b‘))#打印字符串对应的ascii码
print(dict(a=1,b=2))#转换字典
print(dir(1))#打印传入对象的可调用方法,带下划线的不用管
print(eval(‘[]‘))#执行python代码,只能执行简单的,定义数据类型和运算,引号里面可以换成字典{}\list[]\字符串等等
print(exec(‘def a():pass‘))#执行python代码
filter(func,[1,2,3,4])#根据前面的函数处理逻辑,依次处理后面可迭代对象里面的每个元素,返回true才保存,不适用于多个入参
【举例】
def func(num):
return num
print(filter(func,[0,1,2,3,4]))#在python2里面会返回[1,2,3,4],python3只会返回内存地址
print(list(filter(func,[0,1,2,3,4])))#非0即真,在python3里面返回[1,2,3,4]
map(func,[1,2,3,4])#根据前面的函数处理逻辑,依次处理后面可迭代对象里面的每个元素,保存前面函数返回的所有结果,上述例子换成map返回[0,1,2,3,4]
print(globals())#返回程序内所有的变量,返回的是一个字典,函数里面的局部变量不会返回
print(locals())#在函数体里面用,返回这个函数所有的局部变量
print(hex(111))#数字转成16进制
print(max(111,12))#取最大值,也可以传列表
print(oct(111))#把数字转换成8进制
print(round(11.1198,2))#取几位小数,会四舍五入,返回11.12
print(sorted([2,31,34,6,1,23,4]))#排序,默认是升序,加上reverse=True表降序,
【举例】
dic={1:2,3:4,5:6,7:8}
print(sorted(dic.items()))#按照字典的key排序
print(sorted(dic.items(),key=lambda x:x[1]))#按照字典的value排序
__import__(‘decorator‘)#导入一个模块
常用模块
http://www.nnzhp.cn/blog/2016/12/19/python%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E5%85%AD%E5%B8%B8%E7%94%A8%E6%A8%A1%E5%9D%97/
什么是模块,模块其实就是一个python文件,常见的os,time,sys 在pycham里面ctrl+单击名称,即可以查看模块内部写法
用哪个模块就要import哪个模块,格式:import+python文件名(不要.py后缀)
import的本质就是把这个python从头到尾执行一次
如:两个python文件a.py和b.py如果要在a中定义了一个函数run(),在b中写
import a
a.run()#这里一样会执行a这个函数,a中定义多个,这里也可以调用多个,格式--模块名.函数()
如果a中有多个函数,b中不想全部import,那么可以写成如下:
from a import run,run1#只导入某个函数的时候这么写,但是代码也会从头到尾执行一遍,只是最后保留其中要的函数
run()
run1()
from a import *# 也可以这样写,表示导入a模块中的所有函数
from a1 import *#导入a1模块中的所有函数,多行这种很难识别,自己千万别写!!
run()
run1()
run2()
from day4.a import run#在其他目录下导入,terminal下运行报错,直接run可以(run的时候,会自动把这段代码加到环境变量中,所以可以);如果加到环境变量中(环境变量就是让你在任意一个目录下都可以使用这个命令),那就都可以执行
run()
ps:包和文件夹的区别就是,python2里面,如果要导入其他文件夹下面的python文件,那么文件夹必须是个包(下面带个_init_.py),python3里面不要求,是文件夹就行
导入模块的时候,python首先在当前目录下找这个模块,如果在当前目录下没有找到这个文件的话,那么就去环境变量里面的目录找,都找不到,则报错。
【如何看】
import sys
print(sys.path)#看系统环境变量
sys.path.append(‘E:\byz_code‘)#可以执行该语句将目录加到环境变量里面
避免碰见要应用的py文件和系统常见模块名称一致!如time.py和import time
import random
import random,string
print(random.random())#随机浮点数,默认取0-1,不能指定范围,没啥用
print(random.randint(1,20))#随机整数
print(random.randrange(1,20))#随机产生一个range,基本上和randint一致
print(random.choice(‘x23serw4‘))#随机取一个元素,里面可以是字符串,list等可迭代对象,返回类型无限制
【举例】
date_list = [‘10:23‘,‘10:24‘]
random.choice(date_list)
print(random.sample(‘hello‘,2))#从序列中随机取2个元素,也可以取list等,数字可变,返回的是int
print(random.uniform(1,9))#随机取浮点数,可以指定范围
x = [1,2,3,4,6,7]
random.shuffle(x)#洗牌,打乱顺序,会改变原list的值,只能是list
print(x)#无赋值,不会返回值,直接打乱了x的顺序,x只能是list
print(string.ascii_letters+string.digits)#所有的数字和字母
五、json处理,可以用与字典和list
json格式和字典很像,比如true的首字母大小写,而且json里面只能是双引号,python单双引号都可以,可以用www.bejson.com校验格式
json串实际上就是一个字符串(接口返回的json其实就是个字符串)
如果json是存在文件里面,则用
fr = open(‘users‘)
json_dic_file = json.load(fr)#这里和json.loads(fr.read())一样
#load方法是传入一个文件对象,然后load方法自动去读这个文件的内容,然后转成字典
把字典转成json串并且生成到newuser文件中
只有两种方法:
json.loads()和json.load() : json串转字典的
json.dumps()和json.dump() :字典转json串的
带s的就和字符串沾边,不带s的