跟着ALEX 学python day4集合 装饰器 生成器 迭代器 json序列化

时间:2023-03-08 23:29:28
跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

文档内容学习于

http://www.cnblogs.com/xiaozhiqi/ 

装饰器 :

定义: 装饰器 本质是函数,功能是装饰其他函数,就是为其他函数添加附加功能。

原则:

1、不能修改被装饰的函数的源代码

2、不能修改被装饰的函数的调用方式

看以下

[root@localhost day4]# cat decorator.py
#!/usr/bin/env python3 import time
def timmer(func): #装饰器。 其实编写当时和写函数 是一样的
def warpper(*args,**kwargs):
start_time = time.time()
func()
stop_time =time.time()
print ("the func run time is %s" %(stop_time-start_time))
return warpper @timmer #使用装饰器(这个装饰器的作用其实是统计test1 这个函数的运行时间),然后这个装饰器 对被修饰的 test1这个函数 这个其实是不影响的。 并没有违背以上2条原则。 def test1():
time.sleep(3)
print ("this is test")
return 0 test1() [root@localhost day4]# ./decorator.py
this is test
the func run time is 3.0033674240112305 #装饰器的效果 ,统计test1 函数的运行时时间。

我们  一步 一步 把装饰器 拆开来 慢慢 理解 。

装饰器的知识储备

1. 函数即“变量”

这个概念  可以看视屏day4__5.  简单说就是 python通过内存地址(函数名,变量名)来调用变量(函数)。

2.高阶函数

3.嵌套函数

高阶函数+  嵌套函数==>  装饰器

然后 我们 引用

1.函数即“变量”

2.高阶函数

之前我们提到了 高阶函数的 概念

1.  把一个函数名当做实参传给另一个函数

2. 返回值中包含函数名

的概念   其实功能 就类似以下。   但是以下不是装饰器。只是功能类似。因为他违背了2、不能修改被装饰的函数的调用方式 的规则(这个说明只是为了帮助理解)

import  time

def bar():                                       #定义了bar 这个函数
time.sleep(3)
print ("in the bar") def test(func): # bar作为实参传进来, 这个 其实这个时候func就等于bar 这个函数了
start_time = time.time()
func() # 运行 func这个变量(函数),, 其实就运行了bar这个函数
stop_time =time.time()
print ("the func run time is %s" %(stop_time-start_time)) test(bar) # 将bar作为时实参传进去, 此处还需要注意,这边是传函数,不是传函数的执行结果,所有不能bar()这么写

 PS :

在以上 例子中bar其实是源代码,  虽然我们没有变化bar的源代码 。 但到最后其实调用bar的方式改变了(将bar作为实参使用了)。违背了第2条原则。  所以以上并不是装饰器。

然后我们上面看到了  高阶函数的  第二条定义

2. 返回值中包含函数名

我们做以下尝试

import  time

def bar():
print ("in the bar") def test(func):
start_time = time.time()
func()
stop_time =time.time()
print ("the func run time is %s" %(stop_time-start_time))
return func # 进行这个变量(函数)作为返回值 ,这样这个函数的执行结果就是这个函数的内存地址(这个函数的变量名),就可以定义在外面定义变量了。 bar = test(bar) #这样再定义bar,就可以不修改 bar这个源代码的调用方式了。
bar()

通过以上例子 我们可以发现  

返回值中包含函数名    的 作用相当于   不修改函数的调用方式  

这样,我们对于高阶函数的定义 ,在装饰器中可以理解为

1.  把一个函数名当做实参传给另一个函数(不修改被装饰函数的情况下不修改源代码 )

2. 返回值中包含函数名(不修改函数的调用方式  )

嵌套函数

就是在函数里面 在再定义一个函数

def  foo():
print("in the foo")
def bar (): #这里定义的bar函数,一定要在foo里面才能调用, 作用类似于局部变量,bar这个函数在全局是不生效的。
print ("in the bar")
bar() foo()

看以下

[root@master day4]# cat  decarate.py
#!/usr/bin/env python3 x = 0
def grandba():
x = 1
def dad():
x = 2
def son():
x = 3
print (x)
son()
dad() grandba() [root@master day4]# ./decarate.py
3

然后将高阶函数和 嵌套函数结合起来使用

[root@localhost day4]# cat decorator2.py
#!/usr/bin/env python3 import time def timer(func): # 高阶函数: 把函数作为实参进来
def deco(): # 嵌套函数:函数里面定义函数
start_time=time.time()
func()
stop_time=time.time()
print ("the func run time is %s" %(stop_time-start_time))
return deco #高阶函数:用函数作为返回值。 这边定义的返回值其实是deco这个函数, 在timer这个函数里面无需执行 def test1():
time.sleep(3)
print ("in the test1") test1 = timer(test1) # 外部调用函数
test1()

