Python 闭包

时间:2020-02-23 14:42:31  来源:igfitidea点击:

要了解python闭包,您应该具有嵌套函数和python类的想法。
实际上,python闭包也是一个提供了使用代码封装某些数据的机会的功能。

Python嵌套函数

def funcOut():
  print("Now we are in funcOut.")
  def funcIn():
      print("This function is defined inside the funcOut.\nThis one is called a nested Function.")
  print("Here we will call the funcIn that is defined.")
  funcIn()
print("We are in _main_.\nCalling the funcOut.")
funcOut()

在上面的代码中,funcIn是嵌套在funcOut中的函数。
如果您看上面代码的输出,那么您将了解函数的调用顺序。
输出将是:

We are in _main_.
Calling the funcOut.
Now we are in funcOut.
Here we will call the funcIn that is defined.
This function is defined inside the funcOut.
This one is called a nested Function.

将funcOut变成python闭包

假设您想拥有funcOut中的funcIn完成的所有功能。

你该怎么做?你在想什么?

返回值

通常,我们从函数返回值或者引用。
但是其中我们需要返回funcIn的全部功能。
如果我们仅用return funcIn覆盖第6行中调用funcIn()的函数,那么我们已经实现了我们想要的。

我们刚刚做的事情被称为python中的闭包。
在阅读整个教程时,您将更清楚地了解python闭包。

Python闭包的想法

因此,从以上内容我们了解到,当一个函数返回其中定义的另一个函数(即嵌套函数)时,称为闭包。
现在让我们看一下闭包的示例结构。

Python闭包结构

def closureFunc():
def nestedFunc():
   # ... statements ...
    print(" Welcome To Closure ")
return nestedFunc
get = closureFunc()
get()

这将输出:

Welcome To Closure

在上面的代码中,按照函数的名称,希望您理解外部函数是闭包函数,其中有一个嵌套函数,闭包函数将返回该函数。

Python闭包将代码嵌入代码

当我们创建一个类的对象时,该对象包含一些信息。
就像该闭包将数据嵌入代码中一样。

让我们用示例代码进行探索

def closureFunc(n):
  def nestedFunc():
      # ... statements ..
      print("Welcome To Closure ")
      print("You have sent argument %d + 10 = %d" % (n, n+10))
  return nestedFunc
getting = closureFunc(12)
getting()

这将输出:

Welcome To Closure 
You have sent argument 12 + 10 = 22

注意第7行和第8行– getting变量现在可以作为函数使用。
嵌套函数的内部函数的所有功能现在都由它完成。

Python Closure记住了它的上下文

看下面的代码,我们已经删除了closureFunc

def closureFunc(sum):
 def nestedFunc():
    # ... statements ..
     print("Welcome To Closure ")
     print("You have sent argument %s" % sum)
 return nestedFunc
getting = closureFunc(12)
del closureFunc
getting()

这将输出:

Welcome To Closure 
You have sent argument 12

这就是闭包的力量。
即使删除了闭包函数," getting"也会记住它的上下文以及它的作用。
这就是为什么即使删除实际函数也得到" getting"输出的原因。

在闭包中使用非局部变量

让我们来看另一个例子。
下面的闭包将所有数字加到一个特定范围内,这是闭包函数的参数。

def closureFunc(up):
 val = 0
 def nestedFunc():
     nonlocal val
     print("Welcome To Closure ")
     for i in range(up+1):
         val += i
     print("Total is =  %d" % val)
 return nestedFunc
getting = closureFunc(5)
getting()

这将输出:

Welcome To Closure 
Total is =  15

注意,我们在closureFunc中使用了一个变量val,并在nestedFunc中重用了它,并使用关键字nonlocal声明为该函数的非本地变量。

如果您未声明为非本地变量,则会在分配之前引用本地变量val的错误提示,这意味着它将被视为nestedFunc函数的局部变量。

带参数的闭包

让我们看一下本教程的最后一个示例。
在此代码中,我们想为nestedFunc提供参数。
并观察输出的不同值。

def closureFunc(up):
 val = 0
 def nestedFunc(arg):
     nonlocal val
     print("Welcome To Closure ")
     for i in range(up+1):
         val += i
     val *= arg
     print("Total is =  %d" % val)
 return nestedFunc
retFunc = closureFunc(5)
retFunc(10)
retFunc(4)

下图显示了以上python关闭程序的输出。

如果您能理解为什么第二个输出是660,那么我必须说您已经从本教程中学到了知识。

输出为660,因为在执行第11行时,设置了变量up = 5。

然后,当执行第12行时,执行" nestedFunc",并设置变量val = 150。

之后,当我们在第13行再次使用不同的参数4调用函数时,closureFunc的up = 5,val = 150。
因此,在for循环中,val将更新150,再加上1到5的总和,等于150 + 15 =165。
然后将其乘以4,等于660。
就是这样。
这就是python闭包。
希望本教程对您有所帮助。
最好的运气编码与闭包。

__closure__

所有函数对象都有一个__closure__元组属性,如果它是一个闭包函数,则返回单元格对象。

def closureFunc(up):
  val = 0

  def nestedFunc(arg):
      nonlocal val
      print("Welcome To Closure ")
      for i in range(up + 1):
          val += i
      val *= arg
      print("Total is =  %d" % val)

  return nestedFunc

retFunc = closureFunc(5)
print(retFunc.__closure__)
print(retFunc.__closure__[0].cell_contents)
print(retFunc.__closure__[1].cell_contents)

retFunc(10)
print(retFunc.__closure__)
print(retFunc.__closure__[0].cell_contents)
print(retFunc.__closure__[1].cell_contents)

retFunc(4)
print(retFunc.__closure__)
print(retFunc.__closure__[0].cell_contents)
print(retFunc.__closure__[1].cell_contents)

现在将产生以下输出,并且闭包上下文值up和val也将被打印。

(<cell at 0x10079f288: int object at 0x10028ba80>, <cell at 0x101033618: int object at 0x10028b9e0>)
5
0
Welcome To Closure 
Total is =  150
(<cell at 0x10079f288: int object at 0x10028ba80>, <cell at 0x101033618: int object at 0x10028cca0>)
5
150
Welcome To Closure 
Total is =  660
(<cell at 0x10079f288: int object at 0x10028ba80>, <cell at 0x101033618: int object at 0x1007eae70>)
5
660

Python闭包是一个很好的功能,但是如果我们有更多内部函数和参数,它将变得复杂。
您可以使用类和常规函数来实现相同的目的。
因此请谨慎使用python闭包。