我真的被上下文管理器 (__enter__ & __exit__) 和 mysql.connector 困住了,但有一个错误
I really got stuck about context managers (__enter__ & __exit__) and mysql.connector with an error
我写了一个 class 来从 MySQL 数据库收集数据。
当我使用 with
.
时,我不明白如何使用 __enter__
和 __exit__
方法
更具体的我没看懂:
我应该在哪里 return self.raws = self.crouser.execute(self.que)
实际上是数据库中的数据。
连接打开到什么时候?
如何在这个具体问题中使用with
方法?
我的代码:
import mysql.connector
class tak:
def __init__(self,host1, user1, password1, db1,aat, que1):
self.host = host1
self.user = user1
self.password = password1
self.database = db1
self.auth_plugin = aat
self.que = que1
def co(self):
try:
self.my = mysql.connector.connect(
host = self.host,
user = self.user,
password = self.password,
database = self.database,
auth_plugin = self.auth_plugin,
charset = 'utf8'
)
except mysql.connector.errors as err :
print(f'{err}')
self.crouser = self.my.cursor()
self.raws = self.crouser.execute(self.que)
self.crouser.fetchall()
def __enter__(self):
return
def __exit__(self, exc_type, exc_val, exc_tb):
self
with tak(host1="localhost",
user1="root",
password1="1234",
db1="local_db",
aat='mysql_native_password',
que1='select * from nand').co() as log:
print(log)
您应该在 __enter__
方法中执行所有初始化并使它 return 上下文管理器实例,并且您应该在 __exit__
方法中执行清理:
class tak:
def __init__(self,host1, user1, password1, db1,aat, que1):
self.host = host1
self.user = user1
self.password = password1
self.database = db1
self.auth_plugin = aat
self.que = que1
def __enter__(self):
try:
self.my = mysql.connector.connect(
host = self.host,
user = self.user,
password = self.password,
database = self.database,
auth_plugin = self.auth_plugin,
charset = 'utf8'
)
except mysql.connector.errors as err :
print(f'{err}')
self.crouser = self.my.cursor()
self.raws = self.crouser.execute(self.que)
self.crouser.fetchall()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.my.close()
以便您可以直接将其实例化为上下文管理器:
with tak(host1="localhost",
user1="root",
password1="1234",
db1="local_db",
aat='mysql_native_password',
que1='select * from nand') as log:
# do something with log here
下面大量解释:
__enter__
准备东西(打开应该稍后关闭的东西等)。如果你想做with ... as ...
,那么返回的对象应该是你想在as ...
中得到的对象(通常是self
,但不一定是)。
__exit__
应该清理东西 - 关闭应该关闭的东西,重新分配它们的原始值...
我不知道您为什么已经在构造函数中执行查询。 经典方式是:__enter__
打开连接,__exit__
关闭。然后任何查询都在块中。
与文件操作比较:
f = open(filename)
data = f.readlines()
f.close()
变为:
with open(filename) as f: # __enter__ returns self
data = f.readlines()
# we exit the block, so __exit__ is performed - it does f.close() for us
虽然您的代码更像...
with open_and_read(filename) as data:
# ????? do something with data I guess?
你就是这样做的:打开东西并做一件预定义的事情......并获得不可关闭的东西,这样它就可以活得更久(现在它只存在于 with
块中)。
如果这真的是你想要的,那么完全放弃上下文管理器:只做一个打开连接、获取查询、关闭连接的函数,returnslog
。
但是如果你想要一个正确的上下文管理器,它可能看起来像这样:
import mysql.connector
class tak :
def __init__(self,host1, user1, password1, db1,aat): #removed query
self.host = host1
self.user = user1
self.password = password1
self.database = db1
self.auth_plugin = aat
# self.que = que1 nope, we don't want it here
def __enter__(self):
self.my = mysql.connector.connect(
host = self.host,
user = self.user,
password = self.password,
database = self.database,
auth_plugin = self.auth_plugin,
charset = 'utf8'
)
return self.my.cursor()
def __exit__(self, exc_type, exc_val, exc_tb):
self.my.close()
# now we can get database info once but open the connection multiple times
db = tak(...)
with db as cur: # our __enter__ returns the cursor
cur.execute(...)
data1 = cur.fetchall()
# as we exit the block, __exit__ is called
# do something with data1
with db as cur: # open new connection, return new cursor
cur.execute(...)
...
...
[我还没有测试这段代码,它可能需要一些调整。我回答的重点是解释上下文管理器的正确用法,而不是给出完美的代码。]
我写了一个 class 来从 MySQL 数据库收集数据。
当我使用 with
.
__enter__
和 __exit__
方法
更具体的我没看懂:
我应该在哪里 return
self.raws = self.crouser.execute(self.que)
实际上是数据库中的数据。连接打开到什么时候?
如何在这个具体问题中使用
with
方法?
我的代码:
import mysql.connector
class tak:
def __init__(self,host1, user1, password1, db1,aat, que1):
self.host = host1
self.user = user1
self.password = password1
self.database = db1
self.auth_plugin = aat
self.que = que1
def co(self):
try:
self.my = mysql.connector.connect(
host = self.host,
user = self.user,
password = self.password,
database = self.database,
auth_plugin = self.auth_plugin,
charset = 'utf8'
)
except mysql.connector.errors as err :
print(f'{err}')
self.crouser = self.my.cursor()
self.raws = self.crouser.execute(self.que)
self.crouser.fetchall()
def __enter__(self):
return
def __exit__(self, exc_type, exc_val, exc_tb):
self
with tak(host1="localhost",
user1="root",
password1="1234",
db1="local_db",
aat='mysql_native_password',
que1='select * from nand').co() as log:
print(log)
您应该在 __enter__
方法中执行所有初始化并使它 return 上下文管理器实例,并且您应该在 __exit__
方法中执行清理:
class tak:
def __init__(self,host1, user1, password1, db1,aat, que1):
self.host = host1
self.user = user1
self.password = password1
self.database = db1
self.auth_plugin = aat
self.que = que1
def __enter__(self):
try:
self.my = mysql.connector.connect(
host = self.host,
user = self.user,
password = self.password,
database = self.database,
auth_plugin = self.auth_plugin,
charset = 'utf8'
)
except mysql.connector.errors as err :
print(f'{err}')
self.crouser = self.my.cursor()
self.raws = self.crouser.execute(self.que)
self.crouser.fetchall()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.my.close()
以便您可以直接将其实例化为上下文管理器:
with tak(host1="localhost",
user1="root",
password1="1234",
db1="local_db",
aat='mysql_native_password',
que1='select * from nand') as log:
# do something with log here
下面大量解释:
__enter__
准备东西(打开应该稍后关闭的东西等)。如果你想做with ... as ...
,那么返回的对象应该是你想在as ...
中得到的对象(通常是self
,但不一定是)。
__exit__
应该清理东西 - 关闭应该关闭的东西,重新分配它们的原始值...
我不知道您为什么已经在构造函数中执行查询。 经典方式是:__enter__
打开连接,__exit__
关闭。然后任何查询都在块中。
与文件操作比较:
f = open(filename)
data = f.readlines()
f.close()
变为:
with open(filename) as f: # __enter__ returns self
data = f.readlines()
# we exit the block, so __exit__ is performed - it does f.close() for us
虽然您的代码更像...
with open_and_read(filename) as data:
# ????? do something with data I guess?
你就是这样做的:打开东西并做一件预定义的事情......并获得不可关闭的东西,这样它就可以活得更久(现在它只存在于 with
块中)。
如果这真的是你想要的,那么完全放弃上下文管理器:只做一个打开连接、获取查询、关闭连接的函数,returnslog
。
但是如果你想要一个正确的上下文管理器,它可能看起来像这样:
import mysql.connector
class tak :
def __init__(self,host1, user1, password1, db1,aat): #removed query
self.host = host1
self.user = user1
self.password = password1
self.database = db1
self.auth_plugin = aat
# self.que = que1 nope, we don't want it here
def __enter__(self):
self.my = mysql.connector.connect(
host = self.host,
user = self.user,
password = self.password,
database = self.database,
auth_plugin = self.auth_plugin,
charset = 'utf8'
)
return self.my.cursor()
def __exit__(self, exc_type, exc_val, exc_tb):
self.my.close()
# now we can get database info once but open the connection multiple times
db = tak(...)
with db as cur: # our __enter__ returns the cursor
cur.execute(...)
data1 = cur.fetchall()
# as we exit the block, __exit__ is called
# do something with data1
with db as cur: # open new connection, return new cursor
cur.execute(...)
...
...
[我还没有测试这段代码,它可能需要一些调整。我回答的重点是解释上下文管理器的正确用法,而不是给出完美的代码。]