首页 > 其他 > 详细

Pyton中的作用域、闭包、装饰器

时间:2020-06-11 23:54:42      阅读:65      评论:0      收藏:0      [点我收藏+]

Python的4种作用域

  • L (Local) 局部作用域
  • E (Enclosing) 闭包函数外的函数中
  • G (Global) 全局作用域
  • B (Built-in) 内建作用域,python自带的内置变量

  查找顺序:L –> E –> G –>B ,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,最后去内建中找

 

Python中变量作用域的改变

  • 定义函数内部的变量再函数外部无法访问
  • 定义条件分支、异常代码块、循环语句内部定义的变量,在外部可以访
# 作用域代码示例
if True:
    """ 使用if条件分支语句定义的变量在外部也可以访问"""
    num = 9
    print("num=%d" % num)   # 全局变量:num=9

print(num)  # 9

def func_method1():
    """
    函数内定义的变量(局部变量),外部无法访问
    :return:
    """
    num = 5
    print(num)

print(num)  # 9

 

Python的函数高级引用

  • 函数名可作为参数传递
  • 函数名可以赋值给其他变量
  • 函数名可以作为返回值
# 高阶函数代码示例
import random

def fun_method1():
    """
    获取0~100的任意随机数字
    :return:
    """
    return random.randint(0, 100)

def fun_method2():
    """
    将函数名当做返回值
    :return:
    """
    def func_method3():
        """
        获取1.5~9.9之间的任意小数,round保留两位小数
        :return:
        """
        return round(random.uniform(1.5,9.9),2)
    return func_method3

if __name__ == "__main__":
    # 函数名赋值给变量,就可以通过变量名来调用函数
    var = fun_method1
    print(var())

    # 将函数名当做返回值:var1() => func_method3()
    var1 = fun_method2()
    print(var1())

 

Python中的闭包

  • 定义:如果在一个内部函数里,对在外部函数内(但不是在全局作用域)的变量进行引用 , 那么内部函数就被认为是闭包
  • 作用:闭包(延长了局部变量的生命周期),函数运行完之后,函数内的变量就会被销毁
def func_decorator1():
    # num变量一般会在当前函数执行后被回收
    num = 500

    def func_num():
        """
        闭包:函数内部定义函数,引用非当前函数的外部变量(非全局变量)
        :return:
        """
        print(num)

    return func_num

if __name__ == "__main__":
    var_func = func_decorator1()   # func_decorator1函数执行完,局部变量就会一般会被回收掉
    var_func()  # 500;注:var_func() => func_num(),闭包函数还是可以访问已调用结束的函数局部变量

 

Python中的装饰器

  • 装饰器本质上也是一个函数, , 装饰器函数用来修饰其他函数, ,在不改变原函数代码的情况下为函数增加功能而无需修改调用方式
  • 装饰器经常用于切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景
  • 实现方式:在被修饰的函数头上添加“@装饰函数名(参数..)”

 

  现有问题:已经存在一个功能强大且没有bug的方法,但是添加了新的需求,需要保留该方法原有的功能,而且还要在该方法上增加新的功能

  解决方法:①.直接在该方法上添加新的代码实现功能(缺点:可能会给这个测试通过的方法带来新的bug)

       ②.丢弃该方法,重写一个方法(缺点:会造成太多的重复代码,而且之前调用过该方法的地方都要修改)

       ③.写一个新的方法,然后调用该方法(缺点:之前调用该方法的地方没有你新添加的功能,如果需要你新增加的功能,也需要挨个改调用方法的方法名)

          ④.使用装饰器,在不改变原函数代码的情况下为函数增加功能而无需修改调用方式(强烈建议)

# 模拟装饰器代码示例
def func_one():
    """
    已有的一个功能强大的函数
    :return:
    """
    print("func_one method...")

