Python Django 调用其他函数时出现 UnboundLocalError

0 投票
2 回答
684 浏览
提问于 2025-04-17 06:28

不久前,我开始学习用Python和Django编程。有时候我会遇到奇怪的错误,完全不知道为什么。现在我们就来看看其中一个错误。

我有一个视图(View),里面有两个函数。举个例子:

def view_post(request, slug):
    """
    Shows a single post
    """
    posts = Post.objects(slug = slug).limit(1)
    for items in posts:
        post = items

    cssClasses = css_class_converter({ _css_class_editable })

    context = RequestContext(request)
    return render_to_response("single.html", { 'post': post, 'class': cssClasses }, context)

def new_post(request):
    '''
    Opens a blank page for creating a new post
    '''

    post = Post()
    cssClasses = css_class_converter({ _css_class_editable, _css_class_new })
    context = RequestContext(request)
    return render_to_response("single.html", {'post': post, 'new': True }, context)

然后通过我的URL配置来调用它们。调用view_post函数时,一切正常,没有错误。

urlpatterns = patterns('blog.views',
    # Examples:
    url(r'^$', views.index),
    url(r'^(?P<slug>[^\.]+)', 'view_post', name='view_blog_post'),
    url(r'^new/$', 'new_post', name='new_blog_post'),

...

但是调用new_post函数时,在第39行出现了一个UnboundLocalError异常,错误信息是"在赋值之前引用了局部变量'post'"。第39行是视图函数中的render_to_response,而不是new函数。

所以,为什么我调用new函数时会在view函数中出现错误呢? 说实话,我也不知道。我之前是用C#的,所以我肯定没有理解某个特别的Python规则,导致我写错了代码。

更新:由于stackoverflow.com的代码面板,两个函数的缩进不正确,别在意这个。

在这里输入图片描述

2 个回答

1

这个错误听起来像是 view_post 这个视图函数被调用了。你确定你的 URL 模式设置正确吗?或者说,可能有两个 URL 正则表达式都指向了 view_post

view_post 中,如果查询没有找到任何项目,那么在循环中设置的变量 post 就不会被设置,这样在 render_to_response 中引用它时就会出现 UnboundLocalError 的错误。

你可以通过在循环之前将 post 设置为 None 来避免这个问题。

def view_post(request, slug):
        """
        Shows a single post
        """
        posts = Post.objects(slug = slug).limit(1)
        post = None   # Ensure post is bound even if there are no posts matching slug
        for items in posts:
            post = items

        cssClasses = css_class_converter({ _css_class_editable })

        context = RequestContext(request)
        return render_to_response("single.html", { 'post': post, 'class': cssClasses }, context)

你可以通过这个更简单的函数来理解为什么会出现 UnboundLocalError

def first_element(items):
    for item in items:
        result = item
        break
    return result

(显然,你不会真的这样实现 first_element,但这能说明发生了什么。)如果你用一个非空列表调用 first_element,它会按预期工作:

>>> first_element([2, 3, 4])
2

但是如果你用一个空列表调用它,结果就从来没有被绑定过,所以你会得到错误:

>>> first_element([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in first_element
UnboundLocalError: local variable 'result' referenced before assignment
3

问题出在缩进上

def view(request):
    ...
    def new(request):
        ...

这在Python中是不同的:

def view(request):
    ...

def new(request):
    ...

你应该确保使用空格来缩进,Python推荐使用4个空格,而不是制表符(Tab键)

更新:

问题出在网址上:

url(r'^$', views.index),
url(r'^(?P<slug>[^\.]+)', 'view_post', name='view_blog_post'),
url(r'^new/$', 'new_post', name='new_blog_post'),

把它改成:

url(r'^$', views.index),
url(r'^new/$', 'new_post', name='new_blog_post'),
url(r'^(?P<slug>[^\.]+)', 'view_post', name='view_blog_post'),

这是因为网址/new/符合这个正则表达式

r'^(?P<slug>[^\.]+)'

撰写回答