生成器 迭代器,装饰器 ,软件开发规范

一、生成器

1、列表生成式

有列表data=[1,2,3,4],要求将列表data里面的数据均加1:

     除了循环,可以用列表生成式一行写出替代多行的循环

1 data=[1,2,3,4]
2 data=[i+1 for i in data]
3 print(data)

生成式中也可以写三元运算

#需求:列表中小于3的都*2,大于等于3的+1
data=[i*2 if i<3 else i+1 for i in data]

   列表生成式,是python内置的一种直接生成list的表达式,可以直接生成一个列表,但是受内存限制,容量有限,如果生成的数据量很大,但是使用到的寥寥无几,那么其他数据占用的控件就会浪费,那么有没有节省控件的方法呢?。。。。。。。生成器 generator

  2.生成器generator

生成器生成的方式有两种,一种是将列表生成式的‘[]’改为‘()’,一种是听过在函数中加入yield关键字

生成器和列表生成式的区别:列表生成式在生成的时候就已经计算出了参数的一个列表,而生成器被调用的时候,才会去生成参数

(1)通过()生成生成器

1 data=[1,2,3]
2 gen1=[i+1 for i in data]# gen1为一个列表生成式
3 gen2=(i+1 for i in data)#gen2为一个生成器
4 print(gen1)# 打印列表生成式  会输出一个列表:[2, 3, 4]
5 print(gen2)# 直接打印生成器  可以看到这时候只是生成了一个对象 ,还未进行运算:<generator object <genexpr> at 0x0000000001157048>

既然不能直接打印生成器,那么如何取得生成器生成的参数呢?

两种方法:1、gen._next_()/next(gen)       2、for 循环

1 print(gen2.__next__())#输出2
2 print(next(gen2))#输出3
3
4 for i in gen2:
5     print(i)#输出 4,如果没有上面两次调用,则for循环调用生成器得的结果就是:2,3,4

    (2)函数中加入yield关键字

例子:斐波那契数列  除了第一个数和第二个数外,其他数都是前两个数的和  1,1,2,3,5,8,13,21,34..........,要求打印该数列的前8个数

1 def fbq(max):
2     n,a,b=0,0,1
3     while n<max:
4         print(b)
5         a,b=b,a+b
6         n=n+1
7 fbq(8)

       现在将上面的函数变为一个生成器:

def fbq(max):
    n,a,b=0,0,1
    while n<max:
        yield b
        a,b=b,a+b
        n=n+1
f=fbq(8)
print(f)
print(f.__next__())
for i in f:
    print(i)

        程序执行到yiled的时候,就会暂停,再次调用生成器函数的时候便会在上次暂停的位置,继续往下执行。即yield保存了程序的中间状态

     在单线程下,生成器还可以模拟并行运算:

def conumer(name):
    print(‘%s准备吃包子‘%name)
    while True:
        baozi=yield    #注意:此处yield无参数
        print(‘包子%s做好了,%s开始吃包子‘%(baozi,name))
def producer(name):
    c=conumer(‘A‘)
    c2=conumer(‘B‘)
    c.__next__()
    c2.__next__()
    print(‘_____________________‘)
    for i in range(3):
        c.send(i)          #给yield传参数
        c2.send(i)
producer(‘songxiaonna‘)
A准备吃包子
B准备吃包子
_____________________
包子0做好了,A开始吃包子
包子0做好了,B开始吃包子
包子1做好了,A开始吃包子
包子1做好了,B开始吃包子
包子2做好了,A开始吃包子
包子2做好了,B开始吃包子

二、迭代器

  可直接进行for循环的数据类型:  列表  元组  集合  字符串,还有生成器,统称为可迭代对象。

  判断对象时候可以迭代:isinstance

from collections import Iterable #导入模块
print(isinstance([],Iterable))   # 返回true

  生成器不仅可以通过for循环,还可以用next调用,可以被next函数调用,并不断返回下一个值的对象,统称为迭代器 iteratior

  定义一个迭代器:iter

data=[1,2,3]
data=iter(data)
print(data) # data:<list_iterator object at 0x0000000000565CC0>
print(next(data))#  1

  迭代器的对象,表示的是一个数据流,我们不知道数据流的长度,迭代器的计算是惰性运算,按需运算,但是列表等可迭代对象是长度,提前就已经知道列表中的数据,所以列表、 元组、  集合、 字符串不是迭代器

三、装饰器

  装饰器的本事就是函数,其功能是为其他函数添加附加功能,实现之前函数没有的功能

假如,当前有10个函数,需要再这10个函数每个函数增加一个记录日志的功能,可以另外定义一个函数logger(),然后每个函数去调用这个函数.......

