Python 通过尝试后抛出错误 - 除了块

Python Throwing Error After Passing Try - Except Block

我正在使用此脚本在 PostgreSQL“集群”中创建数据库和用户,然后创建存在于另一个模式中的新模式(我只复制它们的名称)。

我正在使用 Python 2.7.5,这是我的脚本:

import sys
import psycopg2
import getpass

def connect_db(database):
    connection = psycopg2.connect(user="postgres",
                              password="mypass",
                              host="127.0.0.1",
                              port="5432",
                              database=str(database))
    connection.autocommit = True
    cursor = connection.cursor()
    return cursor


def execute_query_2_select(cursor, query):
    try:
        cursor.execute(query)
        output = cursor.fetchall()
        return output
    except Exception as e:
        print(e)


def execute_query_2_create(cursor, query):
    try:
        cursor.execute(query)
    except Exception as e:
        print(e)


def main():
    source_database = str(raw_input("Enter a tns name(DB_UNIQUE_NAME): ")).strip()
    target_database = str(raw_input("Enter a username(OID): ")).strip()
    user_password = str(getpass.getpass("Enter the password of" )).strip()

    try:
        cursor_source = connect_db(source_database)
    except Exception:
        print("Please check your input and try again.\n")
        main()

    query_2_get_schemas = "select schema_name from information_schema.schemata where schema_name not like 'pg_%' and schema_name not in ('public', 'information_schema');"
    schema_template_list = execute_query_2_select(cursor_source, query_2_get_schemas)
    cursor_source.close()

    cursor_postgres = connect_db("postgres")

    execute_query_2_create(cursor_postgres, "create user {x} with encrypted password '{y}';".format(x=target_database, y=user_password))
    execute_query_2_create(cursor_postgres, "create database {x} owner {x};".format(x=target_database))
    cursor_postgres.close()

    cursor_target = connect_db(target_database)

    for i in schema_template_list:
        execute_query_2_create(cursor_target, "CREATE SCHEMA IF NOT EXISTS {x};".format(x=i[0]))
        execute_query_2_create(cursor_target, "GRANT USAGE ON SCHEMA {x} TO {x};".format(x=i[0]))
        execute_query_2_create(cursor_target, "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA {x} TO {x};".format(x=i[0]))
        execute_query_2_create(cursor_target, "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA {x} to {x};".format(x=i[0]))
        execute_query_2_create(cursor_target, "ALTER DEFAULT PRIVILEGES IN SCHEMA {x} GRANT ALL PRIVILEGES ON TABLES TO {x};".format( x=i[0]))
        execute_query_2_create(cursor_target, "ALTER DEFAULT PRIVILEGES IN SCHEMA {x} GRANT ALL PRIVILEGES ON SEQUENCES TO {x};".format( x=i[0]))
        execute_query_2_create(cursor_target, "ALTER SCHEMA {x} OWNER TO {x};".format(x=i[0]))
        print("Commands for schema {x} are executed!".format(x=i[0]))

    cursor_target.close()

if __name__ == "__main__":
    main()

因为异常块

    except Exception:
        print("Please check your input and try again.\n")
        main()

如果用户提供了不正确的连接数据并再次输入,我将让用户返回并检查他们的输入。为了在第一次尝试时测试脚本,我提供了不正确的连接数据。然后它回到我想要它去的地方。最后,我提供了正确的信息,但这次我得到了“UnboundLocalError:局部变量 'cursor_source' 在赋值前被引用”。为什么?它在 second/later 次尝试中定义。

输出:

Enter a database name for schema pattern: asdaslkdjals
Enter a database/user name to create: asdasd
Enter the password of user asdasd
Please check your input and try again.

Enter a database name for schema pattern: test_source
Enter a database/user name to create: test_target
Enter the password of user test_target
Commands for schema test_schemaxx are executed!
Traceback (most recent call last):
  File "schema.py", line 68, in <module>
    main()
  File "schema.py", line 44, in main
    schema_template_list = execute_query_2_select(cursor_source, query_2_get_schemas)
UnboundLocalError: local variable 'cursor_source' referenced before assignment

你试过全局语句了吗? 例如,将全局放在一个循环中:

A = 20
def main():
  print(‘Does Something’)
  input = input(‘ variable a’s new value : ‘)
  #input == 10
main()

如果您尝试访问函数内的变量,将会报错。但如果你这样做:

A = 20
def main():
  global A
  print(‘Does Something’)
  input = input(‘ variable A’s new value : ‘)
  #input == 10
main()

这将停止给出错误。

我不是 100% 了解您为什么要在本地解除绑定,但是从异常处理程序调用 main 绝对是个坏主意。

根据用户必须重试的次数,您可能会进入无限递归状态,并且可能会留下各种 half-initialized 连接。

相反,您应该在 while 循环中重试,这样您就不必退出主函数。

这是你给出的例子的递归程序流程:先是错误的输入,然后是正确的输入:

  1. 你打电话给main
  2. 您在 try
  3. 中传递了错误的输入
  4. 执行except,再次调用main
    1. 你传递了很好的输入
    2. try 执行没有问题
    3. 函数的其余部分 运行s 和 returns
  5. 递归调用结束 - 回到第一次调用.
  6. 现在第一个 main 保持 运行ning 没有 cursor_source 定义(因为try失败)。

您基本上需要将所有代码放在 except 之后的 else 块中 - 如果没有错误,这就是您想要的 运行。但是在那种情况下简单地 return 会更容易:

    try:
        cursor_source = connect_db(source_database)
    except Exception:
        print("Please check your input and try again.\n")
        main()
        return

但是避免递归并简单地使用循环会更容易:

while True:
    source_database = str(raw_input("Enter a tns name(DB_UNIQUE_NAME): ")).strip()
    target_database = str(raw_input("Enter a username(OID): ")).strip()
    user_password = str(getpass.getpass("Enter the password of" )).strip()
    try:
        cursor_source = connect_db(source_database)
    except Exception:
        print("Please check your input and try again.\n")
    else:
        break
    
# rest of function