此脚本在
main()
内部定义了一个变量,但该变量不可用于在 func()
内部运行的 main()
。这是为什么?
#!/usr/bin/env python3
# vars_in_func.py
# Test script for variables within a function.
def func():
print(greeting)
def main():
greeting = "Hello world"
func()
main()
错误:
Traceback (most recent call last):
File "./vars_in_func.py", line 11, in <module>
main()
File "./vars_in_func.py", line 9, in main
func()
File "./vars_in_func.py", line 5, in func
print(greeting)
NameError: name 'greeting' is not defined
如果我将脚本转换为 Python2,错误是相同的,只不过它显示的是
global name
而不是 name
。
我想我只是错过了一个关键概念。我在学习 Bash 后才开始学习 Python。
编辑:阅读完答案后,我意识到我的错误:我仍在思考 Bash,其中函数要么在与调用者相同的 shell 中运行(具有相同的变量),要么在调用者的子 shell 中运行(继承变量)。
greeting = None
def func():
print(greeting)
def main():
global greeting
greeting = "Hello world"
func()
main()
在您的解决方案中,主函数中定义的greeting是局部变量,无法在主函数之外访问。这就是它给你错误的原因
我对Python了解不多,但一般来说,全局变量需要在main范围之外定义,但要在要使用它们的函数之前定义。如果你不想使变量成为全局变量,则需要传递变量作为参数传入函数。
关于 python 作用域规则有很多答案,这在这里确实很重要。但正如我看到你的问题,你的误解在于完全不同的东西:定义函数和调用它之间存在巨大差异。
LEGB 规则很重要,但真正重要的是 “虽然范围是静态确定的,但它们是动态使用的”。粗略地说,函数知道在哪里寻找变量(编译时),但它不知道变量值(在调用函数之前)。
在您的情况下,您只需将一个函数调用到另一个函数的主体中即可。当您调用函数时,调用者将控制权传递给被调用者(粗略地,将其想象为源代码中跳转到函数代码块的开头)。因此,当您呼叫
func
时,您就会跳入 func
身体。此函数尝试查找名称:print
和 greeting
(此过程称为 名称解析)。它在 local
范围中查找,然后在 global
范围(定义它的范围,不称为)中查找,最后在 builtins
中查找。它在 print
中仅找到 builtins
。因为它没有找到 greeting
名称,所以会引发异常 NameError
。在检测到错误的地方引发异常,在您的情况下,在 main
称为 func
的地方引发异常。当根本没有处理异常时,解释器将终止程序的执行,或返回到其交互式主循环。无论哪种情况,它都会打印堆栈跟踪,除非异常为 SystemExit
。
还有一个查找信息的地方:Python 语言参考:执行模型
p.s.:全局范围始终是定义函数的模块(带有代码的文件)。理解这一点非常重要!!!
在Python中,函数不能访问函数外部的任何变量,除非它是一个参数或被声明
global
。
这有望解决问题:
greeting = None
def func():
print(greeting)
def main():
global greeting # Declaring as global means func() can access it
greeting = "Hello world"
func()
main()