python的装饰器迭代器与生成器_python基础-函数之装饰器、迭代器与生成器

deff1():

x= 1

deff2():print("from f2.")

f2()#只能在函数内部调用

f1()

2. 名称空间

2.1 介绍

名称空间:存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方。

内置名称空间:在python解析器启动时产生,存放一些python内置的名字。

全局名称空间:在执行文件时产生,存放文件级别定义的名字。

局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效。

2.2 加载、查找顺序

加载顺序:内置名称空间 --> 全局名称空间 --> 局部名称空间

查找顺序:局部名称空间 --> 全局名称空间 --> 内置名称空间

3. 作用域

3.1 基本概念

作用域:作用的范围

全局作用域:全局存活、全局有效

局部作用域:临时存活、局部有效

查看作用域:globals(),locals()

查看全局作用域:globals()

查看局部作用域:locals()

3.2 global

局部修改全局的名字:global

针对全局不可变类型,用global进行修改

针对全局可变类型,在函数内部可以直接修改全局变量的内容

利用global,在函数内部进行修改全局变量;此种方法慎用;以后尽量避免利用局部修改全局的名字

#不可变类型,利用global进行修改全局变量值x= 20

deffoo():globalx

x= 30foo()print(x) #此时x的值已经被修改,变为30

#可变类型的全局变量,在函数内部进行直接修改l=[]deffoo():

l.append("jack")

foo()print(l) #此时l已经变为:['jack']

3.3 nonlocal

nonlocal,修改的局部变量的上一层变量,只是修改局部的变量;

x =0deff1():

x= 100

deff2():

x= 200

deff3():

nonlocal x

x= 300f3()print(x) #利用nonlocal定义的变量 进行修改上一层的局部变量

f2()print(x) #nonlocal只修改上一层局部变量,此时打印f1定义的变量

f1()

3.2 作用域关系

作用域关系:在函数定义时就已经确定,与调用位置无关;在调用函数时,必须回到函数原来定义的位置去找作用域关系

x = 1

deff1():deff2():print(x)returnf2

func=f1()

x= 10000func()#此时打印1000,只是打印的是x = 1定义的地方,只是在后面进行修改 x = 10000

#作用域关系,在定义阶段就已经确定,与调用位置无关

x= 1

deff1():deff2():print(x)returnf2deffoo(func):

x= 30000func()#相当于调用f2,打印x为1

foo(f1())

4. 闭包函数

4.1 定义

闭包函数简单理解就是:闭合、包裹的函数

闭包函数:定义在函数内部的函数,包含对外部作用域名字的引用,而不是对全局作用域名字的引用,那么该内部函数就称为闭包函数

4.2 实例

#wrapper称为闭包函数,定义deco内部的函数,并对外部x的引用,而变量x不是全局变量

defdeco():

x= 1000

defwrapper():print(x)returnwrapper

func=deco()

func()

4.3 闭包应用-惰性计算

爬网页的简单程序

import requests #pip3 install requests

defindex(url):defwrapper():#return requests.get(url).text

print(requests.get(url).text)returnwrapper

python_web= index("https://www.python.org")

baidu_web= index("https://www.baidu.com")

python_web()

baidu_web()

4.4 查看闭包函数参数

查看闭包函数外面包裹的参数

import requests #pip3 install requests

defindex(url):defwrapper():print(requests.get(url).text)returnwrapper

python_web= index("https://www.python.org")print(python_web.__closure__) #(,)

print(python_web.__closure__[0].cell_contents) #查看闭包函数的包裹的参数 https://www.python.org

5. 装饰器

5.1 基本概念

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

装饰器:装饰其他对象的工具

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

装饰器的遵循的原则:

1.不修改被装饰对象的源代码

2.不修改被调用对象的调用方式

装饰器的目的是:

在遵循1和2原则的前提,为其他可调用对象添加新功能

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

5.2 装饰器前奏

5.2.1 修改源代码

