装饰器定义中未引用的局部变量
Local variable unreferenced in decorator definition
我的代码表现得很奇怪,我不明白为什么。
代码如下:
from django.urls import path
app_name = 'portal'
urlpatterns = []
def route(url, name=""):
def dec(f):
f_name = name or f.__name__
urlpatterns.append(
path(url, f, name=f_name)
)
return f
return dec
from . import views
# 2) The decorator call in the other file
from . import urls
@urls.route("/my_function")
def my_function():
print("Hello world")
我在 name
上得到了一个 UnboundLocalError
File "urls.py", line 10, in dec
if name == "":
UnboundLocalError: local variable 'name' referenced before assignment
name
应该默认设置为""
,我不明白问题出在哪里。
奇怪的是,如果我 运行 相同的代码并将装饰器更改为:
urlpatterns = []
def route(url, name=""):
def dec(f):
if name == "":
print("I work!")
urlpatterns.append(
path(url, f, name=name)
)
return f
return dec
完美运行并输出:
I work !
虽然问题应该来自行 if name == ""
PS: 我在 django 上编程,这一行在 urls.py
文件中。
答案在您没有发布的部分。您的真实代码实际上看起来像
def route(url, name=""):
def dec(f):
if name == "":
# here's the real issue
name = "something_" + f.__name__
urlpatterns.append(
path(url, f, name=name)
)
return f
return dec
分配给 name
使其成为局部变量 - Python 没有变量声明,因此它是定义其范围的名称绑定的地方。在您的情况下,分配给 dec
中的名称会使名称 "name" 成为 dec
的本地名称,因此不会在封闭范围中查找它。既然你测试它 ("reference") before 你分配给它,你会得到非常明显的(不,开玩笑)“局部变量 'name' 在赋值之前引用" 错误。
此处的解决方案是在 dec
函数的顶部将 name
声明为 "nonlocal",因此 Python 知道必须在封闭的函数中查找它范围(或者更准确地说,在捕获 dec
函数环境的闭包单元格中):
def route(url, name=""):
def dec(f):
nonlocal name
if name == "":
# here's the real issue
name = "something_" + f.__name__
urlpatterns.append(
path(url, f, name=name)
)
return f
return dec
请注意,这仅适用于 Python3 - 如果使用 Python2,您将不得不诉诸 hack 来模拟此行为:
def route(url, name=""):
# Py2 hack: wrap the "nonlocal" variable in
# a mutable container
name = [name]
def dec(f):
if name[0] == "":
name[0] = "something_" + f.__name__
urlpatterns.append(
path(url, f, name=name[0])
)
return f
return dec
这里的 hack bing 你 mutate name
而不是重新绑定它,所以 Python 不会将它标记为本地变量。
作为旁注,我不建议尝试将此 @route(url)
习语(Flask 任何人?)移植到 Django。首先,因为将视图定义与 url 映射分开是一个深思熟虑的设计决策,它允许将第三方应用程序 urls 重新映射到我们想要的任何东西,而无需 hack 或 forks 等,也因为大多数 Django开发人员希望 urls 在 urls.py
模块中明确定义,并且会因为你不遵守约定而讨厌你。现在您当然可以随心所欲地编写您的项目,但是遵循约定会让每个人都更容易。我的2美分...
我的代码表现得很奇怪,我不明白为什么。
代码如下:
from django.urls import path
app_name = 'portal'
urlpatterns = []
def route(url, name=""):
def dec(f):
f_name = name or f.__name__
urlpatterns.append(
path(url, f, name=f_name)
)
return f
return dec
from . import views
# 2) The decorator call in the other file
from . import urls
@urls.route("/my_function")
def my_function():
print("Hello world")
我在 name
UnboundLocalError
File "urls.py", line 10, in dec
if name == "":
UnboundLocalError: local variable 'name' referenced before assignment
name
应该默认设置为""
,我不明白问题出在哪里。
奇怪的是,如果我 运行 相同的代码并将装饰器更改为:
urlpatterns = []
def route(url, name=""):
def dec(f):
if name == "":
print("I work!")
urlpatterns.append(
path(url, f, name=name)
)
return f
return dec
完美运行并输出:
I work !
虽然问题应该来自行 if name == ""
PS: 我在 django 上编程,这一行在 urls.py
文件中。
答案在您没有发布的部分。您的真实代码实际上看起来像
def route(url, name=""):
def dec(f):
if name == "":
# here's the real issue
name = "something_" + f.__name__
urlpatterns.append(
path(url, f, name=name)
)
return f
return dec
分配给 name
使其成为局部变量 - Python 没有变量声明,因此它是定义其范围的名称绑定的地方。在您的情况下,分配给 dec
中的名称会使名称 "name" 成为 dec
的本地名称,因此不会在封闭范围中查找它。既然你测试它 ("reference") before 你分配给它,你会得到非常明显的(不,开玩笑)“局部变量 'name' 在赋值之前引用" 错误。
此处的解决方案是在 dec
函数的顶部将 name
声明为 "nonlocal",因此 Python 知道必须在封闭的函数中查找它范围(或者更准确地说,在捕获 dec
函数环境的闭包单元格中):
def route(url, name=""):
def dec(f):
nonlocal name
if name == "":
# here's the real issue
name = "something_" + f.__name__
urlpatterns.append(
path(url, f, name=name)
)
return f
return dec
请注意,这仅适用于 Python3 - 如果使用 Python2,您将不得不诉诸 hack 来模拟此行为:
def route(url, name=""):
# Py2 hack: wrap the "nonlocal" variable in
# a mutable container
name = [name]
def dec(f):
if name[0] == "":
name[0] = "something_" + f.__name__
urlpatterns.append(
path(url, f, name=name[0])
)
return f
return dec
这里的 hack bing 你 mutate name
而不是重新绑定它,所以 Python 不会将它标记为本地变量。
作为旁注,我不建议尝试将此 @route(url)
习语(Flask 任何人?)移植到 Django。首先,因为将视图定义与 url 映射分开是一个深思熟虑的设计决策,它允许将第三方应用程序 urls 重新映射到我们想要的任何东西,而无需 hack 或 forks 等,也因为大多数 Django开发人员希望 urls 在 urls.py
模块中明确定义,并且会因为你不遵守约定而讨厌你。现在您当然可以随心所欲地编写您的项目,但是遵循约定会让每个人都更容易。我的2美分...