以上的方法可以解决问题,但是如果是线上程序,那么修改程序源代码会带来很大的风险。所以为程序的新添加一个功能,需要遵循两个原则:

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

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

装饰器对于被装饰函数是完全透明的

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

  (1)函数即‘变量’

def foo():
    print(‘in the foo ‘)
    bar()
foo()
def bar():
    print(‘in the bar‘)

#输出会报错:应为执行foo()的时候,bar函数还没有定义,正确的代用可以更改为:

def foo():
    print(‘in the foo ‘)
    bar()
def bar():
    print(‘in the bar‘)
foo()

或者将bar函数写在 foo前面

  定义bar函数就相当于将bar函数体复制子给bar变量名。  只要在调用之前,函数已经存在,就可已被调用

   (2)高阶函数

满足下面两个条件之一就是高阶函数

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

def bar():
    print(‘in the bar‘)
def test1(func):
    func()
test1(bar) 

    2、返回值中包含函数名

def test2(func):
    return func()
test2(bar)

  (3)嵌套函数

      在一个函数的函数体内,用def再声明一个函数

def foo():
    def bar():  #该函数只在foo函数中生效   局部变量
        print(‘in the bar‘)
    bar()
foo()
 1 x=0
 2 def foo():
 3     x=1
 4     def fo():
 5         x=2
 6         def f():
 7             x=3
 8             print(x)
 9         f()
10     fo()
11 foo()
12 #输出结果为3     作用于只能从里往外找

    1、不带参数的装饰器:

   原有test1和test2两个函数,现在需要需要新增一个计算每个函数运行时间的功能(已经写好新增功能的函数为timmer)

 1 import time
 2 def timmer(func):#高阶函数
 3     start_time=time.time()
 4     func()
 5     end_time=time.time()
 6     print(‘函数%s运行的时间为:%s‘%(func,(end_time-start_time)))
 7
 8 def test1():
 9     time.sleep(1)
10     print(‘in the test1‘)
11 def test2():
12     time.sleep(2)
13     print(‘in the test2‘)
14
15 timmer(test2)#计算test2函数的运行时间,将函数test2当做实参传入到timmer中    

   新增了timmer功能,但是改变了之前函数test2的调用方法......

不想改变函数的调用方式,可以将test2函数替换,test2=timmer(test2),前提是timmer函数中要返回test2的内存对象,要将func()改为 return func,如下:

import time
def timmer(func):
    start_time=time.time()
    return func    #之前这块的代码: func ()
    end_time=time.time()
    print(‘函数%s运行的时间为:%s‘%(func,(end_time-start_time)))

def test1():
    time.sleep(1)
    print(‘in the test1‘)
def test2():
    time.sleep(2)
    print(‘in the test2‘)
test2 = timmer(test2)#注意:将timmer(test2)赋值给test2的时候就已经在调用timmer函数了
test2()

   还是不可行,因为调用到return()的时候,函数就不会往下执行了,那么有没有完美的解决方案呢?.....................嵌套函数,即在新功能函数外面再套一层函数

 1 import time
 2 #在之前新加功能函数的外面套一层函数
 3  def timmer2(func):
 4       def timmer():
 5           start_time=time.time()
 6           func()         #不需要再用return
 7           end_time=time.time()
 8           print(‘函数%s运行的时间为:%s‘%(func,(end_time-start_time)))
 9       return timmer   #返回timmer函数的内存地址
10
11  def test1():
12      time.sleep(1)
13     print(‘in the test1‘)
14  def test2():
15      time.sleep(2)
16      print(‘in the test2‘)
17  test2 =timmer2(test2)
18 test2()

   有一种更为直观的书写方法,将 test2 =timmer2(test2) 用@+函数名的方式替换掉,如下:      在需要加新功能的功能函数前面加上  @+新功能函数名

import time
def timmer2(func):
    def timmer():
        start_time=time.time()
        func()
        end_time=time.time()
        print(‘函数%s运行的时间为:%s‘%(func,(end_time-start_time)))
    return timmer
@timmer2          # 相当于test2 =timmer2(test2)
def test1():
    time.sleep(1)
    print(‘in the test1‘)

def test2():
    time.sleep(2)
    print(‘in the test2‘)
test1()

   2、带参数的装饰器:

只需要再timmer函数加上*args和**kwarg即可

import time
def timmer2(func):
    def timmer(*args,**kwargs): #给timmer加上非固定参数
        start_time=time.time()
        func(*args,**kwargs)   #。。。加上非固定参数
        end_time=time.time()
        print(‘函数%s运行的时间为:%s‘%(func,(end_time-start_time)))
    return timmer
