python 函数进阶

Posted fqh202

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 函数进阶相关的知识,希望对你有一定的参考价值。

函数进阶


命名空间

  • namespace, 顾名思义, 就是存放名字的地方.举例:若声明变量 x = 1, 值1存放与内存中, 那变量名x 就存放在命名空间里. 命名空间是存放x 和 1 绑定关系的地方.

  • 名称空间共3种,分别如下:
  • locals: 当前所在的函数内的名称空间,包括局部变量和形参
  • globals: 全局变量,函数定义所在模块最外层的名字空间
  • builtins: 内置模块的名字空间

  • 作用域范围
  • 全局范围:全局存活,全局有效
  • 局部范围:临时存活,局部有效

  • LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> builtins
    • locals 是函数内的名字空间,包括局部变量和形参
    • enclosing 外部嵌套函数的名字空间
    • globals 全局变量,函数定义所在模块的名字空间
    • builtins 内置模块的名字空间

闭包

  • 初步理解: 函数定义和函数表达式位于另外一个函数体内(嵌套函数),外部函数返回的是内部函数的函数名,而且内部 函数可以直接访问他们所在的外部函数中声明的所有局部变量、参数, 当这样的一个内部函数在包含他们的外部函数之外被调用的时候,就会形成闭包。

  • 定义: 返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,除了函数内部定义的局部变量,其次就是使用自己外层包裹的作用域,

def outer():
    name = ‘jack‘
    def inner():
        print("在inner里打印外层函数的变量", name)

    return inner

f = outer()   # outer函数执行后等价于 f == inner
f()  # inner()

装饰器

  • 作用: 在不改变现有函数的代码的情况下,进一步增强函数的功能
  • 前提条件: 能形成闭包, 函数作为参数传入上级函数的命名空间,供内部函数返回掉调用
使用装饰器版本
  • 简单实例:
def f1(func):
    def inner():
        return func(n)
    return inner

@f1
def f2(x):
    print(x)

f2()

过程详细解析
  1. 给函数f2加上装饰器f2可以理解为f = f1(f2)这个过程,此时先执行等式右边内容,f2函数作为参数被传入外部函数的命名空间,存储起来;
  2. f1返回inner, 等价于f = inner;
  3. 这就形成了闭包,在inner函数外部函数f1的外部调用f()这个函数,就同时于调用了内部函数inner()
  4. 此时inner结果返回之前传入的参数函数(),即f2()
  5. 此时inner函数就会向外部函数的命名空间查询变量或参数,找到之前传入的f2函数参数
  6. 由于之前传入的函数名就是外部函数f2(),所以直接会调用外部函数f2()
  7. 最后,函数名修改后并不会影响函数内部代码执行,所以直接将f 改为 f2, 那么就是实现了装饰器功能, 在不改变f2代码的同时,在启动前会运行f1(),此时生成中间函数明变量,函数名如果是f2的话,那么在后续调用f2()的时候同时也就启动了函数f2()。

实例2:给代码加认证函数

USERNAME = ‘lynnfang‘
PASSWORD = ‘abc‘
lock_status = 0
login_status = 0

def login(func, *args):
    def inner(*args, **kwargs):
        global lock_status, login_status
        
        if lock_status == 1:
            print(‘您的账户已被锁定!‘)
            
        else:
            if login_status == 0:
                n = 0
                while n < 3:
                    username = input(‘>>> 用户名: ‘)
                    password = input(">>> 密码: ")
                    if username == USERNAME and password == PASSWORD:
                        n = 3
                        login_status = 1
                        return func()
                    else:
                            n += 1
                else:
                    lock_status = 1

            else:
                return func()
                
    return inner

@login
def china():
    print(‘----中国专区----‘)

@login
def japan():
    print(‘----日本专区----‘)

china()
japan()