importtimedefindex():

start_time=time.time()

time.sleep(2)print("from in index")

stop_time=time.time()print("run time is %s" % (stop_time -start_time))

index()

5.2.2 修改了调用方式

importtimedefwrapper(func):

start_time=time.time()

time.sleep(2)

func()

stop_time=time.time()print("run time is %s" % (stop_time -start_time))defindex():

time.sleep(2)print("from in index.")

wrapper(index)#修改了函数的调用方式

5.2.3 应用实例

importtimedeftimmer(func):defwrapper():

start_time=time.time()

func()

stop_time=time.time()print("run time is %s" %(stop_time -start_time))returnwrapper

@timmer#index=timmer(index)

defindex():

time.sleep(2)print("from in index")

@timmer#home=timmer(home)

defhome():

time.sleep(2)print("from in home")

index()

home()

运行结果:

from inindex

run timeis 2.0001142024993896

from inhome

run timeis 2.0001144409179688

5.3 被装饰的对象有参数

解决装饰器的闭包函数,能够适应有参数、无参数、各种各样的参数的形式

importtimedeftimmer(func):def wrapper(*args, **kwargs):

start=time.time()

func(*args, **kwargs)

stop=time.time()print('run time is %s' %(stop-start))returnwrapper

@timmer#home=timmer(home)

defhome(name):

time.sleep(2)print('welcome %s to home page' %name)

home('jack') #hom('jack') wrapper('jack')

5.4 被装饰的对象有返回值

有返回值的情况,需要在装饰器处理有返回值的情况,也就是在wrapper最后,利用return进行返回处理结果

importtimedeftimmer(func):def wrapper(*args, **kwargs):

start=time.time()

res=func(*args, **kwargs)

stop=time.time()print("run time is %s" %(stop-start))returnresreturnwrapper

@timmer#home=timmer(home)

defhome(name):

time.sleep(2)print("welcome %s to home page" %name)return "from home return ok."res= home('jack') #wrapper('jack')

print(res) #from home return ok.

5.5 装饰器:登录认证

实行认证功能的装饰器,需要对用户输入用户名和密码进行验证,在输入正确的情况下,才执行被装饰函数的内容。

5.5.1 无参数装饰器实现认证

current_user={'user':None}defauth(func):def wrapper(*args, **kwargs):if current_user['user']: #自带bool判断功能

return func(*args, **kwargs)

name=input('name:').strip()

password=input('password:').strip()

with open('db.txt', encoding='utf-8') as f:

user_dic=eval(f.read())if name in user_dic and password ==user_dic[name]:

res=func(*args,**kwargs)

current_user['user']=namereturnreselse:print('user or password error')returnwrapper

@auth#index=auth(index) index=wrapper

defindex():print('from index')

@authdefhome(name):print('welcome %s' %name)

index()#wrapper()

home('jack')

5.5.2 有参函数装饰器

current_user={"user":None}def auth(auth_type="file"):defdeco(func):def wrapper(*args, **kwargs):if auth_type == "file":if current_user["user"]:return func(*args, **kwargs)

name= input("name:").strip()

password= input("password:").strip()

with open("db.txt", encoding="utf-8") as f:

user_dic=eval(f.read())if name in user_dic and password ==user_dic[name]:

res= func(*args, **kwargs)

current_user["user"] =namereturnreselse:print("user or password error")elif auth_type == "mysql":print("mysql")elif auth_type == "ldap":print("ldap")else:print("not valid auth_type")returnwrapperreturndeco

@auth(auth_type="mysql") #@deco #index=deco(index)

defindex():print("from index")

@auth(auth_type='file')defhome(name):print("welcome %s" %name)

index()#wrapper()

home('jack')

5.6 装饰器的其他属性

5.6.1 被装饰函数的注释信息

需要导入functools模块,在被装饰的函数上方加@wraps(func)

from functools importwrapsdefdecorator(func):

