day-04

一、 闭包函数

一 什么是闭包?

内部函数包含对外部作用域而非全局作用域的引用

#提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来喽,包起呦,包起来哇

 示例:

def outter():
    x=110
    def inner():
        print(x)
    return inner


f=outter() #这里是把返回值赋值给f
f() #然后在用f调用函数

二 闭包的意义与应用

#闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
#应用领域:延迟计算(原来我们是传参,现在我们是包起来)

from urllib.request import urlopen #加载爬虫模块
def index(url):
    def get():
        return urlopen(url).read()
    return get
baidu=index('http://www.baidu.com') #传入函数参数
print(baidu().decode('utf-8'))

二、 装饰器

装饰器就是闭包函数的一种应用场景

开放封闭原则:对修改封闭,对扩展开放

二 什么是装饰器

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

三 装饰器的使用

一个简单的装饰器案例


#inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间
import time

def timmer(func): #func 就是被装饰对象的内存地址
# func=index
#时间闭包函数
def inner():
start_time = time.time()
func()
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
return inner #把内部函数返回出去,方便外面调用

@timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数
def index():
time.sleep(3)
print("welcome to index page")
index()

 解决home传参问题

#inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间
import time

def timmer(func):
    # func=index
#时间闭包函数
    def inner(*args,**kwargs):  #这里用args 接受所有参数
        start_time = time.time()
        func(*args,**kwargs)  #这原样返回
        stop_time = time.time()
        print('run time is %s' % (stop_time - start_time))
    return inner #把内部函数返回出去,方便外面调用

@timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数
# def index():
#     time.sleep(3)
#     print("welcome to index page")
# index()
def home(name):
    time.sleep(3)
    print("welcome to home %s page"%(name))
home('sunkedong')

带有返回值的装饰器
#inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间
import time

def timmer(func):
    # func=index
#时间闭包函数
    def inner(*args,**kwargs):
        start_time = time.time()
        res=func(*args,**kwargs)
        stop_time = time.time()
        print('run time is %s' % (stop_time - start_time))
        return res  #这里的意思是把上面res保存的结果返回出去,在外面需要调用
    return inner #把内部函数返回出去,方便外面调用

@timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数
def index():
    time.sleep(1)
    print("welcome to index page")
    return "index-res"  #存一个测试的返回值
res=index() #把返回值保存到变量中
print(res)#打印,下面的home是一样的原理
@timmer
def home(name):
    time.sleep(1)
    print("welcome to home %s page"%(name))
    return "home-res"
res=home('sunkedong')
print(res)

用户登录装饰器

第一步

import time
def login(func):
    # func=index
    def inner(*args,**kwargs):
        name=input('username>>').strip()
        pwd=input('password>>').strip()
        if name == "sunkd" and pwd == "sunkd":
            res=func(*args,**kwargs)
            return res
    return inner

@login
def index():
    time.sleep(1)
    print("login success...")
    print("welcome to index page")
    return "index_ok"
@login
def home(name,age):
    time.sleep(1)
    print("login success...")
    print('welcome to %s home page,age is %s '%(name,age))
    return "home_ok"home('sunkd',22)
index()

第二步、修复两次登录的bug

import time
current_status={'user':None,'login_status':False}
def login(func):
    # func=index
    def inner(*args,**kwargs):
        #下面是判断登录状态,如果字典有内容,并且为True 那么直接执行函数,否则跳到登录
        if current_status['user'] and current_status['login_status'] == True:
            res = func(*args, **kwargs)
            return res
        else:
            name=input('username>>').strip()
            pwd=input('password>>').strip()
            if name == "sunkd" and pwd == "sunkd":
                print('login sucess.')
                #登录成功后,记录状态
                res=func(*args,**kwargs)
                current_status['user']=name
                current_status['login_status']=True
                return res
    return inner

@login
def index():
    time.sleep(1)
    print("welcome to index page")
    return "index_ok"
@login
def home(name,age):
    time.sleep(1)
    print('welcome to %s home page,age is %s '%(name,age))
    return "home_ok"

index()
home('sunkd',22)

 三、带参数的装饰器

