“装饰器定义中未引用的局部变量”

2024-04-19 13:56:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我的代码行为怪异,我不明白为什么。你知道吗

代码如下:

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应该默认设置为"",我不知道问题出在哪里。 奇怪的是,如果我运行相同的代码并将decorator更改为:

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文件中。你知道吗


Tags: pathdjango代码namefromimporturlreturn
1条回答
网友
1楼 · 发布于 2024-04-19 13:56:36

答案就在你没贴的那部分。你真正的代码看起来像

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会使名称“name”成为dec的本地名称,因此不会在封闭作用域中查找它。由于在赋值之前对它进行测试(“reference”),所以会出现非常明显的错误(不,只是开玩笑)“localvariable'name'referenced before assignment”。你知道吗

这里的解决方案是在dec函数的顶部将name声明为“非本地”,这样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,则必须借助黑客来模拟此行为:

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

这里的黑客建议您对其进行变异而不是重新绑定,因此Python不会将其标记为局部变量。你知道吗

作为补充,我不建议尝试移植这个@route(url)习惯用法(有人吗?)去Django。首先是因为将视图定义与url映射分离是一个经过深思熟虑的设计决策,它允许将第三部分apps url重新映射到我们想要的任何东西,而无需黑客或叉子等,而且还因为大多数Django开发人员希望url在urls.py模块中被明确定义,并且会因为您不遵守约定而憎恨您。现在你当然可以随心所欲地写你的项目了,但是遵循惯例对每个人来说都很容易。我的2美分。。。

相关问题 更多 >