Day4 - Python基础4 迭代器、装饰器、软件开发规范

Day4 - Python基础4 迭代器、装饰器、软件开发规范

1.迭代器&生成器

 生成器

 背景:通过列表生成式能生成一个列表,但受内存限制,列表的容量肯定是有限的。而且当列表元素很多时,会占用大量内存空间,如果只是使用其中的一些元素,那其它元素会造成空间浪费

 定义:基于以上原因,如果能通过算法推导出列表的元素,这样就不需要创建完整的list,可以节省空间。这种一边循环一边计算的机制,就叫生成器。

   格式:只需把列表生成式[]改成()即可

   方法:使用next()可以获取下一个元素,不过一般用for循环打印

 函数生成器:在函数中加入yield,函数就变成了一个生成器;而且还可以利用此特性,实现协程的效果

  

 1 #普通列表
 2 list_normal = [0,1,2,3,4,5,6,7,8,9,10]  #手动生成列表
 3 print(list_normal)
 4 #列表生成式
 5 list_auto = [i for i in range(11)]  #利用算法生成列表
 6 print(list_auto)
 7 
 8 #生成器
 9 list_generator = (i for i in range(11)) #把生成式[]改成()就是生成器了
10 print(list_generator)
11 #生成器方法
12 print(next(list_generator))
13 print(next(list_generator))
14 for i in list_generator:
15     print(i)
 1 #函数生成器
 2 def num_generator(num):
 3     i = 0
 4     while i <num:
 5         #print(i)
 6         yield i
 7         i +=1
 8     return 'done'
 9 
10 nums = num_generator(5)
11 print(nums)
12 print(nums.__next__())
13 print(nums.__next__())
14 print("干点其它事")
15 print(nums.__next__())
16 print(nums.__next__())
17 print(nums.__next__())
18 #函数生成器异常捕获处理
19 while True:
20     try:
21         print("nums:",next(nums))
22     except StopIteration as e:
23         print("nums gererator return value:",e.value)
24         break
函数生成器
 1 #单线程实现并发运算
 2 import time,os
 3 
 4 def command():
 5     print("开始ping啦")
 6     while True:
 7         addr = yield
 8         os.system("ping "+' '+ addr)
 9 
10 def ips():
11     t = command()
12     t.__next__()
13     print("开始分配IP地址")
14     for i in range(2):
15         if i == 0:
16             continue
17         else:
18             address = "10.172.116.%s"%i
19             time.sleep(1)
20             t.send(address)
21 ips()
单线程实现并发运算  

 迭代器

  可迭代对象Iterable:

  可以被for循环的数据类型,包含二类:

  1.集合数据类型:list、dict、tuple、set、str等

  2.generator,包含生成器、带yield的generator function  

1 from collections import Iterable
2 from collections import Iterator
3 
4 #判断是否是可迭代对象
5 isinstance([],Iterable)
6 isinstance({},Iterable)
7 isinstance((),Iterable)
8 isinstance('string',Iterable)
9 isinstance(100,Iterable)    #数字不可迭代

 迭代器Iterator:

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

  特性:

    把Iterable变成Iterator可以使用Iter()函数

    生成器都是Iterator对象,但list、tuple、dict等虽是Iterable,却不是Iterator

 1 #判断是否是迭代器
 2 isinstance([],Iterator)
 3 isinstance({},Iterator)
 4 isinstance((),Iterator)
 5 isinstance('string',Iterator)
 6 isinstance(100,Iterator)
 7 isinstance((x for x in range(10)),Iterator)
 8 
 9 #迭代对象转换成迭代器方法
10 Iter_list = iter([1,2,3])
11 print(iter_list)

 区别:

      Iterator对象表示的是一个数据流,可以被next()函数调用并不断返回下一个数据,直到数据抛出StopIteration错误。可以把Iterator看成是一个有序序列,但我们却不能提前知道序列长度,它可以表示一个无限大的数据流,如自然数,而这是list办不到的。 

 for循环本质上是通过不断调用next()实现的

 1 #for循环
 2 for i in [1,2,3]:
 3     print(i)
 4 
 5 #等同于下面的迭代器
 6 a = iter([1,2,3])
 7 while True:
 8     try:
 9         next(a)
