Python的习惯用法';尝试直到没有引发异常';
我希望我的代码自动尝试多种方法来创建数据库连接。一旦一种方法起作用,代码就需要继续前进(即,它不应该再尝试其他方法)。如果它们都失败了,那么脚本可能会崩溃 所以,在-我认为是,但很可能不是-一个天才的笔触中,我尝试了这个:Python的习惯用法';尝试直到没有引发异常';,python,Python,我希望我的代码自动尝试多种方法来创建数据库连接。一旦一种方法起作用,代码就需要继续前进(即,它不应该再尝试其他方法)。如果它们都失败了,那么脚本可能会崩溃 所以,在-我认为是,但很可能不是-一个天才的笔触中,我尝试了这个: import psycopg2 from getpass import getpass # ouch, global variable, ooh well, it's just a simple script eh CURSOR = None def get_cursor
import psycopg2
from getpass import getpass
# ouch, global variable, ooh well, it's just a simple script eh
CURSOR = None
def get_cursor():
"""Create database connection and return standard cursor."""
global CURSOR
if not CURSOR:
# try to connect and get a cursor
try:
# first try the bog standard way: db postgres, user postgres and local socket
conn = psycopg2.connect(database='postgres', user='postgres')
except psycopg2.OperationalError:
# maybe user pgsql?
conn = psycopg2.connect(database='postgres', user='pgsql')
except psycopg2.OperationalError:
# maybe it was postgres, but on localhost? prolly need password then
conn = psycopg2.connect(database='postgres', user='postgres', host='localhost', password=getpass())
except psycopg2.OperationalError:
# or maybe it was pgsql and on localhost
conn = psycopg2.connect(database='postgres', user='pgsql', host='localhost', password=getpass())
# allright, nothing blew up, so we have a connection
# now make a cursor
CURSOR = conn.cursor()
# return existing or new cursor
return CURSOR
但第二个和后续的except语句似乎不再捕捉操作错误。可能是因为Python在try…except语句中只捕获一次异常
是这样吗?如果不是:还有什么我做错了吗?如果是这样的话:那你是怎么做的?有标准的成语吗
(我知道有很多方法可以解决这个问题,比如让用户在命令行上指定连接参数,但这不是我的问题好:)
编辑:
我接受了retracile的优秀回答,并接受了gnibbler使用for..else结构的评论。最后的代码是(对不起,我没有真正遵循pep8中每行最多字符数的限制):
编辑2:正如您在Cursor类的注释中所看到的:我真的不知道如何调用这种类。它不是一个真正的单例(我可以有多个不同的游标实例),但是当调用get_Cursor时,每次都会得到相同的游标对象。所以它就像一个单身工厂?:)
大约:
attempts = [
{ 'database'='postgres', 'user'='pgsql', ...},
{ 'database'='postgres', 'user'='postgres', 'host'='localhost', 'password'=getpass()},
...
]
conn = None
for attempt in attempts:
try:
conn = psycopg2.connect(**attempt)
break
except psycopg2.OperationalError:
pass
if conn is None:
raise a ruckus
CURSOR = conn.cursor()
现在,如果您不想调用getpass()
,除非有必要,那么您应该检查在尝试中的'password'是否为:trunt['password']=getpass()
等等
现在,关于全球
class MyCursor:
def __init__(self):
self.CURSOR = None
def __call__(self):
if self.CURSOR is None:
<insert logic here>
return self.CURSOR
get_cursor = MyCursor()
注意:完全未经测试您已接近成功。在这种情况下,最好的做法可能是在except块中嵌套第二次和后续尝试。因此,代码的关键部分如下所示:
if not CURSOR:
# try to connect and get a cursor
try:
# first try the bog standard way: db postgres, user postgres and local socket
conn = psycopg2.connect(database='postgres', user='postgres')
except psycopg2.OperationalError:
# maybe user pgsql?
try:
conn = psycopg2.connect(database='postgres', user='pgsql')
except psycopg2.OperationalError:
# maybe it was postgres, but on localhost? prolly need password then
try:
conn = psycopg2.connect(database='postgres', user='postgres', host='localhost', password=getpass())
except psycopg2.OperationalError:
# or maybe it was pgsql and on localhost
conn = psycopg2.connect(database='postgres', user='pgsql', host='localhost', password=getpass())
不必将
conn
初始化为None
,您只需使用上的else
子句,用于+1@David:中断可确保返回第一个工作的连接。随着数据库数量的增加,此解决方案可以很好地扩展,并且连接字符串已经很好地从代码中抽象出来。@gnibbler-Woah,我忘了Python有那个很棒的功能()@retracile,你是对的,出于某种原因,我认为中断将一事无成。@David:没问题;如果你不愿意,我不会告诉任何人;)-呃,完全不是蟒蛇。使您看起来像C++ COM程序员。
class MyCursor:
def __init__(self):
self.CURSOR = None
def __call__(self):
if self.CURSOR is None:
attempts = [
{'database'='postgres', 'user'='postgres'},
{'database'='postgres', 'user'='pgsql'},
{'database'='postgres', 'user'='postgres', 'host'='localhost', 'password'=True},
{'database'='postgres', 'user'='pgsql', 'host'='localhost', 'password'=True},
]
conn = None
for attempt in attempts:
if 'password' in attempt:
attempt['password'] = getpass()
try:
conn = psycopg2.connect(**attempt)
break # that didn't throw an exception, we're done
except psycopg2.OperationalError:
pass
if conn is None:
raise a ruckus # nothin' worked
self.CURSOR = conn.cursor()
return self.CURSOR
get_cursor = MyCursor()
if not CURSOR:
# try to connect and get a cursor
try:
# first try the bog standard way: db postgres, user postgres and local socket
conn = psycopg2.connect(database='postgres', user='postgres')
except psycopg2.OperationalError:
# maybe user pgsql?
try:
conn = psycopg2.connect(database='postgres', user='pgsql')
except psycopg2.OperationalError:
# maybe it was postgres, but on localhost? prolly need password then
try:
conn = psycopg2.connect(database='postgres', user='postgres', host='localhost', password=getpass())
except psycopg2.OperationalError:
# or maybe it was pgsql and on localhost
conn = psycopg2.connect(database='postgres', user='pgsql', host='localhost', password=getpass())