코드가 자동으로 여러 가지 방법으로 데이터베이스 연결을 만들려고합니다. 하나가 작동하자마자 코드를 계속 옮겨야합니다 (즉, 다른 방법으로 시도해서는 안 됨). 그들 모두가 잘 실패하면 스크립트는 그냥 날아갈 수 있습니다.'예외가 발생하지 않을 때까지 시도하십시오'에 대한 Python 관용구
그래서에서 - 나는라고 생각하지만, 가장 가능성이없는 것 - 천재의 스트로크가 나는이 시도 :
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
을하지만 문을 제외하고 두 번째 이후는 OperationalErrors를 잡는하지 않는 것 같다 더 이상. 아마 파이썬은 try ... except 문에서 한 번만 예외를 catch하기 때문에?
그렇습니까? 그렇지 않다면 내가 잘못하고있는 것이 있습니까? 그렇다면 다음과 같이 어떻게 할 것인가? 표준 관용구가 있습니까?
(I은 사용자가 명령 줄에서 연결 매개 변수를 지정할 수있는 같이이 문제를 해결 방법이 있습니다 알고 있지만 그 확인을 내 질문 : 아니다)
편집 :
I 허용 retracile의 훌륭한 대답과 for..else 구문을 사용하여 gnibbler의 의견을 들었다. 최종 코드는 다음과 같이되었습니다. (필자는 pep8에서 라인 제한 당 최대 문자 수를 실제로 따라갈 수 없습니다) :
EDIT 2 : 커 서 클래스에 대한 의견에서 알 수 있듯이 : 이런 종류의 클래스를 호출하는 방법. 그것은 실제로는 싱글 톤이 아닙니다 (저는 여러개의 Cursor 인스턴스를 가질 수 있습니다) 그러나 get_cursor를 호출 할 때마다 매번 동일한 커서 객체를 얻습니다. 그래서 싱글 톤 공장 같습니까? : 약
import psycopg2
from getpass import getpass
import sys
class UnableToConnectError(Exception):
pass
class Cursor:
"""Cursor singleton factory?"""
def __init__(self):
self.CURSOR = None
def __call__(self):
if self.CURSOR is None:
# try to connect and get a cursor
attempts = [
{'database': 'postgres', 'user': 'postgres'},
{'database': 'postgres', 'user': 'pgsql'},
{'database': 'postgres', 'user': 'postgres', 'host': 'localhost', 'password': None},
{'database': 'postgres', 'user': 'pgsql', 'host': 'localhost', 'password': None},
]
for attempt in attempts:
if 'password' in attempt:
attempt['password'] = getpass(stream=sys.stderr) # tty and stderr are default in 2.6, but 2.5 uses sys.stdout, which I don't want
try:
conn = psycopg2.connect(**attempt)
attempt.pop('password', None)
sys.stderr.write("Succesfully connected using: %s\n\n" % attempt)
break # no exception raised, we have a connection, break out of for loop
except psycopg2.OperationalError:
pass
else:
raise UnableToConnectError("Unable to connect: exhausted standard permutations of connection dsn.")
# allright, nothing blew up, so we have a connection
# now make a cursor
self.CURSOR = conn.cursor()
# return existing or new cursor
return self.CURSOR
get_cursor = Cursor()
대신 None''에'conn'를 초기화하는, 당신은 단지'for' –
+1 @ 데이비드의'else' 절을 사용할 수 있습니다 : 휴식 작업 한 첫 번째 연결이 반환되는지 확인합니다. 이 솔루션은 데이터베이스 수의 증가에 따라 확장 성이 좋으며 연결 문자열은 코드에서 적절히 추출됩니다. –
@gnibbler - Woah, 파이썬에는 멋진 기능이 있다는 것을 잊었습니다 (http://docs.python.org/reference/compound_stmts.html # the-for-statement) –