10     except StopIteration:
11         break
View Code

2.装饰器

  python装饰器:http://blog.51cto.com/egon09/1836763

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

  原则:1.不能修改被装饰的函数的源代码(对被装饰函数是透明的)

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

 实现装饰器知识储备:(高阶函数+嵌套函数=装饰器)

    1.函数即“变量”

     

 

    2.高阶函数

     a.把一个函数名当做实参传给另一个函数(在不修改被装饰函数源代码的情况下为其添加功能)

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

 1 #高阶函数
 2 def bar():
 3      time.sleep(3)
 4      print('in the bar')
 5 
 6 def test2(func):
 7     print(func)
 8     return func
 9 
10 t = test2(bar)
11 t() #run bar
12 
13 bar=test2(bar)  #把之前函数bar名称覆盖了
14 bar()
高阶函数

 

    3.嵌套函数

     定义:一个函数体内用def去声明一个新的函数

1 #嵌套函数
2 def foo():
3     print('in the foo')
4     def bar():
5         print('in the bar')
6     bar()
7 foo()
嵌套函数
 1 #局部作用域和全局作用域的访问顺序
 2 x=0
 3 def grandpa():
 4     x=1
 5     def dad():
 6         x=2
 7         def son():
 8             x=3
 9             print(x)
10         son()
11     dad()
12 grandpa()   #结果是3,从最里面找变量
局部作用域和全局作用域的访问顺序

    4.装饰器案例

 1 #装饰器案例1
 2 #运行test1-->等同于运行deco-->运行deco过程中会运行原来的test1函数-->并附加了计时功能
 3 def timer(func):    #嵌套函数 timer(test1) func=test1
 4     def deco():     #高阶函数
 5         start_time = time.time()
 6         func()      #run test1
 7         stop_time = time.time()
 8         print("run time :%s"%(stop_time-start_time))
 9     return deco     #返回deco的内存地址
10 
11 @timer  #等同于test1 = timer(test1)
12 def test1():
13     time.sleep(3)
14     print('in the test1')
15 
16 test1() #run deco
装饰器案例1
 1  1 #装饰器案例2
 2  2 #实现不定量传参,装饰器更有扩展性
 3  3 def timer(func):    #嵌套函数 timer(test1) func=test1
 4  4     def deco(*arg,**kwargs):     #高阶函数
 5  5         start_time = time.time()
 6  6         func(*arg,**kwargs)      #run test1
 7  7         stop_time = time.time()
 8  8         print("run time :%s"%(stop_time-start_time))
 9  9     return deco     #返回deco的内存地址
10 10 
11 11 @timer  #等同于test1 = timer(test1)
12 12 def test1():
13 13     time.sleep(3)
14 14     print('in the test1')
15 15 
16 16 @timer  #等同于test2 = timer(test2)=deco test2(name)=deco(name)
17 17 def test2(name):
18 18     print('test2:',name)
19 19 
20 20 test1() #run deco
21 21 test2('sam')
装饰器案例2-传参
 1 #网站认证装饰器-初版
 2 #需求:登录index页面不需要认证,登录home/bbs要认证(使用装饰器)
 3 user,passwd = 'sam','123'
 4 def auth(func):    #装饰器
 5     def wrapper():
 6         username = input("Username:").strip()
 7         password = input("Password:").strip()
 8         if username == user and password == passwd:
 9             print("登录成功!")
10             func()
11         else:
12             print("用户名或密码错误.")
13     return wrapper
14 
15 def index():    #不认证
16     print("Welcome to the index page.")
17 
18 @auth
19 def home():    #装饰器认证
20     print("Welcome to the home page.")
21 
22 @auth
23 def bbs():     #装饰器认证
24     print("Welcome to the bbs page.")
25 
26 home()
27 bbs()
网站认证装饰器-初版
 1 #网站认证装饰器-进阶版
 2 #需求:登录index页面不需要认证,登录home/bbs要使用认证方式(使用装饰器),home传参数且有返回值
 3 user,passwd = 'sam','123'
 4 def auth(func):
 5     def wrapper(*args,**kwargs):
 6         username = input("Username:").strip()
 7         password = input("Password:").strip()
 8         if username == user and password == passwd:
 9             print("登录成功!")
