Python嵌套函数和闭包

Posted

tags:

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

参考技术A 在Python语言中,可以在函数中定义函数。 这种在函数中嵌套定义的函数也叫内部函数。我们来看下面的代码:

上述代码中,定义了函数greet,在函数greet内部又定义了一个函数inner_func, 并调用该函数打印了一串字符。

我们可以看到,内部函数inner_func的定义和使用与普通函数基本相同。需要注意的是变量的作用域,在上述代码中,函数参数name对于全局函数greet是局部变量,对内部函数inner_func来说则是非局部变量。内部函数对于非局部变量的访问规则类似于标准的外部函数访问全局变量。

从这个例子我们还可以看到内部函数的一个作用,就是通过定义内部函数的方式将一些功能隐藏起来,防止外部直接调用。常见的场景是,在一个复杂逻辑的函数中,将一些小的任务定义成内部函数,然后由这个外层函数使用,这样可以使代码更为清晰,易于维护。这些内部函数只会在这个外层函数中使用,不能被其他函数或模块使用。

在Python语言中, 函数也是对象,它可以被创建、赋值给变量,或者作为函数的返回值。我们来看下面这个例子。

在上述代码中,在函数gen_greet内部定义了inner_func函数,并返回了一个inner_func函数对象。外部函数gen_greet返回了一个函数对象,所以像gen_greet这样的函数也叫工厂函数。

在内部函数inner_func中,使用了外部函数的传参greet_words(非局部变量),以及函数的参数name(局部变量),来打印一个字符串。

接下来,调用gen_greet("Hello")创建一个函数对象say_hello,紧接着调用say_hello("Mr. Zhang"),输出的结果为:Hello, Mr. Zhang!

同样的,调用gen_greet("Hi")创建一个函数对象say_hi,调用say_hello("Mr. Zhang"),输出的结果为:Hi,Tony!

我们可以发现,gen_greet返回的函数对象具有记忆功能,它能够把所需使用的非局部变量保存下来,用于后续被调用的时候使用。这种保存了非局部变量的函数对象被称作闭包(closure)。

那么闭包是如何实现的呢?其实并不复杂,函数对象中有一个属性__closure__,它就是在创建函数对象时用来保存这些非局部变量的。

__closure__属性是一个元组或者None类型。在上述代码中,我们可以通过下面方式查看:

函数的嵌套所实现的功能大都可以通过定义类的方式来实现,而且类是更加面向对象的代码编写方式。

嵌套函数的一个主要用途是实现函数的装饰器。我们看下面的代码:

在上述代码中,logger函数返回函数with_logging,with_logging则是打印了函数func的名称及传入的参数,然后调用func, 并将参数传递给func。其中的@wraps(func)语句用于复制函数func的名称、注释文档、参数列表等等,使得with_logging函数具有被装饰的函数func相同的属性。

代码中接下来用@logger对函数power_func进行修饰,它的作用等同于下面的代码:

可见,装饰器@符其实就是上述代码的精简写法。
通过了解了嵌套函数和闭包的工作原理,我们在使用过程中就能够更加得心应手了。

python之函数嵌套与闭包

一:函数的嵌套:在函数内部在定义一个函数,一层套一层

def father(name):
    print("from father %s" %name)
    def son():
       print("我的爸爸是%s" %name)
    son()
father("wangyue")

  

二:写一个装饰器的框架

写一个装饰器的框架,满足高阶函数,满足闭包嵌套
# def timer(func):
#     def wrapper():
#         print(func)
#         func()#本层没有func,只能从上层找,所以此时是执行的test这个函数
#     return wrapper

  

# def test():
#     print("执行完毕")
# res = timer(test)#返回的是wrapper的地址
# res()#执行的额是wrapper()

  

三:函数闭包加上返回值:

import time
def timer(func):
    def wrapper():
        start_time = time.time()
        res=func()#就是在运行test
        stop_time = time.time()
        print("运行时间是%s" %(stop_time-start_time))
        return res
    return wrapper

@timer #test = timer(test)
def test():
    print("执行完毕")
    return "ddd"
res = test()
print(res)

四:函数闭包加上参数:

就上个例子来说,加上name和age两个参数

#函数闭包加上参数
import time
def timer(func):
    def wrapper(name,age):
        start_time = time.time()
        res=func(name,age)#就是在运行test
        stop_time = time.time()
        print("运行时间是%s" %(stop_time-start_time))
        return res
    return wrapper

@timer #test = timer(test)
def test(name,age):
    print("执行完毕")
    return "ddd"
res = test("wanggyue",25)
print(res)#执行test就相当于执行timer的返回值

  

#函数闭包加上参数
import time
def timer(func):
    def wrapper(*args,**kwargs):#被修饰的函数参数是不固定的,所以不能写死参数,所以修该装饰器改为*args接受的元祖的格式,**kwargs接受的是字典的格式
        start_time = time.time()
        res=func(*args,**kwargs)#就是在运行test
        stop_time = time.time()
        print("运行时间是%s" %(stop_time-start_time))
        return res
    return wrapper

@timer #test = timer(test)
def test1(name,age):
    print("test函数执行完毕,名字是【%s】 年龄是【%s】" %(name,age))
    return "这是test的返回值"

