关闭

python学习之路-基础篇-day04

标签: python迭代器装饰器生成器序列化和反序列化
108人阅读 评论(0) 收藏 举报
分类:

大纲:
1.装饰器
2.迭代器
3.生成器
4.json和pickle的序列化和反序列化
一.装饰器decorator
1.什么是装饰器?
装饰器的本质就是返回函数的高阶函数,用来装饰其他函数,为其他函数添加一些附加的功能
2.装饰器的原则
1)不能修改被装饰函数的源代码
2)不能修改被装饰函数的调用方式
3.怎样实现一个装饰器呢?
1)一切皆是对象,所以在python中函数也是对象,函数可以赋值给一个变量
2)函数还可以被定义在另一个函数里面
=>一个函数可以返回另一个函数

4.装饰器详解
第一部分

import time
#先定义一个函数实现了某个功能
def test():
    time.sleep(3)
    print("i am test")
#现在来一个新的需求,我需要给这个函数增加一个计算函数运行时间的功能,怎么办呢??
#首先想到的方法是,直接在函数的内部添加
def test():
    time.sleep(3)
    print("i am test")
start_time = time.time()
test()
end_time=time.time()
print("running time is %s",end_time-start_time)
# 但是现在我有很多个类似于test的函数test1(),test2()...都需要添加同样的功能,那么逐个添加的方法效率低,
# 也会使得程序过于陇长,实在是low

第二部分–改变了函数的调用

#那么我就想单独定义计算程序运行时间的方法吧,然后进行调用
def test():
    time.sleep(3)
    print("i am test")
def timmer(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print("running time is %s", end_time - start_time)
timmer(test)
#但是这样的改法改变了代码的逻辑结果,之前运行代码只需要test(),现在却需要timmer(test),有没有更优的办法呢?

第三部分–闭包

#在此之前我们需要讲一个新的概念---闭包
def outer():
    x=10
    def inner():#inner是局部变量,全局无法直接调用#内部函数-条件1
        print(x)#x是外部环境变量-条件2
    return inner#内部函数inner就是一个闭包-结论
#我现在只想执行inner函数,执行方法有两种
#第一种outer()()
#第二种f=outer()  f()
#闭包--如果一个内部函数,对在外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就认为是闭包
#这里内部函数是inner,外部变量是x

第四部分–重点来啦

def timmer(func):
    def deco():
       start_time = time.time()
       func()
       end_time = time.time()
       print("running time is %s", end_time - start_time)
    return deco
def test():
    time.sleep(3)
    print("i am test")
test=timmer(test)#得到的是deco函数的内存地址
test()#执行deco函数,闭包原理

第五部分-装饰器

#装饰器!!!
#新附加的功能timmer就是装饰器,可以把真正需要执行的业务包裹在里面,利用timmer来装饰test,@符号是装饰器的语法糖
#也就是省去了test=timmer(test),直接调用test就可以了
def timmer(func):#func就是返回的deco的内存地址
    def deco():
       start_time = time.time()
       func()
       end_time = time.time()
       print("running time is %s", end_time - start_time)
    return deco
@timmer
def test():
    time.sleep(3)
    print("i am test")
test()

带参数的装饰器
上面的装饰器只能实现只能实现无参数的情况,那么怎样实现带参数情况

def timmer(func):#func就是返回的deco的内存地址
    #定义一个内嵌的包装函数deco,给传入的函数加上计时功能的包装
    def deco(*args,**kwargs):
       start_time = time.time()
       func(*args,**kwargs)
       end_time = time.time()
       print("running time is %s", end_time - start_time)
    ## 将包装后的函数返回
    return deco
@timmer
def test(name,age):
    time.sleep(3)
    print("i am test",name,age)
test("coco",7)

我们再举个带参装饰器的例子加深印象

import time
def show_time(f):  #装饰器函数
    def inner(*x,**y):
        start=time.time()
        f(*x,**y)
        end=time.time()
        print("cost %s"%(end-start))
    return inner

@show_time
def foo(*a,**b):  #功能函数
    sum=0
    for i in a:
        sum+=i
    print(sum)
    time.sleep(1)
foo(1,2,3) #6

装饰器带参数

import time
def log(flag):#为了在show_time里面运用标志位,对代码进行更灵活的操作
    def show_time(f):  #装饰器函数
        def inner(*x,**y):
            start=time.time()
            f(*x,**y)
            end=time.time()
            print("cost %s"%(end-start))
            if flag=="true":
                print("log")
        return inner
    return show_time

@log("true")#@show_time
def foo(*a,**b):  #功能函数
    sum=0
    for i in a:
        sum+=i
    print(sum)
    time.sleep(1)
foo(1,2,3) #6

二.迭代器
1.什么是迭代器Iterator
a.可以直接作用于for循环的对象统称为可迭代对象(Iterable)
有哪些是可以进行for循环的对象呢?
列表,字典,元祖,字符串。。。
b.可以被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator)

a=[1,2,3]
b=iter(a)
print(next(b))
print(next(b))
print(next(b))
#依次取出列表里面的值

总结:凡是可做for循环的对象都是可迭代的类型
凡是可做next()函数的对象都是迭代器类型
三.生成器Generator
1.生成器的使用

