Python中的装饰器,迭代器,生成器

1. 装饰器

  • 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
  • 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
  • 装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
  • 开放封闭原则:对修改封闭,对扩展开放
import time

def timmer(fun):
    start_time=time.time()
    fun()
    end_time=time.time()


def fun1():
    print("in func1")

timmer(fun1)   #改变了原先函数的执行
  • 就要用闭包来包装此函数

import time

def timmer(fun):
    def inner():
        start_time=time.time()
        fun()
        end_time=time.time()
        print("run in {} time {}".format(fun,end_time-start_time))
    return inner   #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用


def fun1():
    print("in func1")

print(timmer(fun1))    #可以运行,其实就是执行Inner,目的就是在全局可以调用,
fun1=timmer(fun1)     #函数本身就是变量,变量值互换
fun1()                  
  • 这样最基本的装饰器就完成了,Python为我们提供了语法糖,一个完整的装饰器如下:会允许函数传参并且返回值不变

import time

def timmer(fun):
    def inner(*args,**kwargs):
        start_time=time.time()
        ret = fun(*args,**kwargs)
        end_time=time.time()
        print("run in {} time {}".format(fun,end_time-start_time))
        return  ret
    return inner   #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用

@timmer
def fun1(num):
    print("in func1 {}".format(num))
    return 123

# print(timmer(fun1))    #可以运行,其实就是执行Inner,目的就是在全局可以调用,
# fun1=timmer(fun1)      #函数本身就是变量,变量值互换
print(fun1(1))
  • 这样可以修饰多个函数,但是要批量更改该怎么,如果不想装饰了,需要挨个去掉吗

import time

def outer():
    Flag=False
    def timmer(fun):
        def inner(*args,**kwargs):
            if Flag:
                start_time=time.time()
                ret = fun(*args,**kwargs)
                end_time=time.time()
                print("run in {} time {}".format(fun,end_time-start_time))
                return ret
            else:
                ret = fun(*args, **kwargs)
                return ret
        return inner   #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用
    return timmer   

@outer()           #之所以加执行就是把outer的返回值timmer函数的内存地址放在这里,其实就是@timmer
def fun1(num):
    print("in func1 {}".format(num))
    return 1

@outer()
def fun2(num):
    print("in func2 {}".format(num))
    return 2

@outer()
def fun3(num):
    print("in func3 {}".format(num))
    return 3

print(fun1(1))
print(fun2(2))
print(fun3(3))
  • 编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码

  • 使用小知识点eval

login_status={"user":None,"status":False}

def outer():
    Flag=True
    def auth(func):
        def inner(*args,**kwargs):
            if Flag:
                with open("user.txt",encoding="utf-8") as read_f:
                    if login_status['user'] and login_status['status']:
                        ret = func(*args, **kwargs)
                        return ret
                    user_info=eval(read_f.read())
                    name=input("your name>>:").strip()
                    password=input("your password>>:").strip()
                    if name in user_info and user_info[name]["password"] == password:
                        login_status["user"]=name
                        login_status["status"]=True
                        print(login_status)
                        ret = func(*args,**kwargs)
                        return  ret
                    else:
                        print("bad")
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return auth


@outer()
def fun1():
    print("in func1")
    return 1

@outer()
def fun2():
    print("in func2")
    return 2

@outer()
def fun3():
    print("in func3")
    return 3

fun1()
fun2()
fun3()
  • 多个装饰器装饰同一个函数

def wrapper1(func):
    def inner():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()

  结果原因如下:从后分析

 装饰器小练习:

#编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
import time
from urllib.request import urlopen

def wrapper(func):
    def inner(*args,**kwargs):
        start_time=time.time()
        ret = func(*args,**kwargs).decode('utf-8')
        end_time=time.time()
        print("{} time is {}".format(*args,end_time-start_time))
        return ret
    return inner

@wrapper
def get(url):
    return urlopen(url).read()

# print(get('http://www.baidu.com'))
get('http://www.baidu.com')

2. 迭代器

  •  其实迭代就是我们说的,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代

  • 可迭代协议的定义非常简单,就是内部有了__iter__方法。
from collections import Iterable

l = [1, 2, 3, 4]
t = (1, 2, 3, 4)
d = {1: 2, 3: 4}
s = {1, 2, 3, 4}

print(isinstance(l, Iterable))
print(isinstance(t, Iterable))
print(isinstance(d, Iterable))
print(isinstance(s, Iterable))
print(dir([1,2]))
  • 用__next__也可以遍历,不依赖for循环

l=[1,2,3,4]
l_iter=l.__iter__()          #先把可迭代对象变成迭代器
print(l_iter.__next__())     #依次取值
print(l_iter.__next__())     #依次取值
print(l_iter.__next__())     #依次取值
print(l_iter.__next__())     #依次取值
  • while..try..

l=[1,2,3,4]
l_iter=l.__iter__()          #先把可迭代对象变成迭代器
# print(l_iter.__next__())     #依次取值
# print(l_iter.__next__())     #依次取值
# print(l_iter.__next__())     #依次取值
# print(l_iter.__next__())     #依次取值


while True:
    try:
        item = l_iter.__next__()
        print(item)
    except StopIteration:
        break

3. 生成器

  • 一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值

  • 但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。

  • 每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

  • 生成器有什么好处呢?就是不会一下子在内存中生成太多数据

def genrator_fun1():
    a=1
    yield a
    b=2
    yield b

g=genrator_fun1()
print(next(g))
print(next(g))
#生成器监听文件输入的例子

  

  

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

  

posted @ 2018-04-23 10:16  阿进,fighting  阅读(184)  评论(0编辑  收藏  举报