@timmer2
def test1():
    time.sleep(1)
    print(‘in the test1‘)
@timmer2def test2(name,age): #test为带参函数 print(name,age) test2(‘宋晓楠‘,18)

   3、小练习:

    需求:现在有一个网站,一个页面为一个函数

        def index():            print(‘___首页____‘)        def home():            print(‘____用户中心____‘)        def bbs()            print(‘____发帖页面____‘)   现在需要在 用户中心页面和发帖页面增加登录功能
 1 def auth(func):
 2     def login():
 3         name=‘songxiaonan‘
 4         pwd=‘123‘
 5         Name=input(‘请输入用户名:‘)
 6         Pwd=input(‘密码:‘)
 7         if Name==name and Pwd==pwd:
 8             func()
 9         else:
10             print(‘用户名或密码错误............‘)
11     return login
12
13
14 def index():
15     print(‘___首页____‘)
16 @auth
17 def home():
18     print(‘____用户中心____‘)
19 def bbs():
20     print(‘____发帖页面____‘)
21
22 home()

四、json&pickle的序列化

  如果有一个字典dict,需要将这个字典写入一个新文件,则必须将字典转为字符串才可以写入  序列化:将一个内存对象转为字符串,即序列化

反序列化:将字符串转回为对应的内存对象,及反序列化
1 data={
2     ‘name‘:‘宋晓楠‘,
3     ‘age‘:22
4 }
5 f=open(‘file‘,‘w‘,encoding=‘utf-8‘)
6 data=str(data)  #写入一个新文件的内容必须为字符串或者二进制,所以将一个内存对象写入硬盘,必须先转为字符串或者二进制
7 f.write(data)

(1)json 模块

    1、序列化 ①json.dumps(data)

#json序列化   json.dumps(data)

import json
data={
    ‘name‘:‘宋晓楠‘,
    ‘age‘:22
}
f=open(‘file‘,‘wb‘,encoding=‘utf-8‘)
data=str(data)
data_json=json.dumps(data)
print(data_json)     #输出:"{‘name‘: ‘\u5b8b\u6653\u6960‘, ‘age‘: 22}"
f.write(data_json) 

          ②json.dump(a,f) 序列化文件之后,直接将序列化的内容写入到文件f中

data={
    ‘name‘:‘宋晓楠‘,
    ‘age‘:22
}
f=open(‘file‘,‘wb‘,encoding=‘utf-8‘)
json.dump(data,f) # ==f.wirte(json.dumps(data))

     2、反序列化 ①json.loads(data_json)

data_loads=json.loads(data_json)
#输出结果  将已经被转为字符串的字典 又转为字典

          ②json.load(f)

f=open(‘file‘,‘rb‘,encoding=‘utf-8‘)
data=json.load(f)  #=data=json.loads(f.read())
print(data)

    注意:json支持所有语言,但是json只支持简单的数据类型的序列化,不支持复杂的数据类型,比如:函数

  (2)pickle

    pickle只支持python语言,但是可以支持复数据类型之间的转换

pickle的用法和json的用法完全一样

  如何dumps或者load是多次?  no!写程序时dumps一次  loads一次,要么就dump多个文件就ok了

五、模块

(1)导入自己写的模块

不在同一个脚本中,想共享同一个代码,可以将功能代码转为模块

   ①import auth    注意:不需要加.py   ②调用auth里面的login方法: auth.login   ③导入auth模块中的login,hehe方法: from auth import login,hehe        ④导入自己写的模块的时候,如果模块和当前文件不在同一个目录下,则:from  模块所在目录 import login  (2)模块路径
#查看python搜索模块的路径集    sys.path
import sys
print(sys.path)#输出一个列表
#输出:

for i in sys.path:
    print(i)
#输出:
#C:/Users/songxiaonan/PycharmProjects/day05_learn
#C:\Users\songxiaonan\PycharmProjects\day05_learn
#C:\Users\songxiaonan\PycharmProjects
#E:\python\python35.zip
#E:\python\DLLs
#E:\python\lib
#E:\python
#E:\python\lib\site-packages
1 import sys,os
2 print(__file__)#答应当前文件的相对路径
3 print(os.path.dirname(__file__))#去掉路径中的文件名
4 print(os.path.dirname(os.path.dirname(__file__)))#再去掉一层
5 print(os.path.abspath(os.path.dirname(os.path.dirname(__file__))))#相对路径变为绝对路径

      进度条:

import sys,time
for i in range(10):
    sys.stdout.write(‘*‘)
    sys.stdout.flush()
    time.sleep(0.3)

 六、软件开发目录结构规范    

Foo/
|-- bin/
|   |-- foo     #启动脚本
|
|-- foo/        软件代码目录
|   |-- tests/      测试脚本目录
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py
|   |-- main.py      程序主入口
|
|-- docs/    文档
|   |-- conf.py
|   |-- abc.rst
|
|-- setup.py    安装脚本
|-- requirements.txt    程序依赖的第三方包
|-- README
readme:  1、软件基本功能  2、运行代码的方法:安装环境,启动命令等  3、使用说明  4、代码目录结构说明,也可以说明软件的基本原理  5、常见问题说明
时间: 2024-10-24 14:43:59

生成器 迭代器,装饰器 ,软件开发规范的相关文章

Python-Day4 Python基础进阶之生成器/迭代器/装饰器/Json &amp; pickle 数据序列化

一.生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了.所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间.在Python中,这种一边循环一边计算的机制,称为生成器:generator. 要创建一个generator,有很多种

Python_Day5_迭代器、装饰器、软件开发规范

本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 1.列表生成式,迭代器&生成器 列表生成 >>> a = [i+1 for i in range(10)] >>> a [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访

生成器,装饰器之类

前期知识点回顾 内容回顾1.可迭代对象.迭代器.生成器.装饰器有什么区别? 可迭代对象:内部实现了__iter__方法,是一个迭代器 迭代器:内部实现了__iter__和__next__方法,可以进行for循环 生成器:函数内部有yield的就是生成器,生成器也有一个__next__方法,它的本质是一个迭代器. 生成器有两大功能:1.生成 2.迭代 装饰器:在函数执行之前或者函数执行之后要扩展的功能,装饰器是用闭包实现的2.面向对象的方法?面向对象有三种方法: 实例方法:def func(sel

递归函数、生成器、装饰器

递归函数.生成器.装饰器 递归:  在函数执行中调用自身 必须有边界条件,递归前进段和递归返回段 python中递归有层次限制 递归函数实现阶乘 def fact(n):      if n <= 1:         return 1     else:         return n * fact(n-1) 调用:fact(3)=3fact(2)=32fact(1)=32*1 fact(3) 6 实现斐波拉契数列 def fib1(n):     if n <= 1:         r

Python 3 软件开发规范

Python 3 软件开发规范 参考链接 http://www.cnblogs.com/linhaifeng/articles/6379069.html#_label14 对每个目录,文件介绍. 1 #=============>bin目录:存放执行脚本 2 3 #start.py 4 5 import sys,os 6 7 8 9 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10 11 sys.pat

Python 软件开发规范

软件开发规范旨在规范以及整理合理的代码进行,让整个程序看起来结构清晰,层次分明,其中没有严格的要求要按那种规范来执行,只要合适清晰即可,这个规范已成为约定熟成的一种规范了 像上边的soft的程序下边 1.bin为执行目录,里边start.py为整个程序的调用执行脚本 2.conf为配置目录,所有配置都存入在这里 3.core为核心代码存在目录,所有的核心逻辑代码都存放在这里 4.db 为数据存放目录 5.lib为调用类目录 6.log 为日志目录,程序发生的日志全存放在这里

模块,包,软件开发规范

模块 import from ... import ... 包 import from ... import ... 绝对导入和相对导入 软件开发规范

谈谈编程器软件开发与设计

*************************************************************************************************************************** 作者:EasyWave                                                   时间:2014.05.24 类别:协议标准-编程器简介                                  声明:

软件开发规范及常用模块一

一.软件开发规范 ATM #总文件夹 bin:用来放程序执行文件:start.py conf:配置文件 log:日志文件 lib:放模块和包 db:数据文件 core:放程序的核心逻辑,里面src.py readme #用来保存详细的每个文件夹的介绍,及作用 以上并未非规定,而是看个人理解不同自行定制.但一定要清晰明了.二.序列化 前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用, 但遇到

包的导入/软件开发规范/异常处理

1.包的导入包是一票文件夹和py绝对导入是从根目录开始from,不能挪动,但是直观(此处的根目录可以通过打印sys.path来查看) 相对路径是使用.和..来表示,可以挪动此时不能再在包内的任何位置使用绝对路径来导入,也绝不能再包里调用里面的py文件 一个' . '表示当前文件夹,两个' . . '表示当前文件夹的上一层文件夹. 2.软件开发规范: 每一个项目都写成这样, bin下面有start.py,作为程序入口,if__name__==双下main,如下定式导入便不会再犯错 import o