def func_two(func):
    """
    另一个功能强大的函数,需要包含第一个强大函数的功能
    :return:
    """
    print("func_two method... *A*")

    def func_three():
        print("func_two method... *B*")
        func()
        print("func_two method... *C*")

    print("func_two method... *D*")
    return func_three

if __name__ == "__main__":
    # 调用方式:myFunc变量接收的类型是函数名func_three,即:myFunc() => func_three()调用myFunc函数,其实是调用了func_three函数
    myFunc = func_two(func_one)
    myFunc()
调用结果:
  func_two method... *A*
  func_two method... *D*
  func_two method... *B*
  func_one method...
  func_two method... *C*


无参装饰器

# Python中的无参装饰器代码示例
def func_two(func):
    """
    装饰函数:接收一个被装饰的函数作为参数
    :return:
    """
    print("func_two method... *A*")

    def func_three():
        print("func_two method... *B*")
        func()
        print("func_two method... *C*")

    print("func_two method... *D*")
    return func_three

@func_two
def func_one():
    """
    被装饰函数:已有的一个功能强大的函数
    :return:
    """
    print("func_one method...")

if __name__ == "__main__":
    # 调用方式:使用Python的装饰器,简化调用函数,func_one() => func_two(func_one),先实行装饰函数里面的代码,然后再次执行被装饰函数的方法
    func_one()
调用结果:
  func_two method... *A*
  func_two method... *D*
  func_two method... *B*
  func_one method...
  func_two method... *C*

有参装饰器(被装饰函数有参数)
# 装饰函数有参数代码示例
def func_two(func):
    """
    装饰函数:接收一个被装饰的函数作为参数
    :return:
    """
    print("func_two method... *A*")

    def func_three(name):
        """
        内部函数其实等同于被修饰的函数,被修饰的函数有参数,只需要在内部参数添加参数即可
        :return:
        """
        print("func_two method... *B*")
        func(name)
        print("func_two method... *C*")

    print("func_two method... *D*")
    return func_three


@func_two
def func_one(name):
    """
    被装饰函数有参数:已有的一个功能强大的函数
    :return:
    """
    print(f"func_one method...,My name is {name}")


if __name__ == "__main__":
    # 调用方式:使用Python的装饰器,简化调用函数,func_one() => func_two(func_one),先执行装饰函数里面的代码,然后再次执行被装饰函数的方法
    func_one("Tom")
调用结果:
  func_two method... *A*
  func_two method... *D*
  func_two method... *B*
  func_one method...,My name is Tom
  func_two method... *C*

有参装饰器(装饰函数有参数)
# 装饰函数有参数代码示例
def func_four(param):
    """
    嵌套装饰函数:用来为装饰器函数传递参数
    :param param: 装饰器需要的参数
    :return: func_two
    """
    def func_two(func):
        """
        装饰函数:接收一个功能强大的函数,需要有参数时,可以一层一层往上返回
        :return: func_three
        """
        print("func_two method... *A*")

        def func_three(name):
            """
            内部函数其实等同于被修饰的函数,被修饰的函数有参数,只需要在内部参数添加参数即可
            :param name: 被装饰函数需要的参数
            :return:
            """
            print("func_two method... *B*")
            func(name)
            print("func_two method... *C*")

        print("func_two method... *D*")
        print(f"装饰函数需要有参数:{param}")
        return func_three

    return func_two

@func_four(param="Hello")
def func_one(name):
    """
    被装饰函数有参数:已有的一个功能强大的函数
    :return:
    """
    print(f"func_one method...,My name is {name}")


if __name__ == "__main__":
    # 调用方式:使用Python的装饰器,简化调用函数,func_one() => func_two(func_one)
    #           先执行装饰函数里面的代码,然后再次执行被装饰函数的方法
    func_one("Tom")
调用结果:
func_two method... *A* func_two method... *D* 装饰函数需要有参数:Hello func_two method... *B* func_one method...,My name is Tom func_two method... *C*

Pyton中的作用域、闭包、装饰器

原文:https://www.cnblogs.com/jason2018524/p/13096641.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!