#通过列表生成式,我们可以直接创建一个列表,但是受到内存的限制,列表的容量是有限的,
# 所有通过列表生成的元素都是占用内存的,而我们只用到一部分的元素,这就造成了内存的浪费
x=[i*2 for i in range(10)]
print(x)#[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
print(type(x))#<class 'list'>
#等价于
x=[]
for i in range(10):
    x.append(i*2)
#在Python中,这种一边循环一边计算的机制,称为生成器,这样大大的节省了内存,创建生成器的方法有多种
#方法1,将[]改成()
x=(i*2 for i in range(10))
print(type(x))#<class 'generator'>
#进行遍历,一个元素一个元素的生成,不占用内存。生产器只有在调用时才调用时才会产生相应的数据
#只有一个__next__()方法,一般我们不这么用,等价于next(x)

2.举例斐波那契数列(任意一个数可由前面两个数相加得到)

def fib(max):
    n,a,b=0,0,1
    while n<max:
        print(b)
        a,b=b,a+b#=>相当于元祖  不是等价于a=b,b=a+b   而是x=(b,a+b)  a=x[0]   b=[a+b]
        n=n+1
fib(10)
#我们对以上的程序稍作修改
def fib(max):
    n,a,b=0,0,1
    while n<max:
        yield b  #某个函数包含了yield,这意味着这个函数已经是一个Generator
        #当调用fib函数后,整个函数都不会执行。必须通过__next__()方法才能取出里面的值
        a,b=b,a+b#=>相当于元祖  不是等价于a=b,b=a+b   而是x=(b,a+b)  a=x[0]   b=[a+b]
        n=n+1
f=fib(10)
print(f.__next__())
print(f.__next__())#调用一次__next__()就能够取出生成器里面的值

3.这里我们补充一个yield是使用,使用了yield,函数就变成了生成器啦!!!
利用yield(生成器)做一个简单的生产者消费者模型,也就是初步认识一下协程。具体什么是生产者消费者模型,什么是协程我们后面的章节会具体进行讲解

import time
def consumer(name):
    print("%s 想去商店买包子吃了"%name)
    while True:
        baozi=yield
        print("包子%s已经买到了,被%s吃了"%(baozi,name))
def product(name):
    a=consumer("coco")
    b=consumer("noki")
    a.__next__()
    b.__next__()
    print("我们商店开始生产包子并且出售啦")
    for i in range(10):
           time.sleep(1)
           a.send(i)
           b.send(i)
product("amy")

四.json和pickle序列化和反序列化
1.概念:
序列化: 将数据结构或对象转换成二进制串等的过程
反序列化:将在序列化过程中所生成的二进制串等转换成数据结构或者对象的过程
2.作用:
使用序列化主要是因为跨平台和对象存储的需求,和数据的传输(也就是不同类型语言的数据交换)
很多语言例如c,Java等都支持序列化和反序列化,这里python有两种方式可以选择json和pickle
3.json序列化和反序列化
json数据类型和python数据类型的相互转换

import json
dic={"name":"飞鸟","age":9,"sex":"F"}
print("原数据:",dic)#{"name":"飞鸟","age":9,"sex":"F"}
print("原数据类型:",type(dic))#<class 'dict'>
#我们先查看一下json到底有哪些方法
print(json.__all__)
#['dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONEncoder']
#dumps是将dict转化成str格式,loads是将str转化成dict格式
#dump和load也是类似的功能,只是与文件操作结合起来了
#1.下面将这个字典进行序列化
print("序列化后的数据:",json.dumps(dic))#{"age": 9, "name": "\u98de\u9e1f", "sex": "F"}
print("序列化后的数据类型:",type(json.dumps(dic)))#<class 'str'>
#2.进行序列化后中文变成了unicode编码,那么怎么将序列化后的中文还是中文呢?
#需要添加ensure_ascii=False
print("处理后的序列化后的数据:",json.dumps(dic,ensure_ascii=False))#{"age": 9, "name": "飞鸟", "sex": "F"}
print("处理后的序列化后的数据:",type(json.dumps(dic,ensure_ascii=False)))#<class 'str'>
#反序列化
dumps_dic=json.dumps(dic,ensure_ascii=False)
loads_dic=json.loads(dumps_dic)
print(loads_dic)#{'age': 9, 'name': '飞鸟', 'sex': 'F'}
print(type(loads_dic))#<class 'dict'>
3.文件序列化和反序列化操作
import json
#新建一个列表
li=["小米",16,"M","worker"]
print(type(li))#<class 'list'>
#将列表序列化写入文件里面,中文都要加上ensure_ascii=False,在D盘会生产新的文件
dump_li=json.dump(li,open("D:/work.txt","w"),ensure_ascii=False)
print(type(dump_li))#<class 'NoneType'>
#反序列化
load_li=json.load(open("D:/work.txt","r"))
print(type(load_li))#<class 'list'>

4.pickle序列化和反序列化

import pickle
print(pickle.__all__)

pickle和json的(dump,dumps,load,loads)的用法是一模一样的,只是将json改成pickle就可以啦
总结:
1.json是标准的数据接口格式,所以json适用于所有的语言间的数据的传输,但是pickle只适合于python间的数据传输
2.pickle不仅可以序列化常规的数据类型还可以序列化类等
3.json只能序列化字典,列表之类的常规数据类型
五.动态的获取绝对路径

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3035次
    • 积分:329
    • 等级:
    • 排名:千里之外
    • 原创:32篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类