函数-----函数进阶(闭包、无参装饰器、有参装饰器、迭代器、生成器)

一、名称空间

顾名思义就是存放名字的地方;举例:若变量X=1,1存放在内存中,是存放名字X与1绑定关系的地方。

名称空间有三种:

1.locals:函数内的名称空间,包括局部变量和形参

2.globals:全局变量,函数定义锁在模块的名字空间

3.builtins: 内置模块的名字空间

二、作用于的查找顺序

LEGB顺序

locals--->enclosing(外部嵌套函数的名称空间)--->globals--->builtins

三、闭包

即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数)。而且,这些函数可以访问他们所在的外部函数中声明的所有局部变量、参数。当其中一个这样的内部函数在包含他们的外部函数之外被调用时,就会形成闭包。

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在函数对象外还包含了一层作用于,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

def func():
    n = 10
    def func2():
        print('func2:',n)
    return func2

f = func()
print(f)
f()

>>>><function func.<locals>.func2 at 0x000001F9C4B1B9D8>
>>>>func2: 10

为函数传参的两种方式:

方式一:直接把函数需要的参数定义成形参

方式二:利用闭包函数传参

复制代码
def func():
    x = 4
    def func2():
        print(x)
    return func2
res = func()
print(res)
res()

四、装饰器

   定义:定义一个工具,该工具是用来装饰其他函数的,来增加额外功能的。

  为什么要用装饰器:在不修改被装饰器源代码对象以及调用方式的前提下,为被装饰对象添加新功能。

开放封闭原则:对拓展功能是开放的;对修改源代码是封闭的。

import time

def index(x,y,z):
    time.sleep(3)
    print('index%s %s %s' %(x,y,z))
    return 666
# print(index)-------<function index at 0x000001A2AD783E18>

def outter(func1):
    # func = index的内存地址
    def wrapper(*args,**kwargs):
        start = time.time()
        res = func1(*args,**kwargs)  # index的内存地址
        stop = time.time()
        print(stop - start)
        return res
    return wrapper
index = outter(index)  # outter的内存地址
# print(index)-----<function outter.<locals>.wrapper at 0x000001A2AF67BA60>
res = index(3,5,6,)
print('返回值----',res)

# 结果
# >>>  index3 5 6
# >>>  3.000042200088501
# >>>  返回值---- 666

语法糖:当需要同一个装饰器装饰不同的函数的时候,可以把装饰器写在最上面,在函数的上面单独一行@装饰器名字

import time
def outter(func1):
    # func = index的内存地址
    def wrapper(*args,**kwargs):
        start = time.time()
        res = func1(*args,**kwargs)  # index的内存地址
        stop = time.time()
        print(stop - start)
        return res
    return wrapper

@outter
def index(x,y,z):
    time.sleep(3)
    print('index%s %s %s' %(x,y,z))
    return 666

装饰器模板

def outter(func):
    def wrapper(*args,**kwargs):
        # 1.调用原函数
        # 2.增加新功能
        res = func(*args,**kwargs)
        return res
    return wrapper

 加了装饰器之后如果需要保持和原函数的属性一直,操作如下:应用wraps

import time
from functools import wraps  # 导入wraps功能

def timmer(func):
    '''计时器'''
    @wraps(func)  # 自动将原函数func的属性赋值给wrapper
    def wrapper(*args,**kwargs):
        strat = time.time()
        res = func(*args,**kwargs)
        stop = time.time()
        print(stop - strat)
        return res
    # 手动将原函数的属性赋值给wrapper
    # 1.函数wrapper.__name__ = 原函数.__name__
    # 2.函数wrapper.__doc__ = 原函数.__doc__
    # 1.wrapper.__name__ = func.__name__
    # 2.wrapper.__doc__ = func.__doc__
    return wrapper

@timmer
def login_in(x):
    '''登入验证'''
    time.sleep(2)
    print('登入成功!',x)
login_in(222)
print(login_in.__name__)
print(login_in.__doc__)

# >>>登入成功! 222
#>>>2.0001063346862793
# >>>login_in
# >>>登入验证

有参装饰器

  应用原因

# 由于语法糖的限制,outter函数只能有一个参数,并且函数知识用来接收被修饰对象的内存地址
def outter(func):  # outter 的参数也不能改动
    def wrapper(*args,**kwargs):  # wrapper的参数不能改动
        res = func(*args,**kwargs)
        return res
    return wrapper

如果outter需要接受多个参数时,在无参装饰器的基础上再套一层,为被装饰对象多传值

def auth(a,b,c):
    def outter(func):  # outter 的参数也不能改动
        def wrapper(*args,**kwargs):  # wrapper的参数不能改动
            res = func(*args,**kwargs)
            return res
        return wrapper
    return outter

@auth(a = 111, b = 222, c = 333)
def logn_in(x):
    pass

多个装饰器:

加载顺序是自下而上的;执行顺序是自上而下的。

五.迭代器

  是指迭代(是一个重复的过程)取值的工具,基于上一次结果而继续的,单纯的重复不是迭代。

  可迭代对象:但凡内置方法中有__iter__方法的都称为可迭代对象

  迭代器对象:有__iter__()同时有__next__()方法

迭代器适用所有类型:(字符串、列表、字典、元组、集合、文件)

a = 'afsafacasd'
a_iterator = a.__iter__()  # 迭代器
while True:
    try:
        print(a_iterator.__next__())
    except StopIteration:
        break

以下代码与上面的功能一样:

1.调出a.__iter__(),得到一个迭代器

2.调出迭代器下面的__next__()方法,拿到一个返回值赋值给k。

3.循环步骤2,直到异常出现,跳出循环。

a = 'afsafacasd'
for k in a:
    print(k)

总结:

  优点:①为序列和非序列类型提供了一种统一的取值方法;②惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。

  缺点:①除非取尽,否则无法获取迭代器的长度;②一次只能取一个值,如果取完了,需要重新调用迭代器才能够继续取值。

六、生成器

  本质就是迭代器;是自定义的迭代器

def func():
    print('第一次')
    yield 1         # yield 函数在运行时,遇到yield会停下来,
            #将yield后面的值当做本次的调用结果返回
print('第二次') yield 2 print('第三次') yield 3 print('第四次') yield 4 g=func() res = next(g) print(res)

yield作为表达式的用法:

def dog(y):
    print('狗狗%s准备吃东西了'%y)
    while True:
        x = yield  # yield 接收到的是send的过来的值,
            # 但是一开始的时候必须send(None)
print('狗狗%s吃了%s'%(y,x)) g = dog('小黑') g.send(None) g.send('包子') g.send('饼干') g.send('骨头')

七、三元表达式

语法格式: 条件成立返回的值 if 条件 else  条件不成立返回的值

列表生成式:l = [表达式 for i in 可迭代对象 if 条件]

原文地址:https://www.cnblogs.com/Holmes-98/p/14289989.html