import time
current_status={'user':None,'login_status':False}

def auth(user_type='mysql'): #这里可以定义一个默认参数。后面可以重新赋值。
    # user_type='file'
    def login(func):
        def inner(*args,**kwargs):
            #下面是判断登录状态,如果字典有内容,并且为True 那么直接执行函数,否则跳到登录
            if current_status['user'] and current_status['login_status'] == True:
                res = func(*args, **kwargs)
                return res
            if user_type == 'file':
                u='sunkd'
                p='sunkd'
            elif user_type == 'mysql':
                print('mysql auth')
            elif user_type == 'ldap':
                print('ldap auth')
            else:
                print('no fount the auth type')
                exit(2)
            #下面开始用户登录
            name = input('username>>').strip()
            pwd = input('password>>').strip()
            if name == u and pwd == p :
                print('login sucess.')
                # 登录成功后,记录状态
                res = func(*args, **kwargs)
                current_status['user'] = name
                current_status['login_status'] = True
                return res
        return inner
    return login
#下面返回的其实还是inner的函数
@auth(user_type='file1')
def index():
    time.sleep(1)
    print("welcome to index page")
    return "index_ok"
index()

# #下面这种调用方式比较原始,做为理解使用
# index=auth(user_type='file')(index) #这里就重新赋值了。会打印file
# index()

 

 

 

 

 

 

 

加多个装饰器

import time
current_status={'user':None,'login_status':False}

def timmer(func):
    def inner(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is :[%s]' %(stop_time-start_time))
        return res

    return inner

def auth(egine='file'):
    # egine='file'
    def wrapper(func):
        def inner(*args,**kwargs):
            if current_status['user'] and current_status['login_status']:
                res = func(*args, **kwargs)
                return res

            if egine == 'file':
                u='egon'
                p='123'
            elif egine == 'mysql':
                u = 'egon'
                p = '123'
            elif egine == 'ldap':
                u = 'egon'
                p = '123'
            else:
                pass
            name = input('username>>:').strip()
            pwd = input('password>>:').strip()
            if name == u and pwd == p:
                print('login successfull')
                current_status['user'] = name
                current_status['login_status'] = True
                res = func(*args, **kwargs)
                return res
        return inner
    return wrapper


@timmer
@auth(egine='ldap') #@wrapper #index=wrapper(timmer_inner)
# @timmer #timmer_inner=timmer(index)
def index():
    time.sleep(3)
    print('welcome to index page')
    return 123


index() #inner()

 

 

三、迭代器

'''
1 什么叫迭代:迭代是一个重复过程,每次重复都是基于上一次的结果来的
2 为什么要用迭代器?

l=['a','b','c']
n=0
while n < len(l):
print(l[n])
n+=1

 


- 对于序列类型:字符串,列表,元组,可以使用基于索引的迭代取值方式,而对于没有索引的类型,如字典,
集合、文件,这种方式不再适用,于是我们必须找出一种能不依赖于索引的取值方式,这就是迭代器

3 可迭代的对象:只要对象内置有__iter__方法,obj.__iter__
4 迭代器对象:对象既内置有__iter__方法,又内置有__next__,如文件对象
注意:可迭代对象不一定是迭代器对象,而迭代器对象一定是可迭代的对象

'''
#可迭代的对象

# 'hello'.__iter__
# [1,2].__iter__
# (1,2).__iter__
# {'a':1}.__iter__
# {1,2,3}.__iter__
#

 

#既是可迭代对象,又是迭代器对象

# open('a.txt','w').__iter__
# open('a.txt','w').__next__

 

# 迭代器对象执行__iter__得到的仍然是它本身

 

# dic={'a':1,'b':2,'c':3}
# iter_dic=dic.__iter__()
#
# print(iter_dic.__iter__() is iter_dic)

 

# f=open('a.txt','w')
# print(f is f.__iter__())


#迭代器对象的用处

# dic={'a':1,'b':2,'c':3}
# iter_dic=dic.__iter__()


# print(iter_dic.__next__())
# print(next(iter_dic))
# print(next(iter_dic))
# print(next(iter_dic)) #StopIteration


# with open('a.txt','r') as f:
# print(next(f))
# print(next(f))
# print(next(f))


# l=[1,2,3,4,5]
# iter_l=l.__iter__()
# print(iter_l)
# print(next(iter_l))
# print(next(iter_l))
# print(next(iter_l))

 

#基于迭代器对象的迭代取值(不依赖索引)

dic={'a':1,'b':2,'c':3}

iter_dic=dic.__iter__()
obj=range(1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)

# list(obj)


# while True:
# try:
# i=next(iter_dic)
# print(i)
# except StopIteration:
# break
#

# for i in dic: #iter_dic=dic.__iter__()
# print(i)

 


'''
迭代器的优缺点:
- 优点:
提供了一种统一的迭代取值方式,该方式不再依赖于索引
更节省内存

- 缺点:
无法统计长度
一次性的,只能往后走,不能往前退,无法获取指定位置的值
'''

 

from collections import Iterable,Iterator

print(isinstance('hello',Iterable))
print(isinstance('hello',Iterator))

 

四、生成器

定义:只要函数内部出现yield关键字,那么再调用该函数,将不会立即执行函数体代码,会到到一个结果
该结果就是生成器对象

#
# def func():
# print('===>first')
# yield 1
# print('===>second')
# yield 2
# print('====>third')
# yield 3
#
#
# g=func()
# print(g)

 

#生成器本质就是迭代器

# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))


# print(next(func()))
# print(next(func()))
# print(next(func()))

 

 

# for i in g:
# print(i)
#
# for i in g:
# print(i)
#
# for i in g:
# print(i)

'''

 

yield的功能:
- 为我们提供了一种自定义迭代器的方式
- 对比return,可以返回多次值,挂起函数的运行状态

'''

#自定义功能,可以生成无穷多个值,因为同一时间在内存中只有一个值

# def my_range(start,stop,step=1):
# while start < stop:
# yield start
# start+=step


# g=my_range(1,5,2) #1 3
# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))
#
# for i in my_range(1,1000000000000000000000000000000000000000000,step=2):
# print(i)

 


# tail -f access.log | grep '404'
# import time
# def tail(filepath):
# with open(filepath,'rb') as f:
# f.seek(0,2)
# while True:
# line=f.readline()
# if line:
# yield line
# else:
# time.sleep(0.2)
#
# def grep(pattern,lines):
# for line in lines:
# line=line.decode('utf-8')
# if pattern in line:
# yield line
#
# g=grep('404',tail('access.log'))
# for line in g:
# print(line)

 

 

 

 


#yield的表达式形式的应用

 

# def eater(name):
# food_list=[]
# print('%s 开动啦' %name)
# while True:
# food=yield food_list #food=‘骨头’
# print('%s 开始吃 %s' %(name,food))
# food_list.append(food)
#
# g=eater('alex')

# g.send(None) #next(g)
# print(g.send('骨头'))
# print(g.send('shi'))

 

# def f1():
# while True:
# x=yield
# print(x)
#
# g=f1()
# next(g)
# g.send(1)
# g.send(1)
# g.close()
# g.send(1)
# g.send(1)
# g.send(1)

二元表达式

 def my_max(x,y):
    return x if x > y else y

列表解析 与生成器表达式

 

egg_list=[]
for i in range(10):
    if i >= 3:
        res='egg%s' %i
        egg_list.append(res)


names=['egon','alex_sb','wupeiqi','yuanhao']

names=[name.upper() for name in names if not name.endswith('sb')]
print(names)

 

#1、把列表推导式的[]换成()就是生成器表达式

#2、示例:生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性
>>> chicken=('鸡蛋%s' %i for i in range(5))
>>> chicken
<generator object <genexpr> at 0x10143f200>
>>> next(chicken)
'鸡蛋0'
>>> list(chicken) #因chicken可迭代,因而可以转成列表
['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4',]

#3、优点:省内存,一次只产生一个值在内存中

 

 

 

 

 

 

 

 

 

 



posted @ 2017-09-26 23:08  sunkd  阅读(143)  评论(0编辑  收藏  举报