day20:有参装饰器、迭代器

要求不同的函数要用不通的认证方式,就需要用有参装饰器。有参装饰器也就是在无参装饰器外面再包一层函数,带上参数。

def deco(auth_type='file'):
    def auth(func):
        def wrapper(*args,**kwargs):
            if auth_type == 'file':
                print('文件的认证方式')
            elif auth_type == 'ldap':
                print('ldap认证方式')
            elif auth_type == 'mysql':
                print('mysql认证方式')
            else:
                print('不知到的认证方式')
        return wrapper
    return auth

@deco(auth_type='abc') #@auth #index=auth(index)
def index():
    print('welecome to index')

@deco(auth_type='ldap')
def home(name):
    print('welecome %s to home page' %name)

index()

home('egon')

迭代器

迭代:
  1 重复
  2 下一次重复是基于上一次的结果

python为了提供一种不依赖索引的迭代方式python会为一些对象内置__iter__方法obj.__iter__称为可迭代的对象z
迭代器的优点:
     1.提供了一种不依赖索引的取值方式
     2.惰性计算,节省内存
迭代器的缺点:
     1.取值不如按照索引的取值方便
     2.一次性的,只能往后走不能往前退
   3.无法获取长度
迭代器的应用:
     1.提供了一种不依赖索引的统一迭代方法
     2.惰性计算,比如取文件的每一行

可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;
一类是generator,包括生成器和带yield的generator function
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable
可以使用isinstance()判断一个对象是否是Iterable对象:
复制代码
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
复制代码

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

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

可以使用isinstance()判断一个对象是否是Iterator对象:

复制代码
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
复制代码

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成Iterator可以使用iter()函数:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

迭代器的优点
1:提供了一种不依赖于索引的取值方式
2:惰性计算。节省内存

迭代器的缺点:
1:取值不如按照索引取值方便
2:一次性的。只能往后走不能往前退
3:无法获取长度

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

复制代码
# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break
课后作业

一、编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到文件中

 注意:时间格式的获取

import time
log_file = r'C:\Users\zzn\PycharmProjects\python3\day1\b.txt'
def time_add(func):
    def wrapper(*args,**kwargs):
        with open(log_file,'a',encoding='utf-8') as f:
            func()
            res = '%s %s run\n' %(time.strftime('%Y-%m-%d %X'),func.__name__ )
            f.write(res)
    return wrapper
@time_add
def f1():
    print('运行f1程序')

f1()

二、 选做题:

基于课上所讲网页缓存装饰器的基础上,实现缓存不同网页的功能
要求,用户提交的不同url,都能缓存下来,对相同的url发起下载请求,
优先从缓存里取内容

from urllib.request import urlopen
import os
cache_path = r'C:\Users\zzn\PycharmProjects\python3\day1\cache_day8'
def add_dic(func):
    def wrapper(*args,**kwargs):
        ret = func(*args, **kwargs)
        t = str(args).strip('()')
        t = t.split('/')
        cache_1 = os.path.join(cache_path,t[2])
        if os.path.isfile(cache_1):
            if os.path.getsize(cache_1):
                with open(cache_1, 'rb') as f:
                    print('读缓存')
                    ret = f.read()
        else:
            with open(cache_1,'wb') as f:
                print('创建')
                f.write(ret)
        return ret
    return wrapper

@add_dic
def get(url):
    return (urlopen(url).read())
print(get('http://www.renren.com/'))
print(get('http://www.baidu.com/'))

 

posted @ 2017-06-16 16:54  小小学徒、  阅读(138)  评论(0编辑  收藏  举报