“绑定对象”和“绑定对象”之间的区别

2024-04-23 23:36:13 发布

您现在位置:Python中文网/ 问答频道 /正文

当我研究Python中的“命名和绑定”时,我看到了以下示例:

>>> def testClosure(maxIndex):
        def closureTest(maxIndex=maxIndex):
            return maxIndex
        maxIndex += 5
        return closureTest()
>>> print(testClosure(10))
10


>>> def testClosure(maxIndex):
        def closureTest():
            return maxIndex
       maxIndex += 5
       return closureTest()
>>> print(testClosure(10))
15

笔者解释为: 在后一个函数中,内部范围中的自由变量绑定到外部范围中的变量,而不是对象。在

我的问题是:Python中的“绑定到变量”和“绑定到对象”有什么区别?在

而且,它非常棘手:结果如果我重新排列代码就不同了。在

^{pr2}$

提前谢谢。在


Tags: 对象函数代码示例returndef命名print
3条回答

如果您想一想在'def'语句的参数表达式中发生的绑定,可能就不那么容易混淆了。当您看到“def closureTest(maxIndex=maxIndex):”这是一个类似“if”或“while”的语句,后面跟着一组要解析并绑定到函数(可调用对象)的代码。在

“def”语句在找到它的范围内求值(概念上处于相同的嵌套/缩进级别)。它的参数表达式声明如何将参数映射到函数自身作用域内的名称。提供默认值的任何一个函数对象(例如示例中的maxIndex)都会创建一个函数对象,并将相应的参数名绑定到“def”语句时(在范围内)命名或实例化的任何对象。在

调用函数时,它的每个参数(其范围内的名称)都绑定到提供给函数的任何参数。因此,任何可选参数都将与作为“def”语句一部分计算的参数保持绑定。在

在所有的例子中,内部函数都是在每次调用外部函数时创建的。在第二个示例中,参数列表为空,内部函数只是通过一个嵌套范围级别查看名称。在第一个示例中,内部函数的def语句在新函数的名称空间内创建一个默认的maxIndex name(这样就可以防止使用来自周围范围的值对名称进行任何解析,正如您对任何函数中的任何局部变量所期望的那样)。在

在最后一个例子中,maxIndex的值在内部函数被(重新)定义之前被修改。当您意识到在每个外部函数调用上都(重新)定义了函数,那么它看起来就不那么棘手了。在

Python是一种动态语言你的代码流的每一次都是由你的代码行执行的。(是的,代码是字节编译的,但是'def'被编译成vmop代码,在运行时执行代码计算和名称绑定(到函数的名称)。在

如果您定义了一个带有参数列表的函数,比如'(myList=list())',那么在执行定义时,将实例化一个列表。无论何时在没有参数的情况下调用函数时,都可以从函数代码的调用中访问它。任何带有参数的调用都将在该参数名绑定到调用时提供的参数的情况下执行。(def时实例化的对象仍由def语句后缩进的suite定义的code对象引用)。在

如果不保持参数和参数之间的区别,这些都没有任何意义。请记住,参数是函数定义的一部分;它们定义了如何将参数映射到函数的本地命名空间中。参数是调用的一部分;它们是传递到任何函数调用中的东西。在

我希望这有帮助。我意识到两者之间的区别是微妙的,而且这些术语经常被误用,好像它们是可以互换的(包括整个Python文档)。在

>>> def testClosure(maxIndex):
        def closureTest(maxIndex=maxIndex): # You're creating a function with a kwarg of maxIndex
            return maxIndex                 # which references the int passed in from outside
        maxIndex += 5                       # Incrementing maxIndex means that the maxIndex in the outer
        return closureTest()                # scope now points to a different int.
>>> print(testClosure(10))
10

考虑:

^{pr2}$

我不知道你说的“绑定到对象”和“绑定到变量”是什么意思变量“是对事物的引用,当你增加a时,你正在修改它以引用一个不同的值,b仍然引用原始值。在

如果不将maxIndex的值传递到内部函数中,然后请求它,因为它没有在本地范围内定义,而是在扩展范围中查找它。在

我在这里做了一个非常大的假设,但是您可以看到执行时间的不同,我倾向于将其归因于扩展查找的成本:

>>> import timeit
>>> def testClosure(maxIndex):
...     def closureTest(maxIndex=maxIndex):
...         return maxIndex
...     maxIndex += 5
...     return closureTest()
...
>>> def testClosure2(maxIndex):
...     def closureTest():
...         return maxIndex
...     maxIndex += 5
...     return closureTest()
...
>>> timeit.Timer('testClosure(10)','from __main__ import testClosure').timeit()
1.4626929759979248
>>> timeit.Timer('testClosure2(10)','from __main__ import testClosure2').timeit()
1.7869210243225098

两个关键事实:

  1. Python使用the LEGB rule查找 (裸)变量名的值。 LEGB代表本地,扩展, 全球,内置。这意味着 变量名“绑定”到本地 值,如果没有,则 该值在 扩展范围,如果没有 这样的变量,查找是在 全局范围,最后在 内置范围。在
  2. 当定义一个函数时

    def closureTest(maxIndex=maxIndex):
        return maxIndex
    

    默认值固定在 definition-time,而不是{}。我所说的definition-time是指函数定义时处理def语句的时间。我所说的run-time是指函数被调用的时间。注意,当有嵌套函数时,内部函数的definition-time发生在外部函数被调用之后。


第一个例子由于变量名maxIndex被过度使用而变得更加复杂。如果你首先理解了这一点,你就会理解第一个例子:

^{pr2}$
  • (1) 在定义时间,索引 默认值设置为10。在
  • (2) 调用closureTest()时 如果没有参数,index被设置为 默认值为10。所以这是 返回值。在

def testClosure(maxIndex):
    def closureTest():
        return maxIndex                 # (3)
   maxIndex += 5
   return closureTest()                 # (4)
print(testClosure(10))
  • (3)LEGB规则告诉Python 在中查找maxIndex的值 局部范围。没有maxIndex 在局部范围内定义,因此 在扩展范围内查找。它发现 作为参数的maxIndextestClosure

  • (4)到closureTest()是 调用时,maxIndex的值为15。 因此maxIndex返回 closureTest()是15。


>>> def testClosure(maxIndex):
        maxIndex += 5                           # (5)    
        def closureTest(maxIndex=maxIndex):     # (6)
            return maxIndex
        return closureTest()                    # (7)
  • (5)maxIndex为15

  • (6)closureTest的maxIndex已设置 默认值为15 定义时间。

  • (7)调用closureTest()时 没有参数时,默认值 for maxIndex被使用。值15 返回。

相关问题 更多 >