首页 > 编程语言 >Python闭包概念入门

Python闭包概念入门

时间:2023-12-05 14:57:47浏览次数:29  
标签:闭包 输出 return 入门 Python print def 函数

'''
Python闭包概念入门
闭包(Closure)是 Python 中一个重要的工具。
闭包:高阶函数中,内层函数携带外层函数中的参数、变量及其环境,一同存在的状态(即使已经离开了创造它的外层函数),被称之为闭包。
被携带的外层变量称之为:自由变量,也被形容为:外层变量被闭包捕获了。
闭包中的自由变量有两个神奇的特性:
1. 第一个特性是,自由变量在闭包存在的期间,其中的值也会一直存在。因此闭包可以持有状态。
2. 另一个特性是,闭包与闭包之间的状态是隔离的。

闭包的几个特性:
它是一个嵌套函数
它可以访问外部作用域中的自由变量
它从外层函数返回
'''


# 在 Python 中,函数可以根据给定的参数返回一个值:
def hello(name):
return "hello " + name


print(hello("Bob"))

# 与 Python 的其他对象(如字符串、整数、列表等)一样,函数也是对象,也可以赋值给一个变量
h = hello
print(hello) # 输出: <function hello at 0x108e903a0>

print(h) # 输出: <function hello at 0x108e903a0>

# 可以看到 hello 和 h 都指向同一个函数,而函数后加括号 h('Jack') 是对其进行了调用。
print(h('jack')) # 输出: hello jack

''' 1.函数里的函数 '''


def hi():
def bob():
return 'Bob'

print('Hi ' + bob())


# 输出: Hi Bob
hi()
# 此时的 bob 函数的作用域在 hi 之内的。如果在全局调用 bob() 会引发错误:
# bob()


'''
2.函数作为返回值
函数可以作为返回值,也可以内部定义。这种在函数里传递、嵌套、返回其他函数的情况,称之为高阶函数。
函数还可以作为其他函数的参数。
闭包:高阶函数中,内层函数携带外层函数中的参数、变量及其环境,一同存在的状态(即使已经离开了创造它的外层函数),被称之为闭包。
被携带的外层变量称之为:自由变量,也被形容为:外层变量被闭包捕获了。
'''


def cook():
def tomato():
print('I am Tomato')

return tomato


t = cook()
t() # 输出: I am Tomato

'''
3. 闭包与自由变量:
通常来说,函数中的变量为局部变量,一但函数执行完毕,其中的变量就不可用了:

'''


def cook():
food = 'apple'


cook()
# print(food) # 输出报错:NameError: name 'food' is not defined


'''
同样的情况到了高阶函数这里,就有点不对劲了:
cook() 函数执行之后,按道理来说 food 变量就应该被销毁掉了。但实际上没有任何报错, value() 顺利的输出了 food 的值。
甚至于,即使将 cook() 函数销毁了,food 的值都还存在:

'''


def cook():
food = 'apple'

def wrapper():
print(food)

return wrapper


value = cook()
value() # 输出:apple

# 删除原函数
del cook

value() # 输出:apple

'''
4. 参数捕获:
很多时候,我们希望闭包所捕获的自由变量可以根据不同的情况有所区分。
很简单,把它作为外层函数的参数就可以了:
'''


def cook(name):
def wrapper():
print('I am cooking ' + name)

return wrapper


apple = cook('apple')
pear = cook('pear')
# 外层函数的参数也可以成为自由变量,被封装到内层函数所在的环境中
# 这种局部变量起作用的特定环境,有时候被称为作用域或者域。
apple() # 输出: I am cooking apple
pear() # 输出: I am cooking pear

'''
5. 函数生成:
既然外层函数可以携带参数,那被返回的内层函数当然也可以带参数:

'''


def outer(x):
def inner(y):
print(x + y)

return inner


# 看到两个括号就代表进行了两次函数调用。第一个括号对应 outer 的参数 x ,第二个括号里对应 inner 的参数 y。
outer(1)(2) # 输出: 3


