gpt4 book ai didi

python - 为什么我可以在函数中使用变量之前在 Python 中定义它?

转载 作者:太空宇宙 更新时间:2023-11-03 14:52:22 24 4
gpt4 key购买 nike

在下面的代码中,我定义了两个函数。 maincube .我要 main为了开始我的程序,所以我调用 cube内部 main :

>>> def main():
number = int(input('Enter a number: '))
cubed_number = cube(number)
print("The number cubed is: ", cubed_number)


>>> def cube(number):
return number * number * number

>>>

但我正在定义 cube之后 main ,所以我认为我的代码会引发 NameError .然而,Python 并没有引发异常,而是完美地执行了我的代码:
>>> main()
Enter a number: 5
The number cubed is: 125
>>>

发生了什么?为什么 Python 能够运行我的代码,但不知道如何运行 cube定义了吗?为什么不是 NameError提高?

更奇怪的是,当我尝试对类做同样的事情时,Python 确实引发了 NameError :
>>> class Main:
cubed_number()


Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
class Main:
File "<pyshell#27>", line 2, in Main
cubed_number()
NameError: name 'cubed_number' is not defined
>>>

这里发生了什么事?

注:这不是 Why can I call a function before defining it, with only a warning? 的副本,因为那里的答案并没有真正解释这种行为在 Python 中为什么或如何工作。我创建了这个问答是因为当前对此类问题的回答分散在各种问题中。我也觉得展示幕后正在发生的事情会有所帮助。随意编辑和改进问答。

最佳答案

要了解正在发生的事情,必须了解 Python 在定义函数和执行函数之间的区别。
定义与执行
当 Python 遇到函数定义时,它 编译 将函数转换为代码对象。
代码对象是 Python 用来保存与特定可执行代码块相关联的字节码的内部结构。它还包含 Python 执行字节码所需的其他信息,例如常量和局部变量名称。 documentation gives a much more more extensive overview of what code objects are .
然后使用代码对象来构造函数对象。然后,函数对象的代码对象用于在稍后调用函数时执行该函数。 Python 不会 执行 函数,它只会将函数编译成一个对象,以便稍后执行。 Python 执行函数的唯一时间是调用函数时 .
这是来自 the documentation which mentions this 的相关部分:

A function definition is an executable statement. Its execution binds the function name in the current local namespace to a function object (a wrapper around the executable code for the function). This function object contains a reference to the current global namespace as the global namespace to be used when the function is called.

The function definition does not execute the function body; this gets executed only when the function is called.


由于这种区别,在调用函数之前,Python 无法验证名称是否实际定义。因此,您可以在函数体中使用当前不存在的名称。只要在调用函数时定义了名称,Python 就不会引发错误。
这是一个例子。我们定义了一个函数 func将两个变量相加; ab :
>>> def func():
... return a + b
如您所见,Python 没有引发任何错误。这是因为它只是编译 func .它没有尝试执行该函数,所以它没有看到 ab没有定义。
我们可以拆机 func的代码对象,并使用 dis 查看字节码的样子模块。这将告诉我们更多关于 Python 正在做什么的信息:
>>> from dis import dis
>>> dis(func)
2 0 LOAD_GLOBAL 0 (a)
2 LOAD_GLOBAL 1 (b)
4 BINARY_ADD
6 RETURN_VALUE
Python 编码两个 LOAD_GLOBAL字节码中的指令。指令的参数是变量名 ab分别。
这表明 Python 确实看到我们在编译函数时试图引用两个变量,并为此创建了字节码指令。 但它不会尝试实际执行指令,直到函数被调用 .
让我们看看当我们尝试执行 func 的字节码时会发生什么通过调用它:
>>> func()
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
func()
File "<pyshell#14>", line 2, in func
return a + b
NameError: name 'a' is not defined
如您所见,Python 引发了 NameError .这是因为它试图执行两个 LOAD_GLOBAL说明,但发现在全局范围内未定义的名称。
现在让我们看看如果我们定义两个变量 a 会发生什么和 b调用前 func :
>>> a = 1
>>> b = 2
>>>
>>> func()
3
上述工作的原因是因为当 Python 正在执行时 func的字节码,它能够找到全局变量 ab ,并使用它们来执行函数。
这个例子同样适用于问题。当 main被编译,Python“看到”我们试图调用一个名为 cube 的变量并生成一条指令来获取 cube 的值.但它没有试图找到名为 cube 的可调用对象。直到指令被执行。到时候 main的字节码被执行(例如 main 被调用),一个名为 cube 的函数已定义,因此 Python 不会引发错误。
但是,如果我们尝试在定义多维数据集之前调用 main,由于与上述示例相同的原因,我们将收到名称错误:
>>> def main():
... number = int(input('Enter a number: '))
... cubed_number = cube(number)
... print("The number cubed is: ", cubed_number)
...
>>> main()
Enter a number: 23
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
main()
File "<pyshell#22>", line 3, in main
cubed_number = cube(number)
NameError: name 'cube' is not defined
类(class)呢?
Python 处理类定义与函数定义有点不同。
当 Python 遇到类定义时,它会为该类创建一个代码对象,就像函数一样。但是,Python 还允许类具有在类定义期间执行的命名空间。 Python 不会等待执行类命名空间,因为定义的任何变量都应该属于该类。因此,在类 namespace 内使用的任何名称都必须定义为在类定义期间使用。
documentation for class definitions touches on this :

The class’s suite is then executed in a new execution frame (see Naming and binding), using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly function definitions.) When the class’s suite finishes execution, its execution frame is discarded but its local namespace is saved.


但是,这不适用于方法。 Python 将方法中的未定义名称视为函数,并允许您在定义方法时使用它们:
>>> class Class:
... def method(self):
... return var
...
>>> var = 10
>>> cls = Class()
>>> cls.method()
10

关于python - 为什么我可以在函数中使用变量之前在 Python 中定义它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45042273/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com