import socket import pymysql class Mydb(object): conn = pymysql.connect(host='location', port=3306, user='root', password='123456', database='socket', charset='utf8' ) cursor = conn.cursor() def __init__(self, name): self.name = name # print(name, '初始化了Mydb类') # cursor.execute('insert into user(name,adder,age,pass) values (%s,%s,%s,%s)') # cursor.close(["张三","上海市浦东新区",20,"123456"]) def __del__(self): print('销毁连接', self.name) self.cursor.close() self.conn.close() def query(self, sql) -> str | int | Exception: try: res = self.cursor.execute(f'{sql}') # 返回执行sql语句后受影响的行数 except Exception as sql_error: return sql_error if res >= 1: return self.cursor.fetchone()[0] else: return res def add(self, sql) -> int | str | Exception: """ :param sql: 更新语句 :return: 返回1为语句执行成功 """ try: res = self.cursor.execute(sql) self.conn.commit() except Exception as update_sql: return update_sql if res >= 0: return 1 else: return f'更新失败: {res}' class SocketSetting(object): def __init__(self, name): self.db = Mydb(name) print(name) self.evn: str = 'server' self.serverip: str = self.get_server_ip() self.clientip: str = self.get_client_ip() def get_server_ip(self): server_ip = socket.gethostbyname(socket.gethostname()) if self.evn == 'server': if self.db.add(f'update socket.ip set server="{server_ip}";') == 1: return server_ip else: return '172.26.120.34' else: return server_ip def get_client_ip(self): res = self.db.query('select server from socket.ip;') print(self.db.name, res) if 11 >= len(res) >= 8: return res else: return '172.26.120.34' class Myoption(object): def __init__(self, name): self.socket = SocketSetting(name) class Run(object): def __init__(self): self.setting = SocketSetting('setting1') self.setting = SocketSetting('setting2') self.setting = SocketSetting('setting3') if __name__ == '__main__': run = Run()
上面的代码执行就会报错,我的理解是三个setting实例化的SocketSetting相互独立连接并不会被影响 ,前面的setting被后面的setting对象覆盖会触发__del__方法 但是不知道这里为什么在setting3时报错了
如果按照下面这种来写就不会报错搞不懂为什么
class Run(object): def __init__(self): self.setting = SocketSetting('setting1') self.setting = SocketSetting('setting2')
在你的代码中,出现了 del 方法导致的异常。这是因为 Python 的垃圾回收机制会自动调用 del 方法来进行对象的清理,但是在某些情况下(比如循环引用),del 方法可能会在不同的顺序和时间点被触发,从而导致异常。
在你的第一个示例中,当 Run 类实例化时,会创建三个 SocketSetting 的实例对象 setting1、setting2 和 setting3。然而,后面的两个对象会覆盖前面的对象,导致前面的对象无法被访问并且会被垃圾回收。
当 setting1 对象被垃圾回收时,会触发 Mydb 类的 del 方法,关闭了数据库连接。然后 setting2 对象被创建,同样触发了 Mydb 类的 del 方法,但此时 Mydb 类中的 self.cursor 和 self.conn 已经被关闭,因此会抛出异常。
要解决这个问题,你可以考虑在 SocketSetting 类的 del 方法中添加对 self.db 的判断,以确保在调用 del 方法时,数据库连接是有效的。例如:
python
Copy code
def del(self):
print('销毁连接', self.name)
if self.db:
self.db.cursor.close()
self.db.conn.close()
这样在 setting2 对象被创建时,虽然 setting1 对象已经被覆盖,但 setting1 对象中的数据库连接不会立即关闭,直到垃圾回收时才会关闭。
但是需要注意的是,使用 del 方法来关闭数据库连接并不是一个理想的做法。更好的方式是在代码中显式地关闭数据库连接,或者使用上下文管理器 (with 语句) 来管理数据库连接的生命周期,以确保在使用完毕后及时释放资源。
另外,建议避免在 del 方法中进行复杂的操作,以防止意外发生。如果可能的话,最好在代码中显式地管理对象的生命周期。
你好,其实对这个问题我还有个疑问在执行时setting3报错了却不是setting2报错 ,setting2虽然覆盖掉了setting1应该触发__del__方法但是解释器没有立即去执行 是因为当时在执行setting2的初始化代码所以解释器因为全局解释锁的关系无法执行吗
大佬能不能帮忙看下我这个分析对吗:https://www.aliyundrive.com/s/KZBkSzHbzs8
1.在Mydb类中,在__del__方法中你尝试关闭了数据库连接和游标,但是你的代码中并没有将conn和cursor作为实例属性进行保存,因此在__del__方法中无法访问这些属性。你可以考虑在__init__方法中将它们保存为实例属性,以便在__del__方法中使用。
2.在SocketSetting类中,你在__init__方法中实例化了一个Mydb对象,但是在后续的代码中并没有使用到这个对象。如果你想在SocketSetting类中使用数据库连接,你需要将db对象作为一个实例属性保存,并在需要的地方使用它。
3.在Run类中,你实例化了多个SocketSetting对象,但是每次实例化都将前一个对象覆盖掉了。因此,在你的代码中只会保留最后一个SocketSetting对象的引用。如果你想在Run类中使用多个SocketSetting对象,可以考虑使用列表或字典等数据结构来保存这些对象。
调整后示例代码,仅供参考:
import pymysql
import socket
class Mydb(object):
def __init__(self, name):
self.name = name
self.conn = pymysql.connect(host='location', port=3306, user='root', password='123456', database='socket', charset='utf8')
self.cursor = self.conn.cursor()
def __del__(self):
print('销毁连接', self.name)
self.cursor.close()
self.conn.close()
def query(self, sql) -> str|int|Exception:
try:
res = self.cursor.execute(sql)
if res >= 1:
return self.cursor.fetchone()[0]
else:
return res
except Exception as sql_error:
return sql_error
def add(self, sql) -> int|str|Exception:
try:
res = self.cursor.execute(sql)
self.conn.commit()
if res >= 0:
return 1
else:
return f'更新失败:{res}'
except Exception as update_sql:
return update_sql
class SocketSetting(object):
def __init__(self, name):
self.name = name
self.db = Mydb(name)
print(name)
self.evn:str = 'server'
self.serverip:str = self.get_server_ip()
self.clientip:str = self.get_client_ip()
def get_server_ip(self):
server_ip = socket.gethostbyname(socket.gethostname())
if self.evn == 'server':
if self.db.add(f'update socket.ip set server="{server_ip}";') == 1:
return server_ip
else:
return '172.26.120.34'
else:
return server_ip
def get_client_ip(self):
res = self.db.query('select server from socket.ip;')
print(self.db.name, res)
if 11 >= len(res) >= 8:
return res
else:
return '172.26.120.34'
class Myoption(object):
def __init__(self, name):
self.socket = SocketSetting(name)
class Run(object):
def __init__(self):
self.settings = []
self.settings.append(SocketSetting('setting1'))
self.settings.append(SocketSetting('setting2'))
self.settings.append(SocketSetting('setting3'))
大佬能不能帮忙看下我这个解析对吗:https://www.aliyundrive.com/s/KZBkSzHbzs8