@wraps(func)def wrapper(*args,**kwargs):

res= func(*args,**kwargs)returnresreturnwrapper

@decoratordefindex():'''这是注释index信息'''

print('from to index')return "in the index"

print(index.__doc__)#print(help(index))

5.6.2 一个函数被多个装饰器装饰

一个函数的多个装饰器,在上面的装饰器先执行,在下面的装饰器后执行

deftimmer(func):def wrapper(*args, **kwargs):print("this is timmer.")

res=func(*args,**kwargs)returnresreturnwrapperdef auth(auth_type='file'):defdeco(func):def wrapper(*args, **kwargs):print("this is auth.")return func(*args, **kwargs)returnwrapperreturndeco

@timmer#index=timmer(wrapper)

@auth() #@deco #index=deco(index) #wrapper

defindex():'''这是index函数'''

print('welcome to index')return "from in index"index()

6. 迭代器

6.1 解析

迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来;取出序列类型的元素,就是迭代

序列类型:列表、元组、字符串

下面的方法按照索引的取值方式,不适用没有索引的数据类型

l=['aa','bb','cc','dd']

count=0while count

count+=1

不依赖索引方式,进行取值,就是迭代器;迭代非序列类型编程可能。

6.2可迭代对象

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

s='hello' #字符串

l=['a','b','c','d'] #列表

t=('a','b','c','d') #元组

dic={'name':'egon','sex':'m'} #字典

set1={1,2,3} #集合

f=open('db.txt') #文件

s.__iter__()

l.__iter__()

t.__iter__()

dic.__iter__()

set1.__iter__()

f.__iter__()

6.3迭代器对象

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

迭代器:本身也是可迭代对象

什么是迭代器对象:

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

2.有__next__方法

dic = {'name': 'egon', 'sex': 'm', "age": 18}

i= dic.__iter__()#print(i) #iterator迭代器

#i.__next__() #next(i)

print(next(i))print(next(i))print(next(i))print(next(i)) #StopIteration

l= ['a', 'b', 'c', 'd']

i= l.__iter__()print(next(i))print(next(i))print(next(i))print(next(i))print(next(i)) #StopIteration

可以不依赖于索引的取值方式

l=['a','b','c','d']

dic={'name':'egon','sex':'m',"age":18}

iter_l=iter(l)

iter_dic=iter(dic)whileTrue:try:#print(next(iter_l))

k=next(iter_dic)print(k,dic[k])exceptStopIteration:break

6.4迭代器优缺点

迭代器对象的优点

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

2:迭代器本身,比起其他数据类型更省内存

l = ['a', 'b', 'c', 'd']

i=iter(l)

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

x=dic.keys()print(x)

i= x.__iter__() #执行__iter()__,成为迭代器对象;可以对i执行next()的方法

#文件是迭代器对象

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

#print(next(f))

#print(next(f))

f.read()

迭代器对象的缺点

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

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

l=['a','b','c','d']

i=iter(l)print(next(i))print(next(i))print(next(i))

6.5 for循环原理

for循环遵循迭代器协议,有__iter__方法,还有__next__方法。

for循环,利用迭代器,进行循环;for,可跟可迭代对象的数据类型;自动进行捕捉异常,自动调用__iter__方法

例如列表:for循环,先调用__iter__方法,变为迭代器对象,然后再进行循环

迭代器:有__iter__方法,为for循环准备的。

l=['a','b','c','d']for item in l: #iter_l=l.__iter__()

print(item)for item in {1,2,3,4}: #可循环集合

print(item)

with open('a.txt') as f:#for line in f: #i=f.__iter__() 可循环文件 把文件变成可迭代对象

#print(line)

print(f is f.__iter__())

6.6 判断可迭代对象、迭代器对象

需要利用模块Iterable、Iterator进行判断

from collections importIterable,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)) #只有文件是迭代器对象

7. 生成器

7.1 简介

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

生成器就是迭代器

