Python 2.7.6:如何正确清理类?

时间:2017-01-30 19:00:14

标签: python-2.7 class

在以下和可执行代码中,您会看到SessionScope() - 类。在main() - 函数中,用户可以登录到他的MySQL数据库服务器。我们来看看课堂。有两种神奇的方法(__enter__, __exit__), 这使我可以使用with语句轻松使用该对象。在此语句中,您还会看到程序使用会话。当__exit__() - 方法是 然后调用会话关闭。但我们知道这会将连接返回到Engine的连接池。这意味着,它不会直接关闭连接, 因为连接正在汇集。到现在为止还挺好。在GUI端,用户可以选择注销。好吧,让我们想象一下:经过非常非常漫长的工作 数据库用户希望连接实际关闭,但他并不希望程序自行关闭。稍后用户可能会再次登录并继续工作。在那之前程序仍在运行而没有连接 数据库。用户不再需要连接。

这意味着对于python,我们不再需要SessionScope() - 类了。在我的情况下,我们可以使用del session_scope删除/清理此类。我的想法是重新实现__del__() - 方法。在这个方法中我想 关闭连接池的所有连接。如果清除/删除此类,则应断开所有连接,这就是我在del() - 函数中使用log_out的原因。

这是正确的方法吗?

TA,你的Sophus

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import SQLAlchemyError

class SessionScope(object):
    def __init__(self, dbms, dbdriver, dbuser, dbuser_pwd, db_server_host, dbport, db_name):

        self.dbms = dbms
        self.dbdriver = dbdriver
        self.dbuser = dbuser
        self.dbuser_pwd = dbuser_pwd
        self.db_server_host = db_server_host
        self.dbport = dbport
        self.db_name = db_name

        url = '{}+{}://{}:{}@{}:{}/{}'.format(
           self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name)

        self.engine = create_engine(url, encoding='utf8', echo=True)

        # store a sessionmaker for this db connection object
        self._Session = sessionmaker(bind=self.engine)
        self.session = None

    def __enter__(self):
        self.session = self._Session()
        return self._Session()

    def __exit__(self, exception, exc_value, traceback):

        try:
            if exception:
                self.session.rollback()
            else:
                self.session.commit()
        finally:

            self.session.close()
            self.session = None

    def __del__(self):
        self.engine.dispose()

def log_out(session_scope):
    del session_scope

def main():
    dbm_system = raw_input("Which DBMS? (type for e.g. mysql): ")
    dbm_driver = raw_input("Which db-driver? (type for e.g. pymysql): ")
    db_host = raw_input("Server-Host: ")
    db_user = raw_input("Database-user: ")
    db_passwd = raw_input("User-Password: ")
    db_name = raw_input("Database Name: ")
    db_port = raw_input("Port: ")

    try:
        session_scope = SessionScope(dbm_system, dbm_driver, db_user, \
                    db_passwd, db_host, db_port, db_name)

        with session_scope as session:
            # Its just for testing.
            print session.execute("SELECT VERSION();")

        log_out(session_scope)

    except SQLAlchemyError as err:
        print "ERROR", err[0]


if __name__ == '__main__':
    main()

编辑#1:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import SQLAlchemyError

class SessionScope(object):
    def __init__(self, engine):

        self.engine = engine

        # store a sessionmaker for this db connection object
        self._Session = sessionmaker(bind=self.engine)
        self.session = None

    def __enter__(self):
        self.session = self._Session()
        return self._Session()

    def __exit__(self, exception, exc_value, traceback):

        try:
            if exception:
                self.session.rollback()
            else:
                self.session.commit()
        finally:

            self.session.close()
            self.session = None

class Engine(object):
    def __init__(self, dbms, dbdriver, dbuser, dbuser_pwd, db_server_host, dbport, db_name):

        self.dbms = dbms
        self.dbdriver = dbdriver
        self.dbuser = dbuser
        self.dbuser_pwd = dbuser_pwd
        self.db_server_host = db_server_host
        self.dbport = dbport
        self.db_name = db_name

        url = '{}+{}://{}:{}@{}:{}/{}'.format(
           self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name)

        self._Engine = create_engine(url, encoding='utf8', echo=True)

    def __enter__(self):
        return self._Engine

    def __exit__(self, exception, exc_value, traceback):
        '''
            Make sure the dbconnection gets closed
        '''
        self._Engine.dispose()

logged_in = True

def main():

    dbm_system = raw_input("Which DBMS? (type for e.g. mysql): ")
    dbm_driver = raw_input("Which db-driver? (type for e.g. pymysql): ")
    db_host = raw_input("Server-Host: ")
    db_user = raw_input("Database-user: ")
    db_passwd = raw_input("User-Password: ")
    db_name = raw_input("Database Name: ")
    db_port = raw_input("Port: ")

    try:
        with Engine(dbm_system, dbm_driver, db_user, \
                    db_passwd, db_host, db_port, db_name) as engine:

            while logged_in:
                with SessionScope(engine) as session:
                    # Its just for testing.
                    print session.execute("SELECT VERSION();")

    except SQLAlchemyError as err:
        print "ERROR", err[0]


if __name__ == '__main__':
    main()

1 个答案:

答案 0 :(得分:2)

__del__方法并非如此。当用户执行del some_instance时,它不会被调用,但是当解释器的垃圾收集器看到没有对该对象的实时引用时。你的log_out方法什么都不做,因为它正在删除的引用是为了将会话作为参数传递给它而创建的额外引用(外部引用仍然存在)。

我怀疑你真的想拥有两个支持上下文管理器协议的不同类。这使您可以拥有两个嵌套的with语句,一个持续整个登录,并且每个数据库会话的持续时间仅为一个。像这样:

with Engine() as engine:
    while logged_in:
        with Session(engine) as session:
            do_stuff()

您可能需要在外部with周围进行另一个循环,以便在您注销后程序不会退出。