[root@localhost day4]# ./decorator2.py
in the test1
the func run time is 3.0034003257751465

@符

在python3中可以直接使用 @ 符号来调用装饰器。

1.它一定要写在被修饰函数的前面

[root@localhost day4]# cat decorator2.py
#!/usr/bin/env python3 import time def timer(func):
def deco():
start_time=time.time()
func()
stop_time=time.time()
print ("the func run time is %s" %(stop_time-start_time))
return deco @timer #直接@符加修饰器名字。 但是一定要写在被修饰函数的前面 @time ==== test1=timer(test1)
def test1():
time.sleep(3)
print ("in the test1") test1()
[root@localhost day4]# ./decorator2.py
in the test1
the func run time is 3.003570795059204

完整的装饰器

装饰器的源代码使用传参

理解 一下。  是在理解不了,就死记吧。  要传参就是,需要deco和 func这边也将形参写好。

[root@localhost day4]# cat decorator2.py
#!/usr/bin/env python3 import time def timer(func):
def deco(*args,**kwargs): ### 进行传参
start_time=time.time()
func(*args,**kwargs) ### 因为这个func函数在这边是直接调用的,不是定义的。所以参数需要deco传进来
stop_time=time.time()
print ("the func run time is %s" %(stop_time-start_time))
return deco @timer # test2 = timer(test2) ==> 其实 test2()== fun() 执行是 deco(),所以test2()传参就是 deco() 传参 再传给func() def test2(name,age):
time.sleep(1)
print ("this is %s,%s" %(name,age) ) test2("haha",55) [root@localhost day4]# ./decorator2.py
this is haha,55
the func run time is 1.0164666175842285

查看  以下代码:

有3个页面 index  home  bbs 。 本来是直接就能访问。   现在需要有的页面认证才能访问 。

所以 就有了一个 认证的装饰器 。

# Author ricky

username,passwd = "ricky","123"

def auth(func):                                                          #认证页面的装饰器
def wrapper(*args,**kwargs):
Uname = input ("please input your name ").strip()
Passwd = input ("please input your passwd ").strip()
if Uname == username and Passwd == passwd: # 判断用户和密码
print("\033[32;1mAuth is ok\033[0m")
func(*args,**kwargs)
else:
print ("\033[31;1mInvaild Auth\033[0m") #认证不通过直接就退出了
exit()
return wrapper def index(): #index不需要认证
print ("welcome to index") @auth #home页面需要认证
def home():
print ("welcome to home") @auth #bbs页面需要认证
def bbs():
print ("welcome to bbs") index()
home()
bbs()

执行一下. 结果如下 。

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

如果我们源码里面就有 return的, 这个时候为了不改变他的调用方式。需要进行以下修改

[root@master day4]# cat decarate2.py
#!/usr/bin/env python3 username,passwd = "ricky","123" def auth(func):
def wrapper(*args,**kwargs):
Uname = input ("please input your name ").strip()
Passwd = input ("please input your passwd ").strip()
if Uname == username and Passwd == passwd:
print("\033[32;1mAuth is ok\033[0m")
res = func(*args,**kwargs) #用一个了变量来指定这个func的执行结果。 同时这个函数已经执行了 。
print ("after func") # 标记位
return res # 返回func这个函数的执行结果,不能直接return func。因为直接return func的话。就等于这个func又执行了一下。所以需要用变量来代替。
else:
print ("\033[31;1mInvaild Auth\033[0m")
return wrapper def index():
print ("welcome to index") def home():
print ("welcome to home") @auth
def bbs():
print ("welcome to bbs")
return ("from bbs") #函数本生是有return。
index()
home()
print (bbs()) # 直接打印执行结果 [root@master day4]# ./decarate2.py
welcome to index
welcome to home
please input your name ricky
please input your passwd 123
Auth is ok # 认证ok
welcome to bbs # 执行wrapper(func===bbs)函数、 其实是在定义res变量的时候执行的
after func # 标记位
from bbs # 指定了 bbs函数的执行结果 、

上面例子中。 如果我们在  wrapper  里面直接 return了 func(),func()会有执行一遍。 查看以下

username,passwd = "ricky","123"

