函数和局部变量可以同名吗?
Can a function and local variable have the same name?
这是我的意思的一个例子:
def foo():
foo = 5
print(foo + 5)
foo()
# => 10
代码没有产生任何错误并且运行完美。这与变量和函数不应该具有相同名称除非您覆盖它们的想法相矛盾。 它为什么有效?当应用于实际代码时,我应该使用不同的 function/local 变量名,还是完全没问题?
foo = 5
在您的函数中创建一个局部变量。 def foo
创建一个全局变量。这就是为什么他们可以有相同的名字。
如果您在 foo()
函数中引用 foo
,则您指的是局部变量。如果您在该函数之外引用 foo
,则您指的是全局变量。
由于它显然会给试图遵循代码的人造成混淆,您可能不应该这样做。
答案是肯定的。
函数是 Python 中的第一个 class 个对象。 foo
函数和 foo
变量之间没有根本区别。这两个都是对内存的引用并且都有一个范围,所以它们都等同于一个变量。
如果你把 foo 定义为一个函数,然后不在本地覆盖它,它就像一个全局变量(取自上层作用域):
def foo():
print(foo)
然后如果你用局部变量覆盖它,它只会在函数范围内定义一个局部变量:
def foo():
foo = 3
print(foo)
在Python中,每个引用(变量)都可以在特定作用域的生命周期内被覆盖。你可以试试:
def foo(): pass
foo = 3
这将覆盖 foo 的值,它现在将指向 3 而不是内存中的函数 foo。
嗯,这是因为每个 foo
的变量范围。函数foo()
在全局范围内,因此可以在其他函数内和函数外调用。
然而,变量foo
在本地范围内。这意味着它只“存在于”函数内部,不能在函数外部被调用或引用。
因此,每个不同的函数在调用时都会创建自己的局部作用域,而一旦作用域被销毁(函数结束),其中创建的变量就会被遗忘。
全局变量可以在局部范围内访问,局部变量不能在全局范围内访问。
如果要在全局范围内创建变量,可以这样调用:
global var
这是全局和局部范围的示例:
var=1
def foo1():
var=3
foo1()
print(var) #prints 1 because the "var" in foo1() is locally assigned
def foo2():
global var
var=2
foo2()
print(var) #prints 2 because "var" is global
因此,您的函数有效,因为我只在本地而非全局分配名称 foo
。
但是,如果您稍后在该函数中调用foo()
,它将引发错误,因为该局部作用域已将一个int值分配给foo
, 不是函数,因此不可调用。
其他人尚未提及的内容:Python 是一种 动态 语言,只有很少的静态检查。所以当你写
def foo():
foo = 5
print(foo + 5)
您可能一直认为这是一个“矛盾”——foo
怎么能同时是一个函数和一个整型变量呢?一阶答案是“这是两个不同的 foo
”,因为内部 foo
只是一个局部变量,与全局名称 foo
无关。但是使它成为全局的,并且代码仍然有效!
def foo():
global foo
foo = 5
print(foo + 5)
foo() # OK, prints 10
在这个代码中是只有一个foo
!但是,它不是“既是变量又是函数”。首先,在第 1-4 行,我们将 foo
定义为具有特定主体的函数 — 但我们尚未执行该主体。 在第 4 行之后,全局 foo
持有一个函数。然后,在第 6 行,我们实际上调用了 foo
所引用的函数,它执行了它的主体。主体做的第一件事是将 5
分配给 foo
... 并且 now foo
持有一个整数。通过将新值分配给 foo
的 运行 代码,我们更改了 foo
的值。它曾经是那个功能在那里;现在是 5。在像 Python 这样的动态类型语言中,这没什么问题。
def foo():
global foo
foo = 5
print(foo + 5)
foo() # OK, prints 10 (and incidentally assigns a new value to foo)
foo() # Raises TypeError: 'int' object is not callable
使用相同名称的另一个问题显然是编写递归时的歧义:
def fibo(n: int) -> int:
if n <= 1:
fibo = 1
else:
fibo = fibo(n - 1) + fibo(n - 2)
return fibo
结果:
UnboundLocalError: local variable 'fibo' referenced before assignment
它发生是因为在函数内部定义了 fibo
。
当 Python 尝试 运行 fibo(n - 1)
时,它会搜索本地 fibo
变量,但找不到它的值。
简短的评论:pylint 用警告标记它。 pylint 是我们的朋友!
在python中,变量的作用域是从当前最内层作用域向全局作用域搜索确定的。
Python Scopes and Namespaces(Emphasis mine)
- A namespace is a mapping from names to objects.
- A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means
that an unqualified reference to a name attempts to find the name in
the namespace.
At any time during execution, there are 3 or 4 nested scopes whose
namespaces are directly accessible:
- the innermost scope, which is searched first, contains the local names
- the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also
non-global names
- the next-to-last scope contains the current module’s global names
- the outermost scope (searched last) is the namespace containing built-in names.
A special quirk of Python is that – if no
global
or
nonlocal
statement is in effect – assignments to names always go into the
innermost scope.
示例中,
# Current module's scope starts here.
def foo():
# Local Scope Starts here.
foo = 5
print(foo + 5)
# Local scope Ends here.
foo()
# Current module's scope ends here.
应用上述规则解析范围
foo = 5
属于 本地范围 因为没有 global
或 nonlocal
语句。函数内部的foo
属于函数的局部作用域。
print(foo + 5)
解析函数内部的 foo
,因为 python 从最内层的范围开始搜索。范围解析规则 1 和 2 适用。这里的最内层作用域与封闭函数的作用域相同。
foo()
在模块级作用域被调用。 Python 开始搜索最内层的可用范围,这里是模块级。因此,它解析为在模块级别定义的函数。
另一个例子,
def foo():
print(foo + 5)
foo()
# TypeError: unsupported operand type(s) for +: 'function' and 'int'
foo()
在模块级作用域被调用。 Python 开始搜索最内层的可用范围,这里是模块级。因此,它解析为在模块级别定义的函数。
print(foo + 5)
也将解析为模块级 foo
函数,因为 python 在封闭函数范围内开始搜索但未找到匹配项。移动到下一个范围,即模块级别并找到匹配项。匹配的是foo
函数。因此,错误。
另一个例子,
def foo():
foo = "str"
def inner():
#(1) foo = 1 # Commented this line
print(foo)
inner()
print(foo)
foo()
# str
# str
# Uncommenting (1) gives output as
foo()
# 1
# str
阅读更多关于 Scoping rules
这是我的意思的一个例子:
def foo():
foo = 5
print(foo + 5)
foo()
# => 10
代码没有产生任何错误并且运行完美。这与变量和函数不应该具有相同名称除非您覆盖它们的想法相矛盾。 它为什么有效?当应用于实际代码时,我应该使用不同的 function/local 变量名,还是完全没问题?
foo = 5
在您的函数中创建一个局部变量。 def foo
创建一个全局变量。这就是为什么他们可以有相同的名字。
如果您在 foo()
函数中引用 foo
,则您指的是局部变量。如果您在该函数之外引用 foo
,则您指的是全局变量。
由于它显然会给试图遵循代码的人造成混淆,您可能不应该这样做。
答案是肯定的。
函数是 Python 中的第一个 class 个对象。 foo
函数和 foo
变量之间没有根本区别。这两个都是对内存的引用并且都有一个范围,所以它们都等同于一个变量。
如果你把 foo 定义为一个函数,然后不在本地覆盖它,它就像一个全局变量(取自上层作用域):
def foo():
print(foo)
然后如果你用局部变量覆盖它,它只会在函数范围内定义一个局部变量:
def foo():
foo = 3
print(foo)
在Python中,每个引用(变量)都可以在特定作用域的生命周期内被覆盖。你可以试试:
def foo(): pass
foo = 3
这将覆盖 foo 的值,它现在将指向 3 而不是内存中的函数 foo。
嗯,这是因为每个 foo
的变量范围。函数foo()
在全局范围内,因此可以在其他函数内和函数外调用。
然而,变量foo
在本地范围内。这意味着它只“存在于”函数内部,不能在函数外部被调用或引用。
因此,每个不同的函数在调用时都会创建自己的局部作用域,而一旦作用域被销毁(函数结束),其中创建的变量就会被遗忘。
全局变量可以在局部范围内访问,局部变量不能在全局范围内访问。
如果要在全局范围内创建变量,可以这样调用:
global var
这是全局和局部范围的示例:
var=1
def foo1():
var=3
foo1()
print(var) #prints 1 because the "var" in foo1() is locally assigned
def foo2():
global var
var=2
foo2()
print(var) #prints 2 because "var" is global
因此,您的函数有效,因为我只在本地而非全局分配名称 foo
。
但是,如果您稍后在该函数中调用foo()
,它将引发错误,因为该局部作用域已将一个int值分配给foo
, 不是函数,因此不可调用。
其他人尚未提及的内容:Python 是一种 动态 语言,只有很少的静态检查。所以当你写
def foo():
foo = 5
print(foo + 5)
您可能一直认为这是一个“矛盾”——foo
怎么能同时是一个函数和一个整型变量呢?一阶答案是“这是两个不同的 foo
”,因为内部 foo
只是一个局部变量,与全局名称 foo
无关。但是使它成为全局的,并且代码仍然有效!
def foo():
global foo
foo = 5
print(foo + 5)
foo() # OK, prints 10
在这个代码中是只有一个foo
!但是,它不是“既是变量又是函数”。首先,在第 1-4 行,我们将 foo
定义为具有特定主体的函数 — 但我们尚未执行该主体。 在第 4 行之后,全局 foo
持有一个函数。然后,在第 6 行,我们实际上调用了 foo
所引用的函数,它执行了它的主体。主体做的第一件事是将 5
分配给 foo
... 并且 now foo
持有一个整数。通过将新值分配给 foo
的 运行 代码,我们更改了 foo
的值。它曾经是那个功能在那里;现在是 5。在像 Python 这样的动态类型语言中,这没什么问题。
def foo():
global foo
foo = 5
print(foo + 5)
foo() # OK, prints 10 (and incidentally assigns a new value to foo)
foo() # Raises TypeError: 'int' object is not callable
使用相同名称的另一个问题显然是编写递归时的歧义:
def fibo(n: int) -> int:
if n <= 1:
fibo = 1
else:
fibo = fibo(n - 1) + fibo(n - 2)
return fibo
结果:
UnboundLocalError: local variable 'fibo' referenced before assignment
它发生是因为在函数内部定义了 fibo
。
当 Python 尝试 运行 fibo(n - 1)
时,它会搜索本地 fibo
变量,但找不到它的值。
简短的评论:pylint 用警告标记它。 pylint 是我们的朋友!
在python中,变量的作用域是从当前最内层作用域向全局作用域搜索确定的。
Python Scopes and Namespaces(Emphasis mine)
- A namespace is a mapping from names to objects.
- A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.
At any time during execution, there are 3 or 4 nested scopes whose namespaces are directly accessible:
- the innermost scope, which is searched first, contains the local names
- the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
- the next-to-last scope contains the current module’s global names
- the outermost scope (searched last) is the namespace containing built-in names.
A special quirk of Python is that – if no global or nonlocal statement is in effect – assignments to names always go into the innermost scope.
示例中,
# Current module's scope starts here.
def foo():
# Local Scope Starts here.
foo = 5
print(foo + 5)
# Local scope Ends here.
foo()
# Current module's scope ends here.
应用上述规则解析范围
foo = 5
属于 本地范围 因为没有global
或nonlocal
语句。函数内部的foo
属于函数的局部作用域。print(foo + 5)
解析函数内部的foo
,因为 python 从最内层的范围开始搜索。范围解析规则 1 和 2 适用。这里的最内层作用域与封闭函数的作用域相同。foo()
在模块级作用域被调用。 Python 开始搜索最内层的可用范围,这里是模块级。因此,它解析为在模块级别定义的函数。
另一个例子,
def foo():
print(foo + 5)
foo()
# TypeError: unsupported operand type(s) for +: 'function' and 'int'
foo()
在模块级作用域被调用。 Python 开始搜索最内层的可用范围,这里是模块级。因此,它解析为在模块级别定义的函数。print(foo + 5)
也将解析为模块级foo
函数,因为 python 在封闭函数范围内开始搜索但未找到匹配项。移动到下一个范围,即模块级别并找到匹配项。匹配的是foo
函数。因此,错误。
另一个例子,
def foo():
foo = "str"
def inner():
#(1) foo = 1 # Commented this line
print(foo)
inner()
print(foo)
foo()
# str
# str
# Uncommenting (1) gives output as
foo()
# 1
# str
阅读更多关于 Scoping rules