Python 3.x 在Python中使用`with`时,如何处理数据库类中的连接错误?

Python 3.x 在Python中使用`with`时,如何处理数据库类中的连接错误?,python-3.x,class,psycopg2,Python 3.x,Class,Psycopg2,在下面的数据库类中,如果连接失败,将打印我的错误。但是,系统错误也会打印出来,因为\uuuu退出\uuu代码触发 AttributeError:“数据库”对象没有属性“\u conn” 我应该如何处理这种情况? 试试/除了还是有更好的方法 import psycopg2 import mysecrets as ms from time import time class Database(object): def __init__(self, localhost=False):

在下面的数据库类中,如果连接失败,将打印我的错误。但是,系统错误也会打印出来,因为
\uuuu退出\uuu
代码触发

AttributeError:“数据库”对象没有属性“\u conn”

我应该如何处理这种情况?
试试/除了
还是有更好的方法

import psycopg2
import mysecrets as ms
from time import time


class Database(object):
    def __init__(self, localhost=False):
        try:
            print(f"ATTEMPTING DATABASE CONNECTION")
            self._conn = psycopg2.connect(
                f"""
                dbname =    {ms.LOCALDB_NAME if localhost else ms.DB_NAME}
                port =      {ms.LOCALDB_PORT if localhost else ms.DB_PORT}
                user =      {ms.LOCALDB_USER if localhost else ms.DB_USER}
                password =  {ms.LOCALDB_PASS if localhost else ms.DB_PASS}
                host =      {ms.LOCALDB_HOST if localhost else ms.DB_HOST}
                """
            )
            self._cursor = self._conn.cursor()
            print(f"CONNECTED TO DATABASE\n")
        except Exception as error:
            print(f"UNABLE TO CONNECT TO DATABASE\n{error}")

    def __enter__(self):
        return self

    def __del__(self):
        self.connection.close()

    def __exit__(self, exc_type, exc_value, traceback):
        self.connection.close()

    @property
    def connection(self):
        return self._conn

    @property
    def cursor(self):
        return self._cursor

    def commit(self):
        self.connection.commit()

    def query(self, sql, params=None):
        self.cursor.execute(sql, params or ())

    def fetchall(self):
        return self.cursor.fetchall()

    def fetchone(self):
        return self.cursor.fetchone()


if __name__ == "__main__":
    start_time = time()

    with Database() as db:
        elapsed_time = round(time() - start_time, 2)
        print(f"Testing database connection took {elapsed_time} seconds.")

在这种情况下,您可以先初始化
self.\u conn
,然后再尝试
,作为
self.\u conn=None
,这样它就存在了。然后,在
\uu退出\uuu
关闭
等处,用

if self._conn is not None:
    self._conn.close()
    self._conn = None

然而,我认为这不是一个好的设计,因为它忽略了一般的
异常
错误。这可能不是连接错误。即使是这样,最终也会得到一个未初始化的对象。这没有用,会导致以后的错误。最好早点抓住它们,让它从
\uuuu init\uuuuu
传递,让任何实例化它的东西来处理它

在这种情况下,您可以在
尝试之前,首先将
self.\u conn
初始化为
self.\u conn=None
,这样它就存在了。然后,在
\uu退出\uuu
关闭
等处,用

if self._conn is not None:
    self._conn.close()
    self._conn = None

然而,我认为这不是一个好的设计,因为它忽略了一般的
异常
错误。这可能不是连接错误。即使是这样,最终也会得到一个未初始化的对象。这没有用,会导致以后的错误。最好早点抓住它们,让它从
\uuuu init\uuuuu
传递,让任何实例化它的东西来处理它

首先,捕获异常而不是特定错误是一种反模式。 在Python中,您应该知道从函数中抛出了哪些异常,并相应地处理它们

其次,如果对
psycopg2.connect
\u conn.cursor()
的调用引发任何错误,那么代码将捕获异常,并且实例变量
\u conn
\u cursor
从未设置。 这就是您的
属性错误的原因

在我看来,正确的处理方法是引发错误,如果数据库类无法连接到数据库,或者让使用该类的任何代码处理错误,则不要继续执行

class Database(object):
    def __init__(self, localhost=False):
        try:
            print(f"ATTEMPTING DATABASE CONNECTION")
            self._conn = psycopg2.connect(
                f"""
                dbname =    {ms.LOCALDB_NAME if localhost else ms.DB_NAME}
                port =      {ms.LOCALDB_PORT if localhost else ms.DB_PORT}
                user =      {ms.LOCALDB_USER if localhost else ms.DB_USER}
                password =  {ms.LOCALDB_PASSWORD if localhost else ms.DB_PASSWORD}
                host =      {ms.LOCALDB_HOST if localhost else ms.DB_HOST}
                """
            )
            self._cursor = self._conn.cursor()
            print(f"CONNECTED TO DATABASE\n")
        except psycopg2.Error as error:
            raise ValueError(f"UNABLE TO CONNECT TO DATABASE\n{error}") from None

可能有比
ValueError
更好的异常可供使用。

首先,捕获
异常而不是特定错误是一种反模式。
在Python中,您应该知道从函数中抛出了哪些异常,并相应地处理它们

其次,如果对
psycopg2.connect
\u conn.cursor()
的调用引发任何错误,那么代码将捕获异常,并且实例变量
\u conn
\u cursor
从未设置。 这就是您的
属性错误的原因

在我看来,正确的处理方法是引发错误,如果数据库类无法连接到数据库,或者让使用该类的任何代码处理错误,则不要继续执行

class Database(object):
    def __init__(self, localhost=False):
        try:
            print(f"ATTEMPTING DATABASE CONNECTION")
            self._conn = psycopg2.connect(
                f"""
                dbname =    {ms.LOCALDB_NAME if localhost else ms.DB_NAME}
                port =      {ms.LOCALDB_PORT if localhost else ms.DB_PORT}
                user =      {ms.LOCALDB_USER if localhost else ms.DB_USER}
                password =  {ms.LOCALDB_PASSWORD if localhost else ms.DB_PASSWORD}
                host =      {ms.LOCALDB_HOST if localhost else ms.DB_HOST}
                """
            )
            self._cursor = self._conn.cursor()
            print(f"CONNECTED TO DATABASE\n")
        except psycopg2.Error as error:
            raise ValueError(f"UNABLE TO CONNECT TO DATABASE\n{error}") from None

可能有比使用
ValueError
更好的异常。

Hi Keith。你的意思是“让任何实例化它的东西来处理它”吗?是的。要么让psycopg2错误通过,要么提出一个可能对你的应用程序更有意义的错误。但是,我会使用
。。。来自错误
,而不是
。。。从“无”
,这样您就不会丢失基线原因。嗨,基思。你的意思是“让任何实例化它的东西来处理它”吗?是的。要么让psycopg2错误通过,要么提出一个可能对你的应用程序更有意义的错误。但是,我会使用
。。。来自错误
,而不是
。。。从“无”
,这样您就不会丢失参考底图原因。