# 利用闭包携带参数并返回函数的这个特性,可以很方便的在一个底层的函数框架上,组装出不同的功能
# 外层函数传递的参数甚至可以是个函数。
def add(x):
def inner(y):
print(x + y)

return inner


add_one = add(1)
add_ten = add(10)

add_one(5) # 输出: 6
add_ten(5) # 输出: 15

'''
6. 状态持有:
闭包中的自由变量有两个神奇的特性:
第一个特性是,自由变量在闭包存在的期间,其中的值也会一直存在。因此闭包可以持有状态。
另一个特性是,闭包与闭包之间的状态是隔离的。

以上两个特性,使得闭包像一个微型的类,因为状态持有和数据隐藏是类的基本功能。
它两在使用上的建议是:如果你的状态比较简单,那么可以用闭包来实现;相反则使用类。
'''


# 记录每次取得的分数- score 闭包打印的列表记录了每次调用的结果。
def make_score():
lis = []

def inner(x):
lis.append(x)
print(lis)

return inner


score = make_score()
score(60) # 输出:[60]
score(77) # 输出:[60, 77]
score(88) # 输出:[60, 77, 88]


# 另一个特性是,闭包与闭包之间的状态是隔离的。
def make_score():
lis = []

def inner(x):
lis.append(x)
print(lis)

return inner


first = make_score()
second = make_score()

first(1) # 输出:[1]
first(2) # 输出:[1, 2]

second(3) # 输出:[3]
second(4) # 输出:[3, 4]

'''
7. 不变量状态:
在上面的例子里,闭包用 lis.append() 直接操作了自由变量。
但如果要操作的自由变量是个不变量,比如数值型、字符串等,那么记得加 nonlocal 关键字:
此关键字就是在告诉解释器:接下来的 total 不是本函数里的局部变量,你最好去闭包或是别的地方找找。

'''


# 记录成绩总分
def make_score():
total = 10

def inner(x):
nonlocal total
total += x
print(total)

return inner


total = make_score()
total(5) # 输出:15

'''
8. 延迟陷阱:
闭包相关的常见陷阱
inner 是延迟执行的,直到真正调用前,都是没进行内部操作的。
'''
funcs = []
for i in range(3):
def inner():
print(i)
funcs.append(inner)

# print(f'i is: {i}')
funcs[0]() # 输出:2
funcs[1]() # 输出:2
funcs[2]() # 输出:2


# 解决方案就是用闭包将 i 的值立即捕获:
funcs = []
for i in range(3):
def outer(a):
def inner():
print(a)
return inner
funcs.append(outer(i))

print(f'i is: {i}')
funcs[0]() # 输出:0
funcs[1]() # 输出:1
funcs[2]() # 输出:2




"""
9. 组合函数:
用闭包实现函数的拼接
"""
def compose(g, f):
def inner(*args, **kwargs):
return g(f(*args, **kwargs))
return inner

# 被拼接函数1
def remove_lase(lis):
return lis[1:]

# 被拼接函数2
def remove_last(lis):
return lis[:-1]

# 进行函数合成
remove_last_remove_last = compose(remove_last, remove_lase)
new_list = remove_last_remove_last([1, 2, 3, 4, 5])
print(new_list) # 输出:[2, 3, 4]


"""
10. 柯里化
柯里化是闭包的一种应用,它将一个多参数的函数转换成一系列单参数函数。

"""
# 柯里化闭包函数
def curry(f):
argc = f.__code__.co_argcount
f_args = []
f_kwargs = {}
def g(*args, **kwargs):
nonlocal f_args, f_kwargs
f_args += args
f_kwargs.update(kwargs)
if len(f_args) + len(f_kwargs) == argc:
return f(*f_args, **f_kwargs)
else:
return g
return g

# 无关紧要的原函数
def add(a, b, c):
return a + b + c

# c_add 是被柯里化的新函数
c_add = curry(add)