def auth(func):
def wrapper(*args,**kwargs):
Uname = input ("please input your name ").strip()
Passwd = input ("please input your passwd ").strip()
if Uname == username and Passwd == passwd:
print("\033[32;1mAuth is ok\033[0m")
func(*args,**kwargs)
print ("after func")
return func(*args,**kwargs) # 接 return了 func(), 这个如果直接return了 func的话 只是打印func这个函数的内存地址。上面有提到过。 所以func(),才是他的执行结果
else:
print ("\033[31;1mInvaild Auth\033[0m")
return wrapper def index():
print ("welcome to index") def home():
print ("welcome to home") @auth
def bbs():
print ("welcome to bbs")
return ("from bbs") index()
home()
print (bbs())

看,func执行了2遍。 所以正确的做法需要用个变量和存他的执行结果 。

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

完整的装饰器2

这边知识点是,装饰器使用参数 。

以上的脚本的认证使用时了用户名和密码。  如果这边有个 ldap服务的 也可以进行认证 。 那么这边就需要判断  是使用用户名进行认证 还是ldap进行认证

其实不难,就是加了一层函数。来进行判断

[root@master day4]# cat  decarate3.py
#!/usr/bin/env python3 # Author ricky username,passwd = "ricky","123" def auth(auth_type): #看这边的形参,已经不是func了。 而是装饰器调用时传参使用的变量
def out_wrapper(func): #多加了一层函数,这边使用的形参才是 func
def wrapper(*args, **kwargs):
if auth_type == "local": #这边就是用来判断认证方式的,就是外面装饰器传参的变量
print ("Need you username and passwd")
Uname = input("please input your name ").strip()
Passwd = input("please input your passwd ").strip()
if Uname == username and Passwd == passwd:
print("\033[32;1mAuth is ok\033[0m")
res = func(*args, **kwargs)
return res
else:
print("\033[31;1mInvaild Auth\033[0m")
elif auth_type == "ldap": #这边就是用来判断认证方式的,就是外面装饰器传参的变量
print ("it is ldap")
return wrapper # return第一层
return out_wrapper # return第二层 def index():
print ("welcome to index") @auth(auth_type="local") #这边先定义了认证的方式,其实就是装饰器传参
def home():
print ("welcome to home") @auth(auth_type="ldap") #这边先定义了认证的方式,其实就是装饰器传参
def bbs():
print ("welcome to bbs")
return ("from bbs") index()
home()
bbs() [root@master day4]# ./decarate3.py
welcome to index
Need you username and passwd
please input your name ricky
please input your passwd 123
Auth is ok
welcome to home
it is ldap
[root@master day4]#

迭代器&生成器

列表生成式

[root@localhost day4]# cat new.py
#!/usr/bin/env python3 a = [ i*2 for i in range(10)] # 生成列表, 0-9的数字, 都会乘以2.
print ( a )
[root@localhost day4]# ./new.py
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

什么是生成器?

  通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

  所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator

1.当列表中有100W字符的时候 列表是会将100W字符都先生产。不管用不用。

生成器的 只会先告诉你生成了。  其实并没有全部生成。 只有当你调用的时候才会生成相应的数据。

[root@localhost day4]# cat generator.py
#!/usr/bin/env python3 a = [ i*2 for i in range(10)]
print ( type(a) ) b = ( i*2 for i in range(10)) # 其实就是讲【】 改成()
print( b ) [root@localhost day4]# ./generator.py
<class 'list'>
<generator object <genexpr> at 0x7f5296f1ed58>
 

调用生成器,出了用for循环你。  还可以用__next__()方法

b = ( i*2 for i in  range(10))
print( b ) print ( b.__next__())
print ( b.__next__())
print ( b.__next__())

next 就是一个 一个往后调用。而且 因为他只是记录了当前的数据。所以只能往后生成。不能往前。

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

例子:

斐波那契 数列

这个数列从第3项开始,每一项都等于前两项之和

[root@master day4]# cat  feibo.py
#!/usr/bin/env python3 def feibo(max):
n,a,b = 0,0,1
while n < max:
print (b)
a,b = b, a + b # 注意 这边一定要这个样子赋值,因为只有这个样子赋值的时候。 虽然a=b, 但是给b赋值的时候,其实a还没有生效。 还是前一次的数值。
n = n+1
return 'done' feibo(10)
[root@master day4]# ./feibo.py
1
1
2
3
5
8
13
21
34
55

查看赋值语句

a,b = b, a + b

其实等于 t = (a, a+b) #t 是一个tuple 相当于一个临时变量
a = t[0]
b = t[1]

如果不写在,在给b赋值的时候,a就已经生效了,会出现以下效果

