博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python基础-函数之装饰器、迭代器与生成器
阅读量:5158 次
发布时间:2019-06-13

本文共 13888 字,大约阅读时间需要 46 分钟。

1. 函数嵌套

1.1 函数嵌套调用

  函数的嵌套调用:在调用一个函数的过程中,又调用了其他函数

def bar():    print("from in the bar.")def foo():    print("from in the foo.")    bar()foo()

 

1.2 求函数最大值

def max2(x,y):    if x > y:        return x    else:        return ydef max4(a,b,c,d):    res1 = max2(a,b)    res2 = max2(res1,c)    res3 = max2(res2,d)    return res3res = max4(2,5,3,-4)print(res)

 

1.3 函数嵌套定义

函数的嵌套定义:在一个函数的内部,又定义另外一个函数

def f1():    x = 1    def f2():        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 = 20def foo():    global x    x = 30foo()print(x)        # 此时x的值已经被修改,变为30 # 可变类型的全局变量,在函数内部进行直接修改l = []def foo():    l.append("jack")foo()print(l)    # 此时l已经变为:['jack']

 

3.3 nonlocal

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

x = 0def f1():    x = 100    def f2():        x = 200        def f3():            nonlocal x            x = 300        f3()        print(x)   # 利用nonlocal定义的变量 进行修改上一层的局部变量    f2()    print(x)      # nonlocal只修改上一层局部变量,此时打印f1定义的变量f1()

 

3.2 作用域关系

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

x = 1def f1():    def f2():        print(x)    return f2func = f1()x = 10000func()       # 此时打印1000,只是打印的是x = 1定义的地方,只是在后面进行修改 x = 10000 # 作用域关系,在定义阶段就已经确定,与调用位置无关x = 1def f1():    def f2():        print(x)    return f2def foo(func):    x = 30000    func()   # 相当于调用f2,打印x为1foo(f1())

 

4. 闭包函数

4.1 定义

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

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

 

4.2 实例

# wrapper称为闭包函数,定义deco内部的函数,并对外部x的引用,而变量x不是全局变量def deco():    x = 1000    def wrapper():        print(x)    return wrapperfunc = deco()func()

 

4.3 闭包应用-惰性计算

  爬网页的简单程序

import requests   # pip3 install requestsdef index(url):    def wrapper():        # return requests.get(url).text        print(requests.get(url).text)    return wrapperpython_web = index("https://www.python.org")baidu_web = index("https://www.baidu.com")python_web()baidu_web()
 

4.4 查看闭包函数参数

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

import requests   # pip3 install requestsdef index(url):    def wrapper():        print(requests.get(url).text)    return wrapperpython_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 修改源代码

import timedef index():    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 修改了调用方式

import timedef wrapper(func):    start_time = time.time()    time.sleep(2)    func()    stop_time = time.time()    print("run time is %s" % (stop_time - start_time))def index():    time.sleep(2)    print("from in index.")wrapper(index)  # 修改了函数的调用方式

 

5.2.3 应用实例

import timedef timmer(func):    def wrapper():        start_time = time.time()        func()        stop_time = time.time()        print("run time is %s" %(stop_time - start_time))    return wrapper@timmer  # index=timmer(index)def index():    time.sleep(2)    print("from in index")@timmer  # home=timmer(home)def home():    time.sleep(2)    print("from in home")index()home()

  运行结果:

from in indexrun time is 2.0001142024993896from in homerun time is 2.0001144409179688

 

5.3 被装饰的对象有参数

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

import timedef timmer(func):    def wrapper(*args, **kwargs):        start=time.time()        func(*args, **kwargs)        stop=time.time()        print('run time is %s' %(stop-start))    return wrapper@timmer # home=timmer(home)def home(name):    time.sleep(2)    print('welcome %s to home page' %name)home('jack')  #  hom('jack') wrapper('jack')

 

5.4 被装饰的对象有返回值

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

