Tôi muốn mã của mình tự động thử nhiều cách để tạo kết nối cơ sở dữ liệu. Ngay sau khi một công trình, mã cần phải di chuyển (tức là nó không nên thử các cách khác nữa). Nếu tất cả đều thất bại, thì kịch bản chỉ có thể nổ tung.Thành ngữ Python cho 'Thử cho đến khi không có ngoại lệ nào được nêu ra'
Vì vậy, trong - những gì tôi nghĩ là, nhưng rất có thể là không - một cơn đột quỵ của thiên tài tôi đã cố gắng này:
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
Nhưng có vẻ như thứ hai và tiếp theo trừ báo cáo không bắt OperationalErrors nữa không. Có lẽ bởi vì Python chỉ bắt một ngoại lệ một lần trong một thử ... ngoại trừ tuyên bố?
Vậy sao? Nếu không: có điều gì khác tôi đang làm sai? Nếu vậy: làm thế nào để bạn làm một cái gì đó như thế này sau đó? Có thành ngữ tiêu chuẩn nào không?
(Tôi biết có những cách giải quyết vấn đề này, giống như có người sử dụng xác định các thông số kết nối trên dòng lệnh, nhưng đó không phải là câu hỏi của tôi ok :))
EDIT:
tôi chấp nhận câu trả lời xuất sắc của retracile và tôi đã nhận xét của gnibbler về việc sử dụng cấu trúc for..else. Mã cuối cùng đã trở thành (xin lỗi, tôi không thực sự theo các ký tự tối đa cho mỗi giới hạn dòng từ pep8):
EDIT 2: Như bạn có thể thấy từ nhận xét về lớp Con trỏ: Tôi thực sự không biết cách gọi loại này. Nó không thực sự là một singleton (tôi có thể có nhiều trường hợp khác nhau của con trỏ) nhưng khi gọi get_cursor tôi nhận được cùng một đối tượng con trỏ mọi lúc. Vì vậy, nó giống như một nhà máy singleton? :)
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()
Thay vì khởi tạo 'conn' thành' None', bạn chỉ có thể sử dụng mệnh đề 'else' trên' for' –
+1 @David: ngắt đảm bảo rằng kết nối đầu tiên hoạt động được trả về. Giải pháp này sẽ mở rộng tốt với số lượng cơ sở dữ liệu tăng lên, và các chuỗi kết nối đã được tóm tắt độc đáo từ mã. –
@gnibbler - Woah, tôi quên Python đã có tính năng tuyệt vời đó (http://docs.python.org/reference/compound_stmts.html # the-for-statement) –