代码解析
  1. 在不改变已写好china()和japan()函数代码的前提下,对其加用户认证,只有认证通过才能调用函数内部表达式
  2. 首先将执行代码脚本,python检测到 @ 符号,将会将对应的函数名称作为参数传入login()函数的命名空间
  3. f1 = inner, f2 = inner
  4. 由于无形的中间函数可以赋值为之前传入的函数名,所以当调用这个函数名时候等同于外部调用inner
  5. 进入inner函数后,声明全局变量后,就可以在嵌套函数内部修改全局变量值,同时,在嵌套函数内部也会将全局变量值作为逻辑语句的判断条件,但最后肯定会返回之前传入的函数调用()
  6. 进入login()函数的命名空间查找对应的函数参数,由于函数参数就是之前传入的外部函数,所以也就调用了外部函数,顺利进入外部执行函数内部
  7. 只要不退出程序,下一次进入login函数就会参考之前的全局变量来判断执行了,所以只要一次登录,以后就不需要重复登录了

生成器(generator)

  • 特点: 生成器不会把结果保存在一个系列中,而是保持生成器的状态,在每次进行迭代时返回一个值,直到遇到StopIteration异常结束。

  • 生成器表达式: 通列表解析语法,只不过把列表解析的[ ]换成( )

  • 与列表解析的差异:生成器表达式能做的事情列表解析基本都能处理,只不过在需要处理的序列比较大时,列表解析比较费内存。

  • 典型生成器 g = (i for i in range(1000),g就是生成器,next(g)就可以迭代出内部的值,直到清空整个生成器

  • range()在底层就是用生成器实现的, 在Python2里,range(10)生产的就是列表,所以要用xrange(10),比较节约空间,python3优化了range(),结果是类生成器, range(121212121212212)‘在python shell下可以马上生成,但是list(range(121212121212121212))`可能会很慢甚至直接出现内存错误,因为列表需要将所有的值都读进内存,但是内存分配给列表的标准内存是有限的空间,所以会出现内存错误,此时生成器的有点就显现出来了

  • 生成器是一次性的,迭代完成会出现StopIteration错误


yield理解

  • yield的作用类似与return;
  • 当python识别到next()函数,就会开始进入函数内部执行,直到遇到yield关键字,然后向外部返回yield对应的值;
  • 之后的每次调用都会从yield关键字开始向后执行代码,随后从函数头向下执行直到遇到yield返回值后就停止等待,直到遇到下一个next();
  • g.send(’a‘)可以将’a‘赋值给yield

  • 生成器实现range( )函数
def range2(end):
    count = 0
    while count < end:
        n = yield count
        count += 1

g = range2(10)
print(next(g))
print(next(g))
print(next(g))
g.send(‘stop‘)
  • 将函数变成生成器,制作fabnacci序列生成器
def fab(max_num):
    n, a, b = 0, 0, 1
    while n < max_num:
        yield b  # 把函数执行过程冻结在这一步,并把b的值返回给外面的next(函数)
        a, b = b, a+b
        n += 1

g = fab(20)
print(g)

迭代器

  • 可迭代对象(iterable):凡是可以用for循环的对象都是可迭代对象, 常见的数据集合list, tuple, set, dict, str都是可迭代对象

  • 迭代器(iterator):
  • 可以被next()调用并不断返回下一个值的对象就是迭代器;
  • 表示的是一个数据流,一个有序序列
  • 惰性,只有在需要返回下一个数据时才会计算
  • 无法预知大小,没有len()这个方法

  • 可迭代对象可以转换成迭代器, 直接调用iter()函数

  • 判断可迭代对象: isinstance(11, Iterable)

  • 判断是否是迭代器: isinstance((i for i in range(10)), Iterator)


以上是关于python 函数进阶的主要内容,如果未能解决你的问题,请参考以下文章

python--函数进阶

Python进阶内容--- 函数式编程

Python进阶学习——函数式编程

python进阶-- 01 函数式编程

Python进阶-函数式编程

python 基础篇 12 装饰器进阶