装饰器

  1、什么是装饰器?

    不修改函数的调用方式,还能再原来函数的基础上增加功能。

  2、装饰器原则:开放封闭原则

    开放:对扩展时开放的

    封闭:对修改是封闭的

  3、装饰器的通用写法:

def wrapper(func):  # 装饰器
    def inner(*args, **kwargs):  # 利用*args和**kwargs接受任意参数:位置参数和关键字参数
        ret = func(*args, **kwargs)  # 接收函数的返回值
        return ret
    return inner
@wrapper  # 装饰器的重点:语法糖:这里实际上是wahaha = wrapper(wahaha),不过这样写应该写到定义的函数后
def wahaha(a,b):   # 原函数
    sum = a + b
    return sum
ret = wahaha(3, 4)  # 函数调用且接受返回值
print(ret)

  ps:小知识补充一:time模块

import time  # 导入time模块
def wrapper(func):
    def inner(*args, **kwargs):
        start = time.time()  # time()可以查看当前时间(从1970到现在)
        ret = func(*args, **kwargs)
        end = time.time()
        print(end - start)  # 可以查看代码执行时间
        return ret
    return inner
@wrapper
def wahaha(a,b):
    sum = a + b
    time.sleep(0.1)  # 让代码停止0.1秒
    return sum
# wahaha = wrapper(wahaha)
ret = wahaha(3, 4)
print(ret)
View Code

  4、装饰器进阶

    完美装饰器

import time
from functools import wraps
def wrapper(func):
    @wraps(func)  # 完美装饰函数
    def inner(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        end = time.time()
        print(end - start)
        return ret
    return inner
@wrapper
def wahaha(a,b):
    sum = a + b
    time.sleep(0.1)
    return sum
print(wahaha.__name__)  # 查看函数名

  5、带参数的装饰器

import time
from functools import wraps
flag = 1  # 通过设置标志位可与以使用户更方便的决定用或不用装饰器
def Flag(flag):  # 在原本装饰器的外层再套一层装饰器,进行一次参数的传递
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            if flag:
                start = time.time()
                ret = func(*args, **kwargs)
                end = time.time()
                print(end - start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return wrapper
@Flag(flag)
def wahaha(a,b):
    sum = a + b
    time.sleep(0.1)
    return sum
ret = wahaha(1,2)
print(ret)
View Code

  6、多个装饰器装饰同一个函数

def wrapper1(func):  # 1
    def inner1(*args, **kwargs):  # 4
        print('before func inner1')  # 14
        ret1 = func(*args, **kwargs)  # 15 wahaha()  # 18 ret1 = 123
        print('after func inner1')  # 19
        return ret1  # 20
    return inner1  # 5
def wrapper2(func):  # 2
    def inner2(*args, **kwargs):  # 8
        print('before func inner2')  # 12
        ret2 = func(*args, **kwargs)  # 13 inner1()  # 21 ret2 = ret1 = 123
        print('after func inner2')  # 22
        return ret2  #23
    return inner2  # 9
@wrapper2  # 7 wrapper2(inner1)  # 10 wahaha = inner2
@wrapper1  # 3 wrapper1(wahaha)  # 6 wahaha = inner1
def wahaha():
    print('wahaha is good')  # 16
    return 123  # 17
ret = wahaha()  # 11 inner2()  #24 ret = ret2 = 123
print(ret)  # 25
View Code

迭代器

  1、双下方法:__iter__()加了双下划线的方法

  2、可迭代协议:只要含有__iter__方法的都是可迭代的   判断方法:'__iter__'in dir(方法名)

    可以被for循环的都是可迭代的

  3、迭代器协议:内部含有__iter__和__next__的方法就是迭代器    判断方法: '__iter__' in dir() and '__next__'in dir()

    可迭代的.__iter__()就得到一个迭代器

    迭代器中的__next__()方法可以一个一个的获取值

    for循环其实就是在使用迭代器

  4、迭代器的优点:

    (1)使用方便,一个迭代器只能从头到尾取值,且只能取一次

    (2)节省内存空间(可迭代对象是一个个给你而不是一次性读取,不会占用大块内存,每次只给一个)

l = [1, 2, 3, 4, 5]
g = l.__iter__()
print(g.__next__())  # 每次返回列表中的一个值
print(g.__next__())  # 每次返回列表中的一个值
print(g.__next__())  # 每次返回列表中的一个值
print(g.__next__())  # 每次返回列表中的一个值

生成器

  1、本质上是一种迭代器,生成器与迭代器都是惰性运算

  2、生成器函数:本质上就是我们自己写的函数,只要含有yield的函数都是生成器函数,且yield不能与return共用,且只能在函数内使用

    生成器函数执行一次后获得一个生成器,此时函数并没有执行

  3、生成器:

   yield在返回值时和return有着相同的作用

def generater():
    print(1)
    yield 'a'
    print(2)
    yield 'b'
g = generater()  # 此时只是获得一个生成器
ret = g.__next__()  # g.__next__()这时函数才真正执行,执行到第一个yield处
print(ret)
ret = g.__next__()  # g.__next__()函数接着上次停止的地方执行,执行到下一个yield处
print(ret)

  因为生成器的本质是迭代器,所以一个生成器只能从头到尾取一次值,当取完值时在执行生成器.__next__()会报错

  4、从生成器中取值的几个方法:

    next、for循环、数据类型的强制转换(比较占用内存)

  5、生成器函数进阶一:send函数

def generator():
    content = yield 1
    print('===',content)
    content = yield 2
    print('***',content)
    content = yield 3

g = generator()
ret = g.__next__()  # 在第一次使用生成器时,需用next获取到一个值
print(ret)
ret = g.send(10)  # send函数与next函数都有获取下一个值的效果,但send函数可以在上一个yield的地方传一个参数
print(ret)
ret = g.send(20)
print(ret)
ret = g.send(30)  # 最后一个yield不能接收外部的值
print(ret)
View Code

  6、生成器函数进阶二:获取移动平均值

def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg  # 生成器激活到这里就停止
        sum += num
        count += 1
        avg = sum/count
a = average()
a.__next__()  # 激活生成器
a1 = a.send(10)  # 在停止位置给num传一个值
a2 = a.send(20)
print('%s,%s'%(a1,a2))
View Code

  ps:小技巧

def generator():
    a = 'asdfg'
    b = '12345'
    yield from a  # 可迭代类型数据都可以
    yield from b
g = generator()
for i in g:
    print(i)
View Code

   7、生成器表达式

    1)列表推导式    

list=['%s'%i for i in [1,2,3,4,5] if i>3]
print(list)

    2)生成器表达式

g = (i for i in range(10))
for i in g:
    print(i)

    生成器表达式与列表推导式的括号不同,返回的值不同。生成器表达式返回的是一个生成器,几乎不占用内存。

    当碰到列表推导式相关面试题时,可以展开进行一步步的推导。

    3)字典推导式

# 将字典的键值互换
dic = {1:'a',2:'b'}
dic1 = {dic[i]:i for i in dic}
print(dic1)

    4)集合推导式

set1 = {i**i for i in [1,-1,2]}
print(set1)  # 集合自带去重功能

 

posted on 2018-10-27 21:31  幸福的小耗子  阅读(183)  评论(0编辑  收藏  举报