10             res = func(*args,**kwargs)
11             #print("---认证之后---")
12             return res
13         else:
14             print("用户名或密码错误.")
15     return wrapper
16 
17 def index():
18     print("Welcome to the index page.")
19 
20 @auth
21 def home(*args):
22     print("Welcome to the home page.",args)
23     return "From home page"
24 
25 @auth
26 def bbs():
27     print("Welcome to the bbs page.")
28 
29 #home()
30 print(home('sam'))
网站认证装饰器-进阶版
 1 #网站认证装饰器-终极版
 2 #需求:登录index页面不需要认证,登录home/bbs要使用不同的认证方式local/ldap(使用装饰器),home传参数且有返回值
 3 user,passwd = 'sam','123'
 4 def auth(auth_type):
 5     #print("auth func:",auth_type)
 6     def outer_wrapper(func):
 7         def wrapper(*args,**kwargs):
 8             #print("wrapper func args:", *args, **kwargs)
 9             if auth_type == 'local':
10                 username = input("Username:").strip()
11                 password = input("Password:").strip()
12                 if username == user and password == passwd:
13                     print("登录成功!")
14                     res = func(*args,**kwargs)
15                     #print("---认证之后---")
16                     return res
17                 else:
18                     print("用户名或密码错误.")
19             elif auth_type == 'ldap':
20                 print("使用Ldap认证")
21         return wrapper
22     return outer_wrapper
23 
24 def index():
25     print("Welcome to the index page.")
26 
27 @auth(auth_type='local')    #home=auth
28 def home(*args):
29     print("Welcome to the home page.",args)
30     return "From home page"
31 
32 @auth(auth_type='ldap')
33 def bbs():
34     print("Welcome to the bbs page.")
35 
36 home()
37 bbs()
网站认证装饰器-终极版

 

3.Json & pickle 数据序列化

 xml逐渐被json取代

 Json不支持函数序列化,只能处理简单的数据类型

#序列化
import json

def sayhi(name):
    print("hello,",name)

info = {
    'name':'alex',
    'age':22,
    #'func':sayhi    #不能序列化函数
}

f = open("test.text","w")
f.write( json.dumps( info) )

info['age'] = 21
f.write( json.dumps( info) )

f.close()

#反序列化
import json

f = open("test.text","r")

#data = json.loads(f.read()) #data = pickle.loads(f.read())

for line in f:
    print(json.loads(line))
Json

 Json是不同开发语言都支持的交互方式,pickle是python自有的

 pickle可以序列化所有数据类型,但函数不能序列

 1 #序列化
 2 import pickle
 3 
 4 def sayhi(name):
 5     print("hello,",name)
 6 
 7 info = {
 8     'name':'alex',
 9     'age':22,
10     'func':sayhi
11 }
12 
13 
14 f = open("test.text","wb")
15 
16 pickle.dump(info,f) #和f.write( pickle.dumps( info) )功能一样
17 
18 f.close()
19 
20 #反序列化
21 def sayhi(name):
22     print("hello2,",name)
23 
24 f = open("test.text","rb")
25 
26 data = pickle.load(f) #和data = pickle.loads(f.read())功能一样
27 
28 print(data["func"]("Alex"))
View Code

 注:dump一次load一次,不要dump多次

4.软件目录结构规范

 假设项目名为Foo

Foo/
|-- bin/
|   |-- foo
|
|-- foo/
|   |-- tests/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py
|   |-- main.py
|
|-- docs/
|   |-- conf.py
|   |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README

简要解释一下:

  1. bin/: 存放项目的一些可执行文件,当然你可以起名script/之类的也行。
  2. foo/: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/存放单元测试代码; (3) 程序的入口最好命名为main.py
  3. docs/: 存放一些文档。
  4. setup.py: 安装、部署、打包的脚本。
  5. requirements.txt: 存放软件依赖的外部Python包列表。
  6. README: 项目说明文件。
posted @ 2018-05-03 17:24  Pynetwork  阅读(189)  评论(0编辑  收藏  举报