首先:你太懒了。在您在这里编写代码之前,至少将其提供给相关语言的解释器或编译器,以消除明显的问题。在这种情况下,有两个:
- 由于语法错误,您的示例代码无法编译。通过在
func1 的定义上添加() 来修复它。
- 由于
func2 在调用位置未定义,您的示例代码将无法运行。
那就试试吧
#!/usr/bin/env python
def func1():
x = 5
def func2(y):
#x = x + 1 # invalid: "x referenced before assignment"
return x*y # not invalid! reference to x is fine
global func3
func3 = func2
#print func3(5) # undefined
func1()
print func3(5)
#print func2(5) # undefined
三行注释;它们在取消注释时会产生错误。
如您所见,Python 对变量和函数的定义默认是本地:在函数中定义时,它们仅适用于该函数,不能在其他地方使用。 p>
在函数外部定义的变量可以在函数内部使用。
但是,它们只能读取,而不能写入。这解释了为什么我们可以在 func2 中使用 x 但不能分配给它;当 x = x + 1 未注释时,它被解释为应用于 func2 内的不同 x 变量,这就是为什么我们会收到错误消息,抱怨它未初始化。
另外,Python有global变量,可以在程序中任何地方使用;此类变量必须明确标记为global。
这与 PHP 非常相似(其中变量也可以标记为global),并且与许多其他语言非常相似,例如 C(没有global,但类似的extern)。
您正在尝试让函数 (func2) 使用在其定义上下文中定义的变量 (x),然后在定义 x 的上下文之外调用该函数并且仍然可以工作.可以做到这一点的函数称为闭包。
我们刚刚看到Python only has partial support for closures: 函数可以读取这些变量,但不能修改它们。这已经比许多其他语言更好。但是,完全闭包也可以修改这些变量。
例如,以下是有效的 Perl 代码:
#!/usr/bin/env perl
use strict;
use warnings;
my $func3 = sub { 1 };
my $func1 = sub
{
my $x = 5;
my $func2 = sub
{
my ($y) = @_;
++$x;
$x*$y
};
$func3 = $func2
};
#&$func2(5); # won't compile: func2 is undefined
print &$func3(5), "\n"; # prints 1
&$func1();
print &$func3(5), "\n"; # prints 30
print &$func3(5), "\n"; # prints 35
传统上,完全闭包支持与 dynamic scoping 相关联(即,使定义成为可执行语句,在运行时评估)。这是因为它是由动态范围的 Lisp 引入的,并且在使用 static (lexical) scoping 的语言中很少支持它(其中定义的范围是在编译时确定的,而不是在运行时确定的)。但是这个 Perl 代码中的所有变量和函数定义都是静态作用域的。