[Python3]装饰器_生成器_迭代器_内置函数_软件目录

装饰器,生成器,迭代器,内置函数,软件目录

装饰器(也叫语法糖)

  • 定义:装饰器本质是函数,用于装饰其他函数,为其他函数添加附加功能。
  • 原则:1.不能修改被装饰函数的源代码;2.不能修改被修改函数的调用方式
  • 知识储备:1.函数即变量;2.高阶函数;3.嵌套函数;4.高阶函数+嵌套函数+闭包=装饰器
  • 自己写一个装饰器:

无参数装饰器

import time
def timer(func):#装饰器函数
    def deco(*args,**kwargs):#传入可变长参数,适应不同函数
        start_time = time.time()
        res = func(*args,**kwargs)#将参数传给原有函数
        stop_time = time.time()
        print("the func run time is %s" %(stop_time - start_time))
        return res#将原有函数的结果进行返回
    return deco
def test_1(name):#原有函数
    time.sleep(1)
    print("%s in the test_1" %(name))
test_1 = timer(test_1)
test_1("zzh") #实际上在执行deco(),但表面上未改变test1的调用方式
###################################
#将写法改为@写法,则变成装饰器
@timer #其中,@timer就等效于test_1 = timer(test_1) = deco的写法
test_1("zzh")
### 结果:zzh in the test_1
### the func run time is 1.0000958442687988

有参数装饰器

import time
def timer(timeout=0):
    def decorator(func):
        def wrapper(*args,**kwargs):
            start=time.time()
            func(*args,**kwargs)
            stop=time.time()
            print 'run time is %s ' %(stop-start)
            print timeout
        return wrapper
    return decorator
@timer(2)#test = timer(2)传入参数并返回decorate
def test(list_test):
    for i in list_test:
        time.sleep(0.1)
        print '-'*20,i
 
#timer(timeout=10)(test)(range(10))
test(range(10))

生成器(generator)

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

生成器定义:

  • 方法一:只要把一个列表生成式的[]改成(),就创建了一个generator:
g = (x*x for x in range(10))#<generator object <genexpr> at 0x1022ef630>
  • 方法二:
def fib(max):#定义生成器
    n,a,b = 0,0,1
    while n<max:
        yield b #只要把原有输出改成yield就成生成器了
        a,b = b ,a+b
        n = n+1
    return  'done'
g=fib(10)#g即是一个定义好的生成器

生成器迭代:

  • 生成器只有在调用时才会生成,相应的,若需要取下一个,只能一个一个按顺序进行迭代才可获取。
  • 生成器可使用for num in g:或者g.__next__()或者next(g)的函数进行迭代生成
  • 生成器向后迭代:g.__next__()#生成器只能使用next方法不断向后迭代,且不可前溯。当生成器中无法再取出数据时,会向外抛出一个异常。通过抓住异常,即可判断结束。
  • 进行异常处理代码:
while True:  #死循环
    try: #尝试下列代码
        x = next(g) #获取迭代器的下一个值
        print('g:',x) #打印该值
    except StopIteration as e: #如果出现Stoplteration的异常时
        print('Generator return value:',e.value) #打印异常和返回值
        break
  • 生成器send方法:
def consumer(name):#定义一个装饰器
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield #当遇到yield,暂停并跳出
       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
zzh = consumer("zzh")
zzh.__next__()
zzh.send("韭菜馅")##send调用yield,并给他传值

zzh 准备吃包子啦!
包子[韭菜馅]来了,被[zzh]吃了!

迭代器

  • 可以直接作用于for循环的数据类型有以下几种:1.集合数据类型,如list、tuple、dict、set、str等;2.generator,包括生成器和带yield的generator function。这些可以直接作用于for循环的对象统称为__可迭代对象:Iterable__。
  • 可以使用isinstance()判断一个对象是否是Iterable对象。
from collections import Iterable#导入的是Iterable
isinstance([], Iterable) ##注意这里是 Iterable,判断是不是可迭代对象
###True
  • 可以被next()函数调用并不断返回下一个值的对象称为__迭代器:Iterator__。
  • 可以使用isinstance()判断一个对象是否是Iterator对象:
from collections import Iterator#导入的是Iterator
isinstance((x for x in range(10)), Iterator) ##注意这里是 Iterator,判断是不是迭代器对象
###True
  • 生成器对象都是可迭代对象,但如list、dict、str等是可迭代对象却不是生成器对象
  • 可以使用iter()函数把list、dict、str等Iterable变成Iterator。如:isinstance(iter('abc'), Iterator)#True

内置方法

内置参数详解 :
https://docs.python.org/3/library/functions.html?

  • abs(x)x.__abs__():#取绝对值
  • all(iterable):如果列表中所有元素均为真,返回真;只要有一个为假,返回假
  • any(iterable):如果列表中有任何一个元素为真,返回真;全为假,则返回假,空列表也为假
  • ascii(iterable):将元素转换为对应的ASCII码
  • bin(x):将填入的十进制数转为二进制
  • bool(x):判断填入的bool值是否为真
  • bytes("abcde",encoding = 'utf-8'):将字符串用utf-8编码,转为byte类型,且不可修改
  • b=bytearray("abcde",encoding = 'utf-8'):将字符串用utf-8编码,转为byte类型,但是可以修改其元素,如b[1]=100修改第二个元素的字符
  • callable(iterable):判断一个元素是否是可调用的
  • cha(98):查询对应ASCII的字符‘b’
  • ord('b'):查询字符对应的ASCII码 #98
  • dict(**kwarg):生成一个字典
  • dir([object]):查询对象具有哪些可用的方法
  • divmod(5,2):整数除法取余,返回商和余数,#(2,1)
  • list(enumerate(['one','two','three'])):返回一个可迭代对象(如序列)的下标和元素的元组#[(0, 'one'), (1, 'two'), (2, 'three')]
  • eval('1+2'):把一个字符串变成一个字典,返回值是求表达式的结果#3
  • exec("print('hello')"):将字符串变成代码进行编译运行 #hello
  • filter(lambda n : n>5 , range(10)):#能够从一组数据中过滤出一些想要的数据来
  • map(lambda n : n*n , range(10)):对输入的值按照用户要求进行处理,再覆盖掉原来的值。等效于[i*i for i in range(10)]
  • print("I am {name}".format(name = "zzh")):格式化输出
  • frozenset([1,2,3,4]):将集合(如列表)变成一个不可变集合
  • print(globals()):返回当前程序中的所有变量,以字典形式返回,变量名和值
  • hash(object):计算一个对象的哈希值
  • hex(12):将数据转化为十六进制#0xc
  • input("name:"):标准输入,括弧中为提示信息
  • len(s):获取对象的长度
  • print(locals()):打印函数内部的局部变量
  • max([1,2,3,4,5]):返回列表中的最大值
  • min([1,2,3,4,5]):返回列表中的最小值
  • next():生成器的调用方法
  • oct(12):十进制转八进制#0o14
  • pow(3,3):求幂,3的3次幂=27
  • print("I am zzh"):将对象打印到文本流文件中
  • range(1,10,2):输出一个序列(开始,停止,步长)
  • reversed(seq):反转一个可迭代对象,如反转一个数组
  • round(1.3342 , 2):保留两位小数 #1.33
  • slice(2,5,1):切片,从2切到5,步长为1
  • sorted(iterable):对iterate中的项目进行排序并返回一个新的列表
  • sum():从左到右开始,计算数据的总和
  • type():查看对象的数据类型
  • print(zip([1,2,3],['a','b','c'])):对于元素进行拼接
  • __import__("模块名"):导入模块,模块名为字符串,等效于import 模块名

软件目录规划

假设你的项目名为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: 项目说明文件。
  • 如果我是一个包下的foo.py,如何通过代码去调用另一个路径下的main.py,例子如下:
import os,sys
print(__file__)#获得当前文件的相对路径
print(os.path.abspath(__file__))#通过相对路径获得绝对路径
print(os.path.dirname(os.path.abspath(__file__)))#以当前绝对路径向上退一级
#再向上一级获得整个文件即Foo的绝对路径,并进行存储
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)#将文件目录加入到环境变量中
import foo#再引用foo包,则不会出现报错

参考:
https://blog.51cto.com/egon09/1836763
https://www.cnblogs.com/alex3714/articles/5765046.html