[root@master day4]# cat  feibo.py
#!/usr/bin/env python3 def feibo(max):
n,a,b = 0,0,1
while n < max:
print (b)
a = b
b = a + b #当给b赋值的时候, a其实已经生效了。 所以就会出现翻倍的效果
n = n+1
return 'done' feibo(10)
[root@master day4]# ./feibo.py
1
2
4
8
16
32
64
128
256
512

然后这个数列,离生成器, 只差一步了。 就是将 print改成  yield

[root@master day4]# cat feibo.py
#!/usr/bin/env python3 # Author ricky def feibo(max):
n,a,b = 0,0,1
while n < max:
# print (b)
yield b
a,b = b, a + b
n = n+1
return 'done' print ( feibo(10) ) # 函数里面没有 print了。 直接当他变成生成器了。 所以直接执行函数是没有效果的 。这边需要打印他。
[root@master day4]# ./feibo.py
<generator object feibo at 0x7f2e7079be08>

然后可以使用__next__()  取值

[root@master day4]# cat feibo.py
#!/usr/bin/env python3 # Author ricky def feibo(max):
n,a,b = 0,0,1
while n < max:
# print (b)
yield b
a,b = b, a + b
n = n+1
return 'done' f = feibo(10)
print ( f.__next__() )
print ( f.__next__() )
print ( f.__next__() )
print ( f.__next__() )
print ( f.__next__() ) [root@master day4]# ./feibo.py
1
1
2
3
5

也可以通过,for循环来取。因为他生成器,所以取过的值,它不会再有了

[root@master day4]# cat feibo.py
#!/usr/bin/env python3 # Author ricky def feibo(max):
n,a,b = 0,0,1
while n < max:
# print (b)
yield b
a,b = b, a + b
n = n+1
return 'done' f = feibo(10) print ( f.__next__() )
print ( f.__next__() )
print ( f.__next__() )
print ( f.__next__() )
print ( f.__next__() ) print ("======start loop")
for i in f :
print (i)
[root@master day4]# ./feibo.py
1
1
2
3
5
======start loop
8
13
21
34
55

抓异常

我们再函数中  有return。

当我们使用 for循环进行读取生成器的时候,没有问题

但是当我们一直使用 next的,会报错。因为如果只有10个值,取多了。他就没值了。  所以return会报错 。

看以下,我明明只有10个值,但是 我next好多。然后再执行的时候 ,就要报错。

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

然后会报 StopIteration 的错

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

为了处理这个异常,我们需要使用try。来抓这个异常 。

课里面 暂时没有细讲。  先死记吧。

[root@master day4]# cat feibo.py
#!/usr/bin/env python3 # Author ricky def feibo(max):
n,a,b = 0,0,1
while n < max:
# print (b)
yield b
a,b = b, a + b
n = n+1
return 'done' f = feibo(10) while True: # 主要就是这段 while代码。来抓取异常 。
try:
x = next(f)
print ('f:',x)
except StopIteration as e: # 这个异常字段,就是前面报的字段。 如果是报其他字段,这段代码就不生效了(要么进行字段调整) 。
print("Generator return value" , e.value)
break [root@master day4]# ./feibo.py
f: 1
f: 1
f: 2
f: 3
f: 5
f: 8
f: 13
f: 21
f: 34
f: 55
Generator return value done
yield 传参
next是能调用yield,如果要传参的话。可以使用send。
[root@localhost day4]# cat new.py
#!/usr/bin/env python3 def consumer(name):
print("%s 准备吃包子" %name)
while True:
baozi = yield
print ("包子[%s]来了,被[%s]吃了" %(baozi,name)) c = consumer("AAA") c.__next__()
c.__next__()
c.send("vegetables") # 可以传递参数
[root@localhost day4]# ./new.py
AAA 准备吃包子
包子[None]来了,被[AAA]吃了
包子[vegetables]来了,被[AAA]吃了

试一下以下代码,单线程下的并行, 可以叫‘协程’,是一种性能很高的 运行方式。

# Author ricky

import time

def consumer(name):
print("%s 准备吃包子" %name)
while True:
baozi = yield
print ("包子[%s]来了,被[%s]吃了" %(baozi,name)) def producer():
c = consumer( 'A')
c2 = consumer('B')
c.__next__() #类似于初始化
c2.__next__() #类似于初始化
print ("开始准备包子")
for i in range(10):
time.sleep(1)
print ("一个分2半")
c.send(i)
c2.send(i) producer()

迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象Iterable

可以使用isinstance()判断一个对象是否是Iterable对象:

可以使用,查看如下类型

