UnboundLocalError:分配前引用的局部变量“光标”

Posted

技术标签:

【中文标题】UnboundLocalError:分配前引用的局部变量“光标”【英文标题】:UnboundLocalError: local variable 'cursor' referenced before assignment 【发布时间】:2015-12-06 06:05:26 【问题描述】:

所以我是一个新手,但正在使用flask/mysql 中的注册系统表单

我收到此错误(UnboundLocalError: local variable 'cursor' referenced before assignment)

在玩了几个小时的代码和研究之后,我需要你的帮助。

这是我的文件,如果还有什么需要分享的,请告诉我。 谢谢

from flask import Flask, render_template, json, request
from flask.ext.mysqldb import MySQL
from werkzeug import generate_password_hash, check_password_hash

app = Flask(__name__)
mysql = MySQL()


app.config['MYSQL_DATABASE_USER'] = 'x'
app.config['MYSQL_DATABASE_PASSWORD'] = 'x'
app.config['MYSQL_DATABASE_DB'] = 'x'
app.config['MYSQL_DATABASE_HOST'] = 'x'
mysql.init_app(app)

@app.route('/')
def main():
    return render_template('index.html')

@app.route('/login')
def login():
    return render_template('login.html')

@app.route('/showSignUp')
def showSignUp():
    return render_template('signup.html')


@app.route('/signUp',methods=['POST','GET'])
def signUp():
    try:
        _name = request.form['inputName']
        _email = request.form['inputEmail']
        _password = request.form['inputPassword']

        # validate the received values
        if _name and _email and _password:

            # All Good, let's call the MySQL

            conn = mysql.connect()
            cursor = conn.cursor()
            _hashed_password = generate_password_hash(_password)
            cursor.callproc('sp_createUser',(_name,_email,_hashed_password))
            data = cursor.fetchall()

            if len(data) is 0:
                conn.commit()
                return json.dumps('message':'User created successfully !')
            else:
                return json.dumps('error':str(data[0]))
        else:
            return json.dumps('html':'<span>Enter the required fields</span>')

    except Exception as e:
        return json.dumps('error':str(e))
    finally:
        cursor.close()
    conn.close()

if __name__ == '__main__':
    app.run()

【问题讨论】:

【参考方案1】:

您只在 if 块中定义 conncursor 检查表单值。如果未输入块,则它们未定义,但您仍然尝试引用它们以关闭它们。如果你已经定义了它们,你应该只在两者上调用close。要么将 conn =cursor = 移到 if 块之前,要么将 close 调用移到块内。

但是,更大的问题是您对如何使用 Flask-MySQLdb 有误解/过于复杂。它会在请求完成时自动创建连接并关闭它,这也会关闭游标。只需使用docs 中所述的扩展名即可。

...
cur = mysql.connection.cursor()
cur.callproc('sp_createUser', (name, email, hashed_password))
data = cur.fetchall()
...

【讨论】:

【参考方案2】:

我个人建议使用上下文管理器来处理光标和连接的打开和关闭。您可以相当简单地实现这一点,并且它更干净,更易于调试。这也将消除尝试关闭连接或游标之前在您的巨型 try except 块中打开它的问题。

from contextlib import closing

# do a bunch of stuff prior to opening connection
with closing(mysql.connect()) as conn:
    with closing(conn.cursor()) as cursor:
        # do a bunch of stuff and don't worry about running .close()

您可以查看closing here 的文档。

使用closing 会将您的代码更改为类似这样。虽然它可以使用更多的重构,但这是代码审查网站的问题。

from flask import Flask, render_template, json, request
from flask.ext.mysqldb import MySQL
from werkzeug import generate_password_hash, check_password_hash
from contextlib import closing

app = Flask(__name__)
mysql = MySQL()


app.config['MYSQL_DATABASE_USER'] = 'x'
app.config['MYSQL_DATABASE_PASSWORD'] = 'x'
app.config['MYSQL_DATABASE_DB'] = 'x'
app.config['MYSQL_DATABASE_HOST'] = 'x'
mysql.init_app(app)

@app.route('/')
def main():
    return render_template('index.html')

@app.route('/login')
def login():
    return render_template('login.html')

@app.route('/showSignUp')
def showSignUp():
    return render_template('signup.html')


@app.route('/signUp',methods=['POST','GET'])
def signUp():
    try:
        _name = request.form['inputName']
        _email = request.form['inputEmail']
        _password = request.form['inputPassword']

        # validate the received values
        if _name and _email and _password:

            # All Good, let's call the MySQL

            with closing(mysql.connect()) as conn:
                with closing(conn.cursor()) as cursor:
                    _hashed_password = generate_password_hash(_password)
                    cursor.callproc('sp_createUser',(_name,_email,_hashed_password))
                    data = cursor.fetchall()

                    if len(data) is 0:
                        conn.commit()
                        return json.dumps('message':'User created successfully !')
                    else:
                        return json.dumps('error':str(data[0]))
        else:
            return json.dumps('html':'<span>Enter the required fields</span>')

    except Exception as e:
        return json.dumps('error':str(e))

if __name__ == '__main__':
    app.run()

【讨论】:

所以我删除了我的 finally 代码,直到 if name 并将其替换为您的 cmets 之间的代码并导入上下文库? 是的,删除 finally 语句并导入该库并将 opens 更改为 with 语句,您应该会很好。 啊,我明白了。我以前从未使用过烧瓶,但我熟悉纯 python 中的手动数据库连接。 @JasonMartinez,切换到 django。 ;) djangoproject.com喜剧+1 @electrometro 我想了一会儿,但我花了很多时间在视频和研究如何用 Python 和烧瓶做事,我拒绝放弃。最终虽然我可能会。

以上是关于UnboundLocalError:分配前引用的局部变量“光标”的主要内容,如果未能解决你的问题,请参考以下文章

UnboundLocalError:分配前引用的局部变量“公会”

分配前引用的 /blog/search/ 局部变量 'cd' 处的 UnboundLocalError

机器人框架:UnboundLocalError:分配前引用的局部变量“cellValue”

Django:UnboundLocalError:分配前引用的局部变量“公司”

UnboundLocalError:分配前引用的局部变量“class_name”

Q:'UnboundLocalError':分配前引用了局部变量'exitErr'