标签:闭包,输出,return,入门,Python,print,def,函数
From: https://www.cnblogs.com/xiao-bai-long/p/17877181.html

相关文章

  • fileinput:一个txt文件的Python库
    文件处理和输入流时,Python中的fileinput模块是一个非常有用的工具。fileinput模块允许迭代处理多个文件,同时还可以处理标准输入流。以下是Python中fileinput模块的五个常见用法。1.逐行迭代文件fileinput模块可以用于逐行迭代处理文件中的内容。importfileinputforlinei......
  • python在word文件指定的文字下划线
    #coding:utf-8importosfromwin32com.clientimportDispatchdefget_string_index(substring,string):"""获取同一字符串中的多个相同字符串的起始索引:paramsubstring:需查找的字符串:paramstring:被查找的字符串:return:"""in......
  • python第二天
    0.以下哪个变量的命名不正确?为什么?  (A)MM_520  (B)_MM520_  (C)520_MM  (D)_520_MMC,数字不能在首位1.在不上机的情况下,以下代码你能猜到屏幕会打印什么内容吗?>>>myteacher='小甲鱼'>>>yourteacher=myteacher>>>yourteacher='黑夜'>>>print(mytea......
  • 实例讲解Python 解析JSON实现主机管理
    本文分享自华为云社区《Python解析JSON实现主机管理》,作者:LyShark。JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式,它以易于阅读和编写的文本形式表示数据。JSON是一种独立于编程语言的数据格式,因此在不同的编程语言中都有对应的解析器和生成器。JSON格式的设计......
  • 【Python/数据库】SQLAlchemy基础操作
    一、SQLAlchemy——创建表#ORM#1.Class-Obj#2.创建数据库引擎#3.将所有的Class序列化为数据表#4.ORM操作-CRUD(增删改查操作的简称)1.创建一个class#create_table.pyfromsqlalchemy.ext.declarativeimportdeclarative_baseBase=declarative_base......
  • 【Python/数据库】SQLAlchemy一对多,多对多操作
    SQLAlchemy一对多操作1.创建多表#create_table_ForeginKey.pyfromsqlalchemy.ext.declarativeimportdeclarative_basefromsalalchemyimportColumn,INT,VARCHAR,ForeignKeyfromsqlalchemyimportcreate_engineBase=declarative_base()classStudent(Base)......
  • PWN学习之LLVM入门
    一、基本流程①找到runOnFunction函数时如何重写的,一般来说runOnFunction都会在函数表最下面,找PASS注册的名称,一般会在README文件中给出,若是没有给出,可通过对__cxa_atexit函数"交叉引用"来定位:②通过逆向,找到函数名及参数,编写基本exp③找到漏洞,写利用exp.c,其中的pwn的目标是op......
  • python练习
    1将数字汉字符号一起打印2大小写转换首字母大写3使用数学函数4注释5对字符串求长度6通过索引获取单个字符7布尔类型8空值类型9查找所属类型type10列表将数字汉字符号一起打印name="璃月"date="12月5号"message=f'{name}您好,今天是:{date}'print(message)或者可以......
  • 使用Python发送HTTP请求的最佳实践:让你的代码锐利如刀!
    在当今的数字化时代,使用Python发送HTTP请求已经成为了许多开发人员的日常任务。无论是进行API交互、网页爬取,还是构建网络服务,掌握Python的HTTP请求技巧都至关重要。但是,要想在竞争激烈的编程领域中脱颖而出,你需要掌握一些最佳实践,让你的代码锐利如刀!安装必要的库首先,确保你已经安......
  • python文件不显示cmd黑窗口,打包py,pyw文件为exe文件
    问题描述:编写的python文件为定时任务,需要长时间运行,但是打开的cmd黑色窗口看起来很不舒服,于是打包为exe文件,隐藏cmd黑色窗口步骤:1.使用pipinstallpyinstaller命令安装pyinstaller(前提是已安装python);2.很多时候出现pip版本过老的报错,此时使用pip--version查看pip版本,确定......