[root@localhost day4]# cat Iterable.py
#!/usr/bin/env python3 from collections import Iterable print ( isinstance ([],Iterable)) # 列表
print ( isinstance ((),Iterable) ) # 元组
print ( isinstance ('abc',Iterable)) # 字符串
print ( isinstance (100,Iterable)) # 数字 [root@localhost day4]# ./Iterable.py
True
True
True
False

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以被next()函数调用并不断返回下一个值的对象称为迭代器Iterator

是不是  迭代器, 可以用dir查看数据类型中,有没有 next。如果没有 就不是。

下面是列表,数据类型。 没有next。不是迭代器 。

[root@localhost day4]# cat Iterable.py
#!/usr/bin/env python3 a = [1,2,3]
print (dir(a))
[root@localhost day4]# ./Iterable.py
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
[root@localhost day4]#

可以使用模块进行判定

[root@localhost day4]# cat Iterable.py
#!/usr/bin/env python3 from collections import Iterator
print ( isinstance (( x for x in range(10)),Iterator) )
[root@localhost day4]# ./Iterable.py
True

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成Iterator可以使用iter()函数:

[root@localhost day4]# cat Iterable.py
#!/usr/bin/env python3 from collections import Iterator
print ( isinstance (( x for x in range(10)),Iterator) )
print ( isinstance ([],Iterator) )
print ( isinstance (iter([]),Iterator) )
[root@localhost day4]# ./Iterable.py
True
False
True

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break

json序列化

我们把变量从内存中变成可存储或传输的过程称之为序列化,就是将内存中的数据以字符串的形式存到存储空间中。

就像以下

进行序列化

[root@localhost day4]# cat serial.py
#!/usr/bin/env python3 info = {
"name ": "AAA",
"age":22
} f = open("test.test","w") # 以字符串的形式,写到文件里面。
f.write(str(info)) f.close() [root@localhost day4]# ls
decorator1.py decorator2.py decorator.py func.py generator.py Iterable.py new.py serial.py
[root@localhost day4]# ./serial.py
[root@localhost day4]# ls
decorator1.py decorator2.py decorator.py func.py generator.py Iterable.py new.py serial.py test.test # 写在文件里面了
[root@localhost day4]# cat test.test
{'name ': 'AAA', 'age': 22}[root@localhost day4]#

然后其实可以使用json的形式下 。

使用dumps

import  json
info = {
"name ": "AAA",
"age":22
} f = open("test.test","w")
f.write( json.dumps(info) ) == json.dump(info,f) # 注意 后面是dump 写法和前面面不一样。但是执行效果是完全一样的 f.close()

使用json实施反序列化,

使用loads

import json

f = open("test.test","r")
data = json.loads(f.read()) == data = json.load(f) # 注意 后面是load 写法和前面面不一样。但是执行效果是完全一样的 print (data["age"]) f.close()

执行结果

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

 pickle

在python里面  json只能处理简单的数据。  如果需要处理复杂的问题,像函数这种的 需要使用pickle

import pickle                                               #调用pickle模块

def sayhi(name):                                            # 定义一个sayhi的函数
print ("you name:",name) info = {
"name ": "AAA",
"age":22,
'func': sayhi # 调用sayhi
} f = open("test.test","wb") # 这里需要使用wb。 以为pickle默认是使用字节的形式。
f.write(pickle.dumps(info)) # 使用pockle调用
f.close()

然后处理出来的文件是这种格式的。 这个其实不是乱码。是pickle的数据排列格式。

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

反序列化的话 ,可以这么写

import pickle

def sayhi(name):                                                 # 在反序列话的时候 需要把这个函数再写一遍。因为这个函数是上一个程序的。  程序执行完的时候。函数的内存地址就已经被释放了。 所以这边需要再写一遍
print ("you name:",name) f = open("test.test","rb")
data = pickle.loads(f.read()) print (data) f.close()

执行结果,可以看到他将“sayhi”这个函数的  内存地址直接打印出来 。 名字就叫“func”

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

可以直接执行这个func

# Author ricky

import pickle

def sayhi(name):
print ("you name:",name) f = open("test.test","rb")
data = pickle.loads(f.read()) print (data["func"]("hahaha")) #注意格式,要传参的 f.close()

执行结果:

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化

同时在反序列化中,只需要函数的名字一样就可以了。 函数的内容不需要完全一致。

看以下:

# Author ricky

import pickle

def sayhi(name):
print ("this is name2:",name) # 函数名不变,但是内容不同。 f = open("test.test","rb")
data = pickle.loads(f.read()) print (data["func"]("hahaha")) f.close()

看执行结果,依然可以执行。所以他序列化是他的整个数据对象。

跟着ALEX 学python day4集合  装饰器 生成器  迭代器   json序列化