python_装饰器详解(函数及变量/高阶函数/嵌套函数)/装饰器案例/迭代器与生成器/内置方法/Json与pickle数据序列化/软件目录结构规范
在这里得感谢,老师Alex金角大王(路飞学城IT)
Python(给兄弟们挂个🔗)
>_<…因为有的是自己理解,如有错误,希望大家踊跃评论,我好即使改正…
一、装饰器详解:
1.装饰器:
(1):本质:装饰器的本质是函数,(装饰其他函数),即为其他函数添加附加功能…
(2)原则:1)不能修改被装饰源代码;2)不能修改函数的调用方式;
3)“透明的"存在…
(3)知识储备:1)函数即"变量”;
2)高阶函数:把一个函数名当作实参传给另一个函数(在不修改被装饰函数源代码的情况下为其添加功能);返回值中包含函数名(不修改函数的调用方式)
3)嵌套函数: 高阶函数 + 嵌套函数 = 装饰器…
2.函数即"变量":
(1)提出这样一个问题:如下…
def function1():
print("i am function1...")
function2()
def function2():
print("i am funciotn2")
function1()
function2 在 function1 下面…这样调用可以吗???
答:可以…
(2)内存回收机制:
result:
1)变量赋值:x=1,x = y ,相当于在内存中找一个"小房间",把 “1”装进去,再把门牌号 “x” 和 “y” ,给 “小房间”…
2) def test ():…test = ‘函数体’,同理,test(函数名)为门牌号…
'函数体’其实是一堆字符串…
tips: lambda x:x* 3…是没有函数名的一种定义函数的方式…calc = lambda x:x*3(是为了后面可以调用它…)
3)“内存回收机制”,即为:当“门牌号”不存在时,内存就会自动清空"房间"…
则上面的程序:可以用下面的“变量”形式,去解释:
x =1
y =3
print(x,y)
y =3
x =1
print(x,y)
即:在"执行function1"之前: def fuc1…def fuc2…顺序不重要
but,唯有这一种:!!!无法运行…!!!
def function1():
print("i am function1...")
function2()
function1()
def function2():
print("i am funciotn2")
调用之前,找不到你…报错…
learn by heart:1.内存回收机制2.lambda x=x*3
3.高阶函数:a:把一个函数当实参,传给另一个函数
b:return 函数名…
(1):把一个函数名当实参,传给另一个函数…(不修改被装饰源代码)
import time
def bar():
time.sleep(3)
print('in the bar')
def test1(func):
start_time=time.time()
func() #run bar
stop_time=time.time()
print("the func run time is %s" %(stop_time-start_time))
test1(bar) #bar()
(2):return"函数名":(不改变其调用方式)…
import time
def bar():
time.sleep(3)
print('in the bar')
def test2(func):
print(func)
return func
# print(test2(bar))
bar=test2(bar)
bar() #run bar
learn by heart:
a:test(bar)…
b:return function…
4.嵌套函数: 233333…就是函数套函数…
def foo():
print('in the foo')
def bar():
print('in the bar')
bar()
foo()
5.装饰器简单实例:
1.写主函数:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
def test_1():
time.sleep(2)
print("run test1")
def test_2():
time.sleep(2)
print("run test2")
def test_3():
time.sleep(2)
print("run test3")
test_1()
test_2()
test_3()
3个test…每个睡3秒…
2.写time装饰器:
1.高级函数 + 嵌套函数 = 装饰器…
def time_1(func):
def deco():
start_time = time.time()
func()
end_time = time.time()
print("test run time : %s"%(end_time-start_time))
return deco
2.写个"语法糖":
@time_1 #翻译一下:test_1 = deco = time_1(test_1)
def test_1():
time.sleep(2)
print("run test1")
哪个"主函数"想被修饰,就在哪个函数前面加…
tips:装饰器…别用模块名…
3.整个程序:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
def time_1(func):
def deco():
start_time = time.time()
func()
end_time = time.time()
print("test run time : %s"%(end_time-start_time))
return deco
@time_1 #翻译一下:test_1 = deco = time(test_1)
def test_1():
time.sleep(2)
print("run test1")
@time_1
def test_2():
time.sleep(2)
print("run test2")
@time_1
def test_3():
time.sleep(2)
print("run test3")
test_1()
test_2()
test_3()
learn by heart:
1.all progress
2.语法糖:@time_1 翻译一下:time_1(test_1) = deco = test_1
4.主函数传参数:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = "Alex Li"
import time
def timer(func): #timer(test1) func=test1
def deco(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs) #run test1()
stop_time = time.time()
print("the func run time is %s" %(stop_time-start_time))
return deco
@timer #test1=timer(test1)
def test1():
time.sleep(1)
print('in the test1')
@timer # test2 = timer(test2) = deco test2(name) =deco(name)
def test2(name,age):
print("test2:",name,age)
test1()
test2("alex",22)
因为test2(name,age)…要传参数…
1.test2 = fuction = deco = timer(test2)…
2.则,deco(* args, **args),function( * args,**aegs)
5.Alex进一步写的函数:(2333333,我斑愿称你为最强… /狗头)
(传参过程有点复杂…可以边调试边分析…分享给大家)
#__author__ = "Alex Li"
import time
user,passwd = 'alex','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;1mUser has passed authentication\033[0m")
res = func(*args, **kwargs) # from home
print("---after authenticaion ")
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
elif auth_type == "ldap":
print("搞毛线ldap,不会。。。。")
return wrapper
return outer_wrapper
def index():
print("welcome to index page")
@auth(auth_type="local") # home = wrapper()
def home(): #>>> 这里的home = func
print("welcome to home page")
return "from home"
#这个 home 执行 是在 function / return "from home"把值给了 func().... 即要return func()
@auth(auth_type="ldap")
def bbs():
print("welcome to bbs page")
index()
print(home()) #wrapper() >>> 这里的home() = wrapper()
bbs()
二、迭代 &生成器:
1.列表生成式:
number = [i*2 for i in range(10) ]
print(number)
result:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[func(i) for i in range(10) ]
2.生成器(generator):
(1):背景:我要生成一个列表,假如这个列表100w个数字,而我只用了前两个;这样内存被大大浪费…
想:会不会有这样一个"算法",让这个列表的前后数是"有联系的",让它边循环边存数据…(空间被大大节省)
number = (i*2 for i in range(10) )
print(number.__next__())
#生成器:
1.只有在调用时,才会生成相应的数据
2.生成器只记住当前数据(为了省内存)…只记住当前位置…
3.只有一个__next__()方法。
4.防止占用内存空间…循环到哪就存到哪…
3."斐波拉契"数列:“任意一个数”,都是由前面两个数相加得到…1,1,2,3,5…
#__author__ = "Alex Li"
def fib(max): #10
n, a, b = 0, 0, 1
while n < max: #n<10
print(b)
a, b = b, a + b
# ''' t =(b,a_test+b) #把值给元组
# a_test = t[0]
# b = t[1]'''
n = n + 1
return '---done---'
f= fib(10)
这是一循环,数列…离"生成器"一步之遥…
__author__ = "Alex Li"
def fib(max): #10
n, a, b = 0, 0, 1
while n < max: #n<10
#print(b)
yield b
a, b = b, a + b
# ''' t =(b,a_test+b) #把值给元组
# a_test = t[0]
# b = t[1]'''
n = n + 1
return '---done---'
f= fib(10)
只需要把 print b ,变成 yield b…“就变成了函数做成一个生成器”…
优点:“可以在程序中断时”,干点其他的…
print(number.__next__())
print(number.__next__())
print("----------------我是分割线-----------------")
print(number.__next__())
print(number.__next__())
4.会"报错":
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = "Alex Li"
def fib(max): #10
n, a, b = 0, 0, 1
while n < max: #n<10
#print(b)
yield b
a, b = b, a + b
# ''' t =(b,a_test+b) #把值给元组
# a_test = t[0]
# b = t[1]'''
n = n + 1
return '---done---'#此时这已经不是一个函数...而是一个生成器,return'---done---'表示错误时候的消息...
#f= fib(10)
g = fib(6)#把函数变为生成器
while True:
try:
x = next(g)#x = g.__next__()
print('g:', x)
except StopIteration as e:#检验到 无法循环时 自动退出
print('Generator return value:', e.value)
break
5.yield 实现"单线程" 并行运算:
(1)首先:yield 的作用:(调试程序一步一步的分析…)
enenen…这样理解吧23333,"生成器"是一种状态(调用一次,我存一次…就是中间会停顿),(你用一次next,我在执行一次语句…我就停在yield等你)
(2)yield 的 c.send()功能…(既能调用yield,又能传值进去…)
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = "Alex Li"
import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
'''
c = consumer("ChenRonghua")
c.__next__()
b1= "韭菜馅"
c.send(b1)
c.__next__()'''
def producer():
c = consumer('A')
c2 = consumer('B')#这一步操作只是把函数变成生成器
c.__next__()
c2.__next__()#这里的next是为了......输出print
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了1个包子,分两半!")
c.send(i)
c2.send(i)#这一步操作是开始传值....
producer()
result:
A 准备吃包子啦!
B 准备吃包子啦!
老子开始准备做包子啦!
做了1个包子,分两半!
包子[0]来了,被[A]吃了!
包子[0]来了,被[B]吃了!
做了1个包子,分两半!
包子[1]来了,被[A]吃了!
包子[1]来了,被[B]吃了!
做了1个包子,分两半!
包子[2]来了,被[A]吃了!
包子[2]来了,被[B]吃了!
拆开看:
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
c = consumer("ChenRonghua")#记住了...这已经不是函数了...这句话不会当成函数一样调用consumer()
#这句话是把这个consumer...变成生成器了....
c.__next__()#记住:next 第一个是为了调用yield,去“找到”yield,找到了...就退出去...
c.send("韭菜馅")#找到过...从yield去执行后面语句...玩了,退出
c.__next__()#第二次找到.但没赋值....执行后面的...
result:
1.“记住”,第一个next,是找“yield”,执行前面的…
2. …后面的找到了,就是"调"…执行后yield后面的
3.emem…以上是我个人总结!!!,在调试下分析的…有可能不对,若其他同学有不同理解,给予评论,我好加以改正…
conclude:
1.列表生成器 2._ _next _ _ / c.send ( ) 3.yield b…return ‘–done–’ 4.错误判断while try…5.不是函数了…吃包子案例运行机制…
3.迭代器:
迭代对象 or 迭代器:
1.迭代对象:(可以直接作用于 for 循环的对象) >>> iterable
list tuple dict set str 等;
from collections import Iterable
isinstance([],Iterable)
isinstance({},Iterable)
isinstance('ABC',Iterable)
isinstance(4132,Iterable)
2.可以被next ( ) 函数调用 并不断返回下一个值的 对象 称为 迭代器: Iterator
from collections import Iterator
isinstance(iter([]),Iterator)
不是迭代器的可以用 iter(),变成迭代器…迭代器本身是一种惰性函数…
文件操作中那个for line in f…就是变成了“迭代器”…
三、内置方法:
python里面自带的方法…
all()#print(all([0,1,2,3])
any()#print(any([0,1,2,3]))
all里面的迭代对象,每个元素都为真(非0),print为真
any里面,存在一个真,print为真
bin()#10进制 转到 二进制...bin(数字)
print(hex(255))#转成十六进制
print(oct(8))#转八进制
print(pow(3,2))#3的平方
print(round(1.3342,2))#保留两位有效数字
bool()#判断真假...空字典、空列表,也为假...
bytes()# "不可以修改" 的 二进制字节格式
a_test = bytes('asdaf',encoding = 'utf-8')
print(a_test.capitalize(),a_test)
b = bytearray('asdaf',encoding = 'utf-8')
print(b[0])
b[1] = 100
print(b)
bytes,无法修改的二进制类型…(不能像列表、字典那样去直接修改);
但是bytearry…可以用ascll码去修改…
#callable 可调用的/后面加括号的
print(callable( [] ))
def sayhi():pass
print(callable( sayhi ))
判断:callable()…里的是否可调用…什么可调用,就是后面加括号的:例如函数…
print(chr(100))#将 ascll码数字 转化为 字符
print(ord('b'))#相反..将字符转换为 ascll码数字
chr & ord
code = "for i in range(10):print(i)"
compile(code,'','exec')#字符串形式 转成代码...
c = compile(code,'','exec')#存成一个变量...
exec(c)#执行代码
compile实现一种“编译”功能,执行"字符串"代码…
记住:compile + eval ( ) + exec ( )
print(divmod(5,2))#5/2 = 2 余 1 ,结果为(2,1)
res = filter(lambda n:n>5,range(10))#filter,是过滤满足条件的...这里变成迭代器
res = map(lambda n:n*3,range(10) )#[i*3 for i in range(10)]
for i in res:
print(i)
import functools
res = functools.reduce(lambda x,y:x+y,range(10))#累加,x是结果,y是第二个数
res_1 = functools.reduce( lambda x,y:x*y,range(1,10))#阶乘
print(res)
print(res_1)在这里插入代码片
lambda函数 + filter(过滤) + map(执行) + functools.reduce(x,y,累加/累乘)
a = frozenset([1,4,33,234,324,25,523,552,5])#集合冻结...frozen + set
print(globals())#以字典的形式.....返回“程序中”所有 变量的 key-value格式
def test():
local_va = 333
print(locals())#打印“程序中”所有局部变量....
test()
a = {6:2,9:6,11:6,1:6,9:4,9:9}# info.items >>> 其输出的是一个列表,info是一个字典
print(sorted(a.items()))#按key排序 # 只有列表可以排序 name.sort()
print(sorted(a.items(),key = lambda x:x[1]))#按value排序
#lambda>>>>>x是"有序"数列的>>>>>>每一个元素>>>>>>x[1]>>>>元素中的位置
print(hash("我爱中国"))
result:7584562962477390689
???这是什么…这是hash"映射"的一种"序号"
1.假如这么一个列表,里面有100w个人的名字,当你在执行代码时;
2.“系统"要去怎么“找”呢???…从第一个开始循环找??…
3.那如果你要的数据,刚好在最后一个,将会大大的浪费运行时间…
此时,Hash这种“映射关系”就很重要了…
它将你所存的数据…都写上一个"序号”,再用“半区间法”…依次的找到你想要的数据…运行次数大大减小…
#zip拉链
a = [3,1,3,9]
b = ['a_test','b','c']
for i in zip(a,b):
print(i)
print(type(zip(a,b)))#zip拉链
result:
(3, ‘a_test’)
(1, ‘b’)
(3, ‘c’)
<class ‘zip’>…是类
import decorator
__import__('decorator')#挺有用的>>>>>后面会讲
#太有用了...只知道模块的字符串格式...就用这个方法去导入
result:导入"字符串模块"…和compile一样…
conclude:
any +all / bytes + bytearray /complie + eval +exec / lambda + filter(过滤) + map(执行) + functools.reduce(累加/累乘) / sort (a.iteams) + (lambda x:x[1])
hash / zip(类) / __import (“字符串”) __
四、Json & pickle 序列化:
这又是什么鬼???
enen…当你在"打游戏"你突然离开了以后…你想把你现在打的“副本”、“装备”…存起来…你就得把你现在的"状态"存起来…
1.josn & pickle :就是专门…干这事的…
2.把你现在的“状态”(代码),转换成字符串…存起来(写在一个.py文件里)…当你需要的时候…在把它读出来运行…
(1)若单纯是利用’这种思想’,用前面的compile也可以做…
info ={
'a': 1,
'b': 2,
'c': 3
}
test_1 = open("test.test",'w')
test_1.write(str(info))
str转成字符串…write存…
f = open('test.test','r')
c = compile(f.read(),'','eval')
g = eval(c)
print(g['a'])
eval(f.read),执行,赋个变量,print…这里exec好像不行(>_<) !!!
(2) json方法序列,比较普及,不同的编程语言之间都可以使用…
但是,josn只能dumps一些基本的code,复杂的序列化不了;例如:序列化一些包含函数…
enen…“敲重点”,这个时候就得用到pickle了…pickle是python自己内部的方法,python所有的“数据类型”都可以序列化…
json序列化:
import json
info ={'a': 1, 'b': 2, 'c': 3}
data = open('wenjian','w')
data.write(json.dumps(info))
json.dump(info,data)
josn反序列化:
import json
duqu = open('wenjian','r')
g = json.loads(duqu.read())
print(g['a'])
pickle序列化:(这里用“wb…写成二进制文件…)
import json,pickle
def hanshu():
print("下周满课")
info ={'a': 1, 'b': 2, 'c': 3,
"课表":hanshu}
data = open('kebibiao','wb')#这里是二进制文本...
pickle.dump(info,data)
import pickle
def hanshu():
print('下周又不是满课')
f = open('kebibiao','rb')
come = pickle.load(f)
print(come)
print(come['课表']())
Attention:
我在 序列化/反序列化时,def hanshu():…里面写了不同的print()…
即我在反序列化的时候…print输出的不一样…即就是:pickle的是整个hanshu ( )的“数据对象”…
conclude:
1.str / compile
2.f.write(json.dumps(info)) / json.dump(info,f)
jubing =json.loads(f.read) / jubing = json.load(f)
3.f.write(pickle.dumps()) / pickle.dump(info,f)
jubing = pickle.loads(f.read) / jubing = pickle.load(f)
4.每dump一次,每load一次…
5.json只能执行一些底层的…pickle可以执行一些高级的,“wb”
五、软件结构目录:
1.(怎么说呢…就是拥有一个清晰的目录结构…)
2.
(1)这里的执行文件…执行程序,去“调用”main.py主程序…
(2)__ init __.py…是"包"package,创建时就有的,和目录不一样
3.执行程序…在“调”main.py时:例如import,问题来了…???跨目录???怎么调???
之前写的day2里面,import要在“当前目录”下,才可以实现调用,还有就是放在第三方库的Lib下…下面要说的是,添加环境变量,然后进行import…
4.代码如下:
print(__file__)#相对路径
这是导入当前.py文件的"相对路径",pycharm上显示的类似于“绝对路径”,是因为它是从根开始打印的…
import os,sys
print(os.path.abspath(__file__))#绝对路径
获取绝对路径…
print(os.path.dirname(os.path.abspath(__file__)))#找到他爸爸
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))#找到他爷爷
找到当前文件目录的上一级,上上一级…
data = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#添加环境变量
sys.path.append(data)#添加环境变量
给个变量,句柄添加…
enen…后面可以正常import跨目录文件…
conclude:
1.os,sys / abspath / dirname / sys.path.append /