python_day4_装饰器详解(函数及变量/高阶函数/嵌套函数)/装饰器案例/迭代器与生成器/内置方法/Json与pickle数据序列化/软件目录结构规范

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 /

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值