@timer #相当于test = timer(test1)
def test1(name,age,gender):#被修饰的函数参数是不固定的,所以不能写死参数,所以修该装饰器
    print("test1函数执行完毕,名字是【%s】 年龄是【%s】 性别是【%s】" %(name,age,gender))
    return "这是test1的返回值"
test1("wangyue",25,"女")

 五:函数闭包之解压序列

#解压序列
l=[10,3,4,6,7,8,3,90,6,7,78]
#实现解压方式取开头和结尾的值
a,*_,c = l  #a代表第一个,*_所有中间,c是末尾
a,*_,c,d=l #取第一个值和倒数第一和第二个值
print(a)

python实现值的互换

#实现a,b值互换,正常写法
c=a
a=b
b=c
print(a)
print(b)
#另一种写法
f1=1
f2=2
f1,f2 = f2,f1
print(f1)
print(f2)

六:函数闭包为函数加上认证功能,联系京东商城每个模块加上用户名和密码验证功能

#为一下函数加上验证功能,写装饰器
def auth_func(func):
    def wrapper(*args,**kwargs):
        #此处输入验证功能
        username= input("用户名:".strip())
        password = input("密码:".strip())
        if username == "you"and password =="123":
           res = func(*args, **kwargs)
           print("返回值%s" %(res))
           return res
        else:
            print("输入错误")
    return wrapper
# 模拟京东商城后台
@auth_func
def index():
  print("欢迎来到京东主页")
  pass

@auth_func
def home(name):  # 京东的主页
    print("欢迎回家%s" %(name))

@auth_func
def shopping_car(name):  # 京东的购物车
    print("购物车里有[%s,%s]" %("奶茶","妹妹"))

# @auth_func
def order():  # 京东的订单
    pass


# 给每个模块加上一个验证功能
def yanzheng():
   pass

index()
home(‘产品经理‘)
shopping_car("产品经理")

七:函数闭包模拟session功能:

cirrentuserdic ={"username":None ,"login":False}
user_list = [{"username":"wangyue" ,"password":"123"},
             {"username":"songyang","password":"123"},
             {"username":"zhaozhen","password":"123"},
             {"username":"wangebiebi","password":"123"}]

#为一下函数加上验证功能,写装饰器
def auth_func(func):
    def wrapper(*args,**kwargs):
        #此处输入验证功能
        if cirrentuserdic["username"] and cirrentuserdic["login"]:
            res = func(*args, **kwargs)
            return res
        username1= input("用户名:".strip())
        password1 = input("密码:".strip())
        for userdic1 in  user_list:
            if username1==userdic1["username"] and password1==userdic1["password"]:
                cirrentuserdic["username"] = username1
                cirrentuserdic["login"] = True
                res = func(*args, **kwargs)
                return res
        else:
                print(‘用户名或者密码错误‘)
    return wrapper
# 模拟京东商城后台
@auth_func
def index():
  print("欢迎来到京东主页")
  pass

@auth_func
def home(name):  # 京东的主页
    print("欢迎回家%s" %(name))

@auth_func
def shopping_car(name):  # 京东的购物车
    print("购物车里有[%s,%s]" %("奶茶","妹妹"))


print(‘before-->‘,cirrentuserdic)
index()
print(‘after--->‘,cirrentuserdic)
home(‘产品经理‘)

接下来思考如何给装饰器加上参数(用的比较少)

cirrentuserdic ={"username":None ,"login":False}
user_list = [{"username":"wangyue" ,"password":"123"},
             {"username":"songyang","password":"123"},
             {"username":"zhaozhen","password":"123"},
             {"username":"wangebiebi","password":"123"}]

#接下来增加验证功能,加一个装饰器实现这个功能
def auth(auth_type=‘filedb‘):
  def auth_func(func):
    def wrapper(*argc,**kwargs):
        print("类型--",auth_type)
        if auth_type==‘filedb‘:
        #添加验证逻辑
            if cirrentuserdic["username"] and cirrentuserdic["login"]:
                res = func(*argc,**kwargs)
                return res
            username=input("用户名:".strip())
            password = input("密码:".strip())
            for user_dic in  user_list:
              if username==user_dic["username"] and password == user_dic["password"]:
                cirrentuserdic["username"]=username
                cirrentuserdic["login"] = True
                res = func(*argc, **kwargs)
                return res
            else:
                print("输入错误")
        elif auth_type==‘ldap‘:
            print("真会玩")

    return wrapper
  return auth_func

@auth(auth_type=‘filedb‘)#auth_func=auth(auth_type=‘filedb‘,auth_func附加了auth_type
def index():
    print("欢迎来到京东")
@auth(auth_type=‘ldap‘)
def home():
    print("欢迎进入京东主页")
@auth
def order():
    print("京东订单")

print("before--",cirrentuserdic)
index()
print("after--",cirrentuserdic)
home()

  

 

以上是关于Python嵌套函数和闭包的主要内容,如果未能解决你的问题,请参考以下文章

Python/函数的嵌套和闭包

python函数嵌套以及闭包的原理

013.Python之函数嵌套名称空间与作用域闭包函数

python初学之函数嵌套与闭包

python之函数嵌套与闭包

python函数之进阶 函数嵌套,命名空间,闭包