本节内容
- 迭代器&生成器
- 装饰器
- Json & pickle 数据序列化
- 软件目录结构规范
- 作业:ATM项目开发
列表生成式 .迭代器 & 生成器
列表生成式
列表生成式,是Python内置的非常简单却强大的可以用来创建列表的生成式。
运用列表生成式,可以快速生成列表 .可以通过一个 list 推导出另一个list,而代码却十分简洁。
现在我们有一个需求,要求将列表 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 里的没一个元素加 “1”.
1 #Author:Junce Liu
2 a =[] # 定义列表
3 for i in range(10):
4 a.append(i*2) # 列表生成
5 print(a)
6
7 输出结果如下: # 实验时用的Pycharm,视觉效果不是很直观 .
8 [0]
9 ......... # 此处省略......
10 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
小结
通过列表生成式,我们可以直接创建一个列表. but受到内存限制。
列表的容量是有限的,创建一个包含100万元素的列表,不仅占用很大存储空间如果仅仅需要访问其中几个元素,那么绝大多数的占用空间都浪费了。
知识拓展
使用 Python 解释器,完成如上任务。
>>> [i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
生成器
在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。在调用生成器运行的过程中 , 每次遇到 yield 时函数会暂停并保存当前所有的运行信息 , 返回yield的值 . 并在下一次执行 next() 方法时从当前位置继续运行。
生成器循环
_next_() 一次次调用实在太low,工作中用next的话没几天估计就要被开除了这里用循环调用. 让有迹可循的斐波那契数列循环。
1 #Author:Junce Liu
2 def fib(num):
3 n,a,b = 0,0,1
4 while n < num: # n < 10
5 yield b
6 a,b = b,a+b
7 n = n + 1 # n = 1 循环10次
8 print(fib(10))
9 for i in fib(10): # for循环10次
10 print(i)
取值方式班的有迹可循,每取一次值返还的按照斐波那契的规律取值!!!
- 输出结果如下:
<generator object fib at 0x0000000001056A98> # 返回的字符串四层相识吧,是一串地址....
1
1
2
3
5
后面的省略………
特性
生成器 只有在调用时才会生成相应的数据
- 只记录当前位置
- 只有一个
__next __()
方法,需要一次一次地取值。
山炮版生成器
在生产环境中基本永远不会这么干,_next_() 的取值方式无法挽尊.这里只需了解生成器的返还是一个储存地址,通过迭代方式取值。
1 #Author:Junce Liu
2 a = (2 * i for i in range(1000)) # 生成器循环1000次,每循环一次*2
3 print(a)
4 print(a.__next__()) # 用__next__()取值,每取值一次 *2
5 print(a.__next__())
6 print(a.__next__())
7
8 输出结果如下:
9 <generator object <genexpr> at 0x0000000000A16A98> # 这里没生成实际列表,而是返回一个存储地址.
10 0
11 2
12 ......
如上所示,生成器只能一次次地取值.如果数值1000W我们要取值100W的值 . 即使有神之右手也挽不了尊。
but anyway 生成器还可以用函数取值,比如著名的斐波那契数列
1 #Author:Junce Liu
2 def fib(num):
3 n,a,b = 0,0,1
4 while n < num: # n < 10
5 print("\033[31;1m This is b \033[0m>>>:",b)
6 a,b = b,a+b # 每次循环只打印"b"每次循环只打印"b",每次打印推断后一位。
7 n = n + 1 # n = 1 循环10次
8 return "done"
9 fib(10)
通过结果我们可以发现一个规律,从第三位开始 — >每后面一位整数是前两位之和.即为 a + b 之和。
- 输出结果如下:
This is b >>>: 1
This is b >>>: 1
This is b >>>: 2
This is b >>>: 3
This is b >>>: 5
This is b >>>: 8
This is b >>>: 13
This is b >>>: 21
This is b >>>: 34
This is b >>>: 55
注意
有同学可能会不理解逻辑关系,我们这里主要看 a,b = a,a+b 矛盾点就在这里。
a,b = b,a+b
相当于 t = (b,a+b) # t 是一个元组(tuple),不必写出临时变量 t 就可以赋值
- a = t[0]
- b = t[1]
迭代器
迭代是Python最强大的功能之一,是访问集合元素的一种方式。可以记住遍历的位置的对象,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束 .
详解
我们已经知道 . 可以直接作用于for循环的数据类型,这些可以直接作用于for循环的对象统称为可迭代对象(Iterable)循环即可迭代。迭代器更相当于一个概念,在底层封装
- 集合数据类型:list、tuple、dict、set、str……
- 生成器:包括生成器带 yield 的生成器、函数生成器
特性
- 只能往前不会后退
- 迭代器有两个基本的方法 iter() & next()
判断迭代
在Python中可以通过 isinstance( ) 检验对象是否可迭代 .
- 参数 Iterable 为判断是否是迭代对象
- 参数 Iterator 为判断是否是迭代器
- 参数 iter() 可将迭代对象转换成迭代器
以下两条皆为 Pycharm 执行格式
1 #Author:Junce Liu
2 import collections
3 ret = isinstance([],collections.Iterable)
4 print(ret)
5 ret2 = isinstance(iter([]),collections.Iterator)
6 print(ret2)
7
8 输出结果如下:
9 True
10 True
以下两条皆为 Python3.5.2 执行格式
>>> from collections import Iterable # 判断是否为迭代对象
>>> isinstance([],Iterable)
True
>>> from collections import Iterator # 判断是否为迭代器
>>> isinstance ((x for x in range(5)),Iterator)
True
>>> isinstance(iter([]),Iterator) # 通过内置iter将迭代对象转换为迭代器
True
标准迭代器
1 #Author:Junce Liu
2 import collections
3 a = [1,2,3]
4 print(iter(a))
5 b = iter(a)
6 print(b.__next__())
7
8 输出结果如下:
9 <list_iterator object at 0x00000196D081C828> # 似曾相识的字符串,迭代器地址
10 1
为什么list、dict、str等数据类型不是Iterator?
Python的迭代器对象表示的是一个数据流,
Iterator
对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator的计算是惰性的
,只有在需要返回下一个数据时它才会计算。Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结
凡是可作用于for循环的对象都是
Iterable
类型;
凡是可作用于next()函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如 list、dict、str 等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
Python的for循环本质上就是通过不断调用next()函数实现的.
例如:
1 #Author:Junce Liu
2 for x in [1, 2, 3, 4, 5]:
3 pass
实际上完全等价于
如下:
1 #Author:Junce Liu
2 it = iter([1, 2, 3, 4, 5]) # 首先获得Iterator对象
3 while True: # 循环
4 try:
5 x = next(it) # 获得下一个值
6 except StopIteration: # 遇到StopIteration就退出循环
7 break
装饰器
装饰器本质是函数,用于装饰其他函数为其他函数添加附加功能。实现在代码运行期间修改函数的上下文,即可以定义函数在执行之前进行何种操作和函数执行后进行何种操作, 而函数本身并没有任何的改变。
特性
- 不修改被装饰的函数源代码.
- 不修改被装饰的函数的调用方式.
函数运行 时间计算.
1 #Author:Junce Liu
2 import time # 调用time模块
3 def timmer(func): # 定义一个装饰器,计算函数运行的时间。
4 def warpper(*args,**kwargs):
5 start_time = time.time()
6 func()
7 stop_time = time.time()
8 print('the func run time is %s' %(stop_time-start_time))
9 return warpper
10
11 @timmer # 将装饰器调用
12 def fun():
13 time.sleep(3)
14 print("玉树临风柳少年\n")
15 fun()
16 输出效果显示如下:
17 玉树临风柳少年 # 符合原则
18 the func run time is 3.000166416168213 # 装饰效果
知识储备
- 函数即”变量”
- 高阶函数
- 嵌套函数
函数即”变量”
在了解这个概念之前,我们先回顾一下前期讲到的”变量”。
- x =1
- y = 2
当变量定义后,会在内存中开辟出一块独立的空间以供调用.(C 语言是这样的,Python是直接引用内存中的数据)
话不多说,有图有真相
如下所示:
上图诠释了变量的定义关系,变量定义后内存空间中的 “1” & “2” 独立存在于自己的小空间之中。我们暂且称之为 “小房间”,而变量名 x & y 相当于各自的门牌号,通过调用门牌号的形式调用对应的变量。
1 #Author:Junce Liu
2 x = 1
3 y = 2
4 print(x,y)
5
6 输出结果如下:
7 1 2
了解了变量的概念,思维转换下写出如下代码在Pycharm中执行
少年早已识破天机!!!
1 #Author:Junce Liu
2 def foo():
3 print("in the foo") # 函数体,即功能这里简要写...
4 py() # 调用函数 py
5 def py():
6 print("in the py")
7 foo() # 调用函数 foo
8
9 输出结果如下:
10 in the foo
11 in the py
OK,看到这如果你还不了解函数即变量的概念 ……
再上一张图,如下所示:
高阶函数
我们了解了函数、特性以及用法但还是过不好一生 …..
何谓高阶函数?
- 把函数名当做实参传给另一个函数
- 返回值中包含函数名
必须满足如上两个条件,方为高阶函数。
而函数都满足,函数即变量的原则。
1 #Author:Junce Liu
2 def test():
3 print("密码:12345678")
4 def fun(data):
5 print(data)
6 print("成功破解隔壁WiFi")
7 data()
8 fun(test) # 将函数名test传入fun
9
10 输出结果如下:
11 <function test at 0x0000019CB5D8F598> # 出现了一段生僻字,这里表示为变量名(门牌号)的所在地址
12 成功破解隔壁WiFi
13 密码:12345678
知识拓展
有同学可能还不理解,为什么data可调用并且被赋值呢?
fun(test),这步操作相当于把 “tase” 量名指向赋值给 “data”.执行时像变量一样来回调用
表现形式为:
- data = test
- “test” 相当于变量名(门牌号),所指向的地址.
因此执行出现 ”<function test at 0x0000019CB5D8F598>
“
记录 test 传入时间
1 #Author:Junce Liu
2 import time # 调用了一个模块
3 def test():
4 print("密码:12345678")
5 time.sleep(3) # 因为Pycharm执行时间实在太快,加3秒更明显。
6 def fun(data):
7 print(data)
#print("成功破解隔壁WiFi") # 注释掉代码看效果
9 start_time = time.time()
10 data() # 这里运行的是"test"
11 stop_time=time.time()
12 print("test 执行时所花费的时间为%s 秒"%(start_time-stop_time))
13 fun(test) # 将函数名test传入fun
14 输出结果如下:
15 <function test at 0x000001F6C4A5F2F0>
16 密码:12345678
17 test 执行时所花费的时间为-3.000290632247925 秒
嵌套函数
在已有的一个函数里声明一个函数,我们称之为嵌套.其中局部作用域与全局作用域的执行顺序为”由里到外”
1 #Author:Junce Liu
2 def fun():
3 print(" in the fun")
4 def data():
5 print("in the data")
6 data() # 注意 全局 & 局部变量的定义,这里只能在外面不调用
7 fun()
8 输出结果如下:
9 in the fun
10 in the data
完美装饰器
最后来一个漂亮甩尾吧!!!
1 #Author:Junce Liu
2 User,Passwd = 'Junce','123'
3 def auth(auth_type):
4 print("auth ",auth_type)
5 def outer_wrapper(func):
6 def wrapper(*args, **kwargs):
7 print("Wrapper func args:",*args, **kwargs)
8 if auth_type == 'local':
9 user = input("账号:")
10 passwd = input("密码:")
11 if user == User and Passwd == passwd:
12 print("\033[31;1m 账号密码输入正确 \033[0m")
13 res = func(*args, **kwargs) # from home
14 print("-------- 通过验证 --------")
15 return res
16 else:
17 exit("\033[31;1m 账号或密码输入有误 \033[0m")
18 elif auth_type == 'Ldap':
19 print("验证个毛线ldap,服务还没起来!")
20 return wrapper
21 return outer_wrapper
22
23 @auth(auth_type="local")
24 def home():
25 print("\033[34;1m 欢迎登陆朔天论坛 \033[0m")
26 @auth(auth_type="Ldap") # sec = wrapper
27 def sec():
28 print("\033[36;1m 欢迎来到朔天官网 \033[0m")
29 return "from sec"
30 home()
31 print(sec())
输出结果如下:
auth local
auth Ldap
Wrapper func args:
账号:Junce
密码:123
账号密码输入正确
欢迎登陆朔天论坛
——– 通过验证 ——–
Wrapper func args:
验证个毛线ldap,服务还没起来!
None
未完待更新…….
各位看博客的妹子们,现在页面是不是还丑了点?是的,我自己都不想看…..回头讲页面优化一并将这个做了。