第四章:Python的装饰器+迭代器+生成器+三元表达式+列表解析+生成器表达式

大纲:

  Python装饰器:

   闭包函数

  迭代器

  三元表达式

  列表解析

  生成器表达式

Python的装饰器 

讲Python的装饰器之前一定要理解毕包函数,什么叫毕包函数:

毕包函数

 python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).这个定义是相对直白的,好理解的,不像其他定义那样学究味道十足(那些学究味道重的解释,在对一个名词的解释过程中又充满了一堆让人抓狂的其他陌生名词,不适合初学者)。

#闭包函数:

#1. 定义在函数内部的函数

#2. 包含对外部作用域名字的引用,而不是对全局作用域名字的引用

#那么该内部函数就称为闭包函数 

下面举一个简单的例子来说明。

#毕包函数
def deco():
    x=123123123123
    def wrapper():  #wrapper就是毕包函数
        print(x)
    return wrapper
func=deco()
func()

#闭包函数的应用:惰性计算

#闭包函数的应用:惰性计算
# import requests
# def get(url):
#     return requests.get(url).text
import requests
def index(url):
    def get():
        print(requests.get(url).text)
    return get
boke_web=index('http://www.cnblogs.com/sheng-247/articles/7225975.html')
baidu_web=index('https://www.baidu.com/')
boke_web()
baidu_web()

总结:

#大前提:作用域关系,在函数定义时就已经固定

# ,与调用位置无关,在调用函数时,必须必须必须

#回到函数原来定义的位置去找作用域关系

毕包函数的应用

==》无参数装饰器和有参装饰器

#1 开放封闭原则:对扩展是开放的,对修改是封闭

#2 装饰器:装饰它人的工具,

#装饰器本身可以是任意可调用对象,被装饰的对象本身也可以是任意可调用对象

  1、装饰器的遵循的原则:1 不修改被装饰对象的源代码 2 不修改被调用对象的调用方式

  2、装饰器的目的是:在遵循1和2原则的前提,为其他新功能函数添加

#@装饰器名,必须写在被装饰对象的正上方,并且是单独一行

无参数装饰器

1、毕包函数应用装饰器(计算函数运行时间)

#装饰器(无参数装饰器)
import time
def timer(fun):
    def wrapper():
        start_time=time.time()
        fun()
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
    return wrapper

@timer  #func=timer(func)   必须写在被装饰对象的正上方,并且是单独一行
def func():
    time.sleep(0.3)
    print('from func ~~')
@timer  #home=timer(home)
def home():
    time.sleep(0.5)
    print('from home ~~')

func()
home()

2、装饰器的修饰

当被装饰额函数有参数的时候装饰器的用法:

import time
def timer(fun):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=fun(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

@timer  #func=timer(func)
def func():
    time.sleep(0.3)
    print('from func ~~')
    return 123
@timer  #home=timer(home)
def home(name):
    time.sleep(0.5)
    print('from home %s ~~'%name)

func()
home('lele')
View Code

3、 实现认证功能装饰器(用户登录装饰器)

#用户登录装饰(简洁版本)
crrent_user={'user_name':None}
def auto(fun):
    def wrapper(*args,**kwargs):
        if crrent_user['user_name']:
            fun()
        else:
            user_name=input('user_name>>').strip()
            passwd=input('passwd>>').strip()
            if user_name == 'sheng' and passwd == '123':
                crrent_user['user_name']=user_name
                fun(*args,**kwargs)
            else:
                print('user_name or passwd error !')
    return wrapper
@auto
def home():
    print('from home')
@auto
def index():
    print('from index')
home()
index()
View Code

4、实现认证功能装饰器(在文件中去用户密码判断)

#用户登录装饰(当用户密码 判断用户那种类型在登录)
crrent_user={'user_name':None}
def auto(fun):
    def wrapper(*args,**kwargs):
        if crrent_user['user_name']:
            fun()
        else:
            user_name=input('user_name>>').strip()
            passwd=input('passwd>>').strip()
            with open('auth.txt','r',encoding='utf-8') as read_f:
                user_data=eval(read_f.read())
            if user_name in user_data and passwd == user_data[user_name]:
                crrent_user['user_name']=user_name
                fun(*args,**kwargs)
            else:
                print('user_name or passwd error !')
    return wrapper
@auto
def home():
    print('from home')
@auto
def index():
    print('from index')

home()
index()
View Code

有参装饰器

5、实现认证功能装饰器(判断用户那种类型在登录)

#用户登录装饰(基于用户登录类型 判断用户那种类型在登录)
crrent_user={'user_name':None}
def Auth(user_type='file'):
    def auto(fun):
        def wrapper(*args,**kwargs):
            if user_type == 'file':
                if crrent_user['user_name']:
                    fun()
                else:
                    user_name=input('user_name>>').strip()
                    passwd=input('passwd>>').strip()
                    with open('auth.txt','r',encoding='utf-8') as read_f:
                        user_data=eval(read_f.read())
                    if user_name in user_data and passwd == user_data[user_name]:
                        crrent_user['user_name']=user_name
                        fun(*args,**kwargs)
                    else:
                        print('user_name or passwd error !')
            elif user_type == 'mysql':
                print('from mysql ....')
            elif user_type == 'ldap':
                print('from ldap !!!')
            else:
                print('user type error !')
        return wrapper
    return auto
@Auth(user_type='file')
def home():
    print('from home')
@Auth(user_type='mysql')
def index():
    print('from index')
home()
index()
View Code

 

迭代器

定义:#迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来

#什么是迭代器对象:

  1、 有__iter__,执行得到仍然是迭代本身

  2、有__next__

#可迭代对象iterable:凡是对象下有__iter__方法:对象.__iter__,该对象就是可迭代对象

#迭代器对象:可迭代对象执行内置的__iter__方法,得到的结果就是迭代器对象

可迭代对象(Iterable

Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,像常见的list,tuple都是。如果给一个准确的定义的话,就是只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下标索引的__getitem__方法(这些双下划线方法会在其他章节中全面解释),那么它就是一个可迭代对象。

迭代器(iterator

迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义了这个方法的都算是迭代器。可以用通过下面例子来体验一下迭代器:

s='hello'
l=['a','b','c','d']
t=('a','b','c','d')
dic={'name':'egon','sex':'m',"age":18}
set1={1,2,3}
f=open('db.txt')
s.__iter__()
l.__iter__()
t.__iter__()
dic.__iter__()
set1.__iter__()
f.__iter__()

一般数据类型都是迭代器对象。

迭代器对象的优点

1、:提供了一种统一的(不依赖于索引的)迭代方式

2、:迭代器本身,比起其他数据类型更省内存,同一时间只有一个值在内存之中

迭代器对象的缺点

1、:一次性,只能往后走,不能回退,不如索引取值灵活

2、:无法预知什么时候取值结束,即无法预知长度

a=['a','c','d','e','f']
iter_a=iter(a)   #无法预知什么时候取值结束,即无法预知长度,需要抛出异常
while True:
    try:
        print(next(iter_a))
    except StopIteration:
        break

迭代器的例子:

for i in l: #l=l.__iter__()  for循环就是利用迭代器的原理来使用
    print(i)
with open('db.txt','r',encoding='utf-8') as read_f: 
    print(read_f is read_f.__iter__()) #文件read_f本身就是迭代器
#True 

补充:判断可迭代对象与迭代器对象(了解)

from collections import Iterable,Iterator
s='hello'
l=['a','b','c','d']
t=('a','b','c','d')
dic={'name':'egon','sex':'m',"age":18}
set1={1,2,3}
f=open('a.txt')

# print(isinstance(s,Iterable))
# print(isinstance(l,Iterable))
# print(isinstance(t,Iterable))
# print(isinstance(dic,Iterable))
# print(isinstance(set1,Iterable))
# print(isinstance(f,Iterable))

print(isinstance(s,Iterator))
print(isinstance(l,Iterator))
print(isinstance(t,Iterator))
print(isinstance(dic,Iterator))
print(isinstance(set1,Iterator))
print(isinstance(f,Iterator))
False
False
False
False
False
True
View Code

 

生成器

生成器(generator)

生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()和__next__()方法了,只需要一个yiled关键字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值。用生成器来实现斐波那契数列的例子是:

生成器

#生成器:在函数内部包含yield关键,那么该函数执行的结果是生成器

#生成器就是迭代器

def func():
    print('first')
    yield 11111111
    print('second')
    yield 2222222
    print('third')
    yield 33333333
    print('fourth')
g=func()  #g就是一个生成器,也就是一个迭代器
print(g is g.__iter__())  #True
for i in g:
    print(i)
    print('============>')

生成器generator的作用:

def fun(n):
    print('开始了~')
    while True:
        yield n
        n+=1
g=fun(0)
for i in g:  #可以产生无穷无尽的值
    print(i)
def my_range(start,stop):
    while True:
        if start == stop:
            raise  StopIteration  #自动抛出异常
        yield start
        start +=1
g=my_range(1,3)

for i in my_range(1,5):
    print(i)

#yield的功能:

# 1 把函数的结果做生迭代器(以一种优雅的方式封装好__iter__,__next__)

# 2 函数暂停与再继续运行的状态是由yield

yield生产器的应用:

       模仿linux命令grep功能:

# yield生产器的应用命令grep:
import  time
def tailf(filepath):
    with open(filepath,'r') as read_f:
        read_f.seek(0,2)
        while True:
            line= read_f.readline()
            if line:
                    yield line
            else:
                time.sleep(0.2)
def grep(word,lines):
    for i in lines:
        if word in i:
            print(i,end='')
grep('error',tailf('db.txt'))
###################往文件里面写##################
with open('db.txt','a',encoding='utf-8') as write_f:
    write_f.write('12eerrorddddr2\n')

 

三元表达式 

# def max(x,y):
#     if x>y:
#         return  x
#     else:return y
x=12
y=23
print(x) if x>y else print(y)  #三元表达式

 

列表解析 

在一个序列的值上应用一个任意表达式,将其结果收集到一个新的列表中并返回。它的基本形式是一个方括号里面包含一个for语句对一个iterable对象迭代。

l=[]
for i in range(10):
    l.append('egg%s'%i)
print(l)
#列表解析
l=['egg%s' %i for i in range(10)]
print(l)
['egg0', 'egg1', 'egg2', 'egg3', 'egg4', 'egg5', 'egg6', 'egg7', 'egg8', 'egg9']
['egg0', 'egg1', 'egg2', 'egg3', 'egg4', 'egg5', 'egg6', 'egg7', 'egg8', 'egg9']

l=['egg%s' %i for i in range(10) if i >5 ]
print(l)
['egg6', 'egg7', 'egg8', 'egg9']
l=[]
for i in range(10):
    if i>5:
        l.append('egg%s'%i)
print(l)
l=['egg%s' %i for i in range(10) if i >5 ]
print(l)

 

练习:

 把列表[1,2,3,4,5]都变成平方:

a=[1,2,3,4,5,6]
a=[i**2 for i in a]
print(a)
a=[1,2,3,4,5,6]
a_2=[i**2  for i in a if i >3]
print(a_2)
[1, 4, 9, 16, 25, 36]
[16, 25, 36]
View Code

 

生成器表达式 

生成器(generator)概念

生成器语法

生成器表达式: 通列表解析语法,只不过把列表解析的[]换成()
生成器表达式能做的事情列表解析基本都能处理,只不过在需要处理的序列比较大时,列表解析比较费内存。

生成器表达式

g=['agg%i' %i for i in range(10)]  #列表解析
print(g)
['agg0', 'agg1', 'agg2', 'agg3', 'agg4', 'agg5', 'agg6', 'agg7', 'agg8', 'agg9']
g=('agg%i' %i for i in range(10))   #生成器表达式
print(g)  #g是一个生成器地址
<generator object <genexpr> at 0x0000000001DE3678>
for i in g:
    print(i)
agg0
agg1
......

练习:

1、统计文本文件最长的一行。

with open('db.txt','r') as read_f:
    # print(max((len(line) for line in read_f)))
    print(max(len(line) for line in read_f))
View Code

2、文件内容如下,标题为:姓名,性别,年纪,薪资

人  性别 个数 价格

apple 18 3000
computer 38 30000
taoz 28 20000
美女 28 10000

要求统计总量是多少(所有个数*价格的总和)

# with open('apple.txt','r',encoding='utf-8') as  read_f:
#     l=[]
#     for line in read_f:
#         line=line.split()
#         count=int(line[1])
#         price=float(line[2])
#         l.append(count*price)
#     print(sum(l))

with open('apple.txt','r',encoding='utf-8') as  read_f:
    l=[int(line.split()[1])*float(line.split()[2])  for line in read_f]
    print(sum(l))
View Code

 #把文本文件中的东西放到列表中

with open('apple.txt','r',encoding='utf-8') as  read_f:
    info=[{'name':line.split()[0],
        'count':int(line.split()[1]),
        'price':float(line.split()[2])} for line in read_f if float(line.split()[2])>3000]
    print(info)
View Code

 

posted @ 2017-07-23 20:35  ShengLeQi  阅读(146)  评论(0)    收藏  举报