import timedef timmer(func):    def wrapper(*args, **kwargs):        start=time.time()        res=func(*args, **kwargs)        stop=time.time()        print("run time is %s" %(stop-start))        return res    return wrapper@timmer # home=timmer(home)def home(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}def auth(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']=name return res else: print('user or password error') return wrapper@auth #index=auth(index) index=wrapperdef index(): print('from index')@authdef home(name): print('welcome %s' %name)index() #wrapper()home('jack')

 

5.5.2 有参函数装饰器

current_user={
"user":None}def auth(auth_type="file"): def deco(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"] = name return res else: print("user or password error") elif auth_type == "mysql": print("mysql") elif auth_type == "ldap": print("ldap") else: print("not valid auth_type") return wrapper return deco@auth(auth_type="mysql") #@deco #index=deco(index)def index(): print("from index")@auth(auth_type='file')def home(name): print("welcome %s" %name)index() #wrapper()home('jack')

 

5.6 装饰器的其他属性

5.6.1 被装饰函数的注释信息

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

from functools import wrapsdef decorator(func):    @wraps(func)    def wrapper(*args,**kwargs):        res = func(*args,**kwargs)        return res    return wrapper@decoratordef index():    '''这是注释index信息'''    print('from to index')    return "in the index"print(index.__doc__)# print(help(index))

 

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

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

def timmer(func):    def wrapper(*args, **kwargs):        print("this is timmer.")        res=func(*args,**kwargs)        return res    return wrapperdef auth(auth_type='file'):    def deco(func):        def wrapper(*args, **kwargs):            print("this is auth.")            return func(*args, **kwargs)        return wrapper    return deco@timmer #index=timmer(wrapper)@auth() # @deco #index=deco(index) #wrapperdef index():    '''这是index函数'''    print('welcome to index')    return "from in index"index()

 

6. 迭代器

6.1 解析

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

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

 

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

l=['aa','bb','cc','dd']count=0while count < len(l):    print(l[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)) # StopIterationl = ['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)while True: try: # print(next(iter_l)) k=next(iter_dic) print(k,dic[k]) except StopIteration: 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 import Iterable,Iterators='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:

def func():    print("first")    yield 111    print("second")    yield 222    print("third")    yield 333    print("forth")g = func()from collections import Iteratorprint(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:

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

def func(n):    print('我开动啦')    while True:        yield n        n+=1g = func(0)    # 没有任何执行效果# print(next(g))# print(next(g))for i in g:    print(i)

 

实例3:

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

def my_range(start,stop):    while True:        if start == stop:            raise StopIteration        yield start        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'import timedef tail(filepath):    with open(filepath, 'r') 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:        if pattern in line:            print(line,end='')grep('error',tail('access.log'))

 

8. 三元表达式

def foo(x):    if x > 3:        return 'ok'    else:        return 'no'# 利用三元表达式,使代码更简洁x = 5res = x if x > 3 else 'no'print(res)def max2(x,y):    return x if x > y else yprint(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判断,不支持elsel=['egg%s' %i for i in range(10) if i > 5]   # 只有条件成立执行,不支持elseprint(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 in f:       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)

 

转载于:https://www.cnblogs.com/goodshipeng/p/7226986.html

你可能感兴趣的文章
ES5_03_Object扩展
查看>>
Apache-ab 接口性能测试
查看>>
EF 4.1 Code First Walkthrough
查看>>
常用MySQL语法
查看>>
007API网关服务Zuul
查看>>
bzoj 2600: [Ioi2011]ricehub
查看>>
iOS __strong __weak @Strongify @Weakify
查看>>
thinkphp引入PHPExcel类---thinkPHP类库扩展-----引入没有采用命名空间的类库
查看>>
创建数据库,表
查看>>
Luogu 1970 NOIP2013 花匠 (贪心)
查看>>
javascript笔记---貌似大叔
查看>>
去重查询表mysql 中数据
查看>>
工厂模式
查看>>
AngularJS学习之旅—AngularJS 模块(十五)
查看>>
计算机网络基础知识
查看>>
大数据算法:对5亿数据进行排序
查看>>
BZOJ4372: 烁烁的游戏【动态点分治】
查看>>
C#里如何遍历枚举所有的项
查看>>
FPGA的上电复位
查看>>
工作那些事(三十一)怎样带好一个项目团队
查看>>