yield的功能:

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

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

7.2 应用实例

实例1:

deffunc():print("first")yield 111

print("second")yield 222

print("third")yield 333

print("forth")

g=func()from collections importIteratorprint(isinstance(g,Iterator)) #生成器就是迭代器

#print(next(g))#print('======>')#print(next(g))#print('======>')#print(next(g))#print('======>')#print(next(g))

for i in g: #i=iter(g)

print(i)

实例2:

产生无穷无尽的值,是个重复的过程。利用生成器解决此问题。

deffunc(n):print('我开动啦')whileTrue:yieldn

n+=1g= func(0) #没有任何执行效果#print(next(g))#print(next(g))

for i ing:print(i)

实例3:

模拟range功能,在python3中,range只是一个迭代器对象,并没有产生所需数据。

defmy_range(start,stop):whileTrue:if start ==stop:raiseStopIterationyieldstart

start+=1g= my_range(1,5) #是个生成器,就是一个迭代器

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

7.3 yield与return的比较

相同:都有返回值的功能

不同:return只能返回一次值,而yield可以返回多次值

7.4 模拟tail、grep

#python3 tail.py -f access.log | grep 'error'

importtimedeftail(filepath):

with open(filepath,'r') as f:

f.seek(0,2)whileTrue:

line=f.readline()ifline:yieldlineelse:

time.sleep(0.2)defgrep(pattern,lines):for line inlines:if pattern inline:print(line,end='')

grep('error',tail('access.log'))

8. 三元表达式

deffoo(x):if x > 3:return 'ok'

else:return 'no'

#利用三元表达式,使代码更简洁

x = 5res= x if x > 3 else 'no'

print(res)defmax2(x,y):return x if x > y elseyprint(max2(1,3))

name='egon'

print('SB' if name == 'alex' else 'shuai')

9. 列表解析

列表解析,也就是列表生成式

列表解析,直接在列表中,写for循环进行生产列表

l=[]for i in range(10):

l.append('egg%s' %i)print(l)#产生10个值的列表

l=['egg%s' %i for i in range(10)]print(l)#按照条件,产生一个列表,支持if判断,不支持else

l=['egg%s' %i for i in range(10) if i > 5] #只有条件成立执行,不支持else

print(l)#对原列表进行附加操作,进行生产新列表

nums=[1,2,3,4,5,6]

nums_new=[item**2 for item in nums if item > 3]print(nums_new)#对原列表根据条件进行筛选,生产新列表

names=['alex_sb','wupeiqi_sb','egon','yuanhao_sb']

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

10. 生成器表达式

g=('egg%s' %i for i in range(1000))

上面就是生成器,其实就是迭代器;每次在内存中就只有一条值

场景:数据量大的场景,

生成器:就是生成值。

生成器表达式:就是拿到生产数据的机器。

实例1:

g=('egg%s' %i for i in range(1000))print(g)print(next(g))print(next(g))print(next(g))

实例2:

#获取文件最长一行的值

with open('db.txt',encoding='utf-8') as f:

res= max(len(line) for line in f) #python提供简写的形式,去掉多余的小括号

print(res)

实例3:

模拟求总价

with open('a.txt',encoding='utf-8') as f:

l= ( float(line.split()[1]) * int(line.split()[2]) for line in f) #解决文件过大的问题

print(sum(l))#等价于

with open('a.txt', encoding='utf-8') as f:

l=[]for line inf:

goods=line.split()

price=float(goods[1])

count=int(goods[2])

cost=price *count

l.append(cost)print(sum(l)) #196060.0

实例4:

模拟数据库查询,根据条件进行查询

#[{'name': 'apple', 'price': 333, 'count': 3}, ]

with open('a.txt',encoding='utf-8') as f:

info=[

{'name':line.split()[0],'price':float(line.split()[1]),'count':int(line.split()[2])

}for line in f if float(line.split()[1]) >= 30000]print(info)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值