Python 用 "with statement" 写我的 class

Python writing my class with "with statement"

我想用 "with as statament" 启动我的 class。我正在使用 pyodbc 模块连接 mssql。

import pyodbc

class Db:
    DRIVER   =  r'DRIVER={ODBC Driver 13 for SQL Server};'
    SERVER   =  r'SERVER=192.168.1.1,1433;'
    DATABASE =  r'DATABASE=Client;'
    USERNAME =  r'UID=sa;' 
    PASSWORD =  r'PWD=1'    

    def __init__(self):
        self.cnxn = pyodbc.connect(self.DRIVER + self.SERVER + self.DATABASE + self.USERNAME + self.PASSWORD)
        self.cursor = self.cnxn.cursor()                

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("__exit__")
        self.cursor.close()
        self.cnxn.close()   


with Db() as d:
    print(d)

上面的代码工作正常,但是当我更改服务器名称时,它崩溃了,我在控制台上看不到 print("exit")。

__exit__方法仅在进入with块时调用。不是 with 语句,而是附加到它的代码块。

如果 Db() 抛出异常,则 __enter____exit__ 都不会被调用。想想看,他们怎么可能呢? Db 对象从未成功构建,因此无法调用其方法。

如果你想修复代码,我会把 DB 连接放在 try except 块中,然后在其中调用 __exit__ 函数。

此外,利用 traceback 将帮助您打印/检索 stacktrace,如果这正是您要查找的内容。

traceback — Print or retrieve a stack traceback
This module provides a standard interface to extract, format and print stack traces of Python programs. It exactly mimics the behavior of the Python

these python docs on traceback

在我的例子中,我只是 运行 你的代码,所以它会抛出 odbc 错误。在您的系统上,您可能会遇到不同的错误。

您修改后的代码

import traceback
import sys

class Db:
    DRIVER   =  r'DRIVER={ODBC Driver 13 for SQL Server};'
    SERVER   =  r'SERVER=192.168.1.1,1433;'
    DATABASE =  r'DATABASE=Client;'
    USERNAME =  r'UID=sa;' 
    PASSWORD =  r'PWD=1'    

    def __init__(self):
        try:
            self.cnxn = pyodbc.connect(self.DRIVER + self.SERVER + \
                        self.DATABASE + self.USERNAME + self.PASSWORD)
        except Exception:
            self.__exit__(sys.exc_info())

        self.cursor = self.cnxn.cursor()                

    def __enter__(self):
        return self

    #def __exit__(self, exc_type, exc_value, traceback):
    def __exit__(self, exc_msg):
        print("__exit__")
        print(exc_msg)
        self.cursor.close()
        self.cnxn.close() 

with Db() as d:
    print(d)

结果

Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 
__exit__
    (<type 'exceptions.NameError'>, NameError("global name 'pyodbc' is not  
  defined",), <traceback object at 0x029ACC60>)