函数内报错后局部变量不释放问题
如果在函数内创建数据库连接, 在后续执行其他语句时报错引发异常退出, 那么这个连接将不会被关闭, 如何能获取到这个局部的数据库连接并将它关闭呢虽然应该在函数内部加入try来捕获异常, 加入finally来处理关闭, 或是用with语句, 但是上述问题如果存在的话应该怎么处理呢
在再次对函数进行赋值或删除函数后, 数据库连接关闭了, 那么意味着这个连接是跟函数进行绑定的, 怎么通过这个函数来获取到这个连接?
如:
import psycopg2
def f():
conn = psycopg2.connect(host='xxx', user='xxx', password='xxx')
cursor = conn.cursor()
cursor.execute('select select')
return ba21 发表于 2022-4-7 16:14
就算不想也没别的办法。
你能把全部相关代码写在同一作用域。
或者变向 lst = 存入列表中。把 ...
我如果在函数中输出id(conn), 在报错之后是可以通过内存地址取到这个连接变量的, 问题在于函数内部的局部变量在函数报错后不释放, 就算不是数据库连接, 而是一个列表或字典也是一样的
In : def g():
...: conn =
...: print(id(conn))
...: cursor = conn.cursor()
...: cursor.execute('select select')
...: conn.close()
...: return
...:
In : g()
140065573745480
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-10-5fd69ddb5074> in <module>
----> 1 g()
<ipython-input-9-59a7e29f8a3c> in g()
2 conn =
3 print(id(conn))
----> 4 cursor = conn.cursor()
5 cursor.execute('select select')
6 conn.close()
AttributeError: 'list' object has no attribute 'cursor'
In : get_value = ctypes.cast(140065573745480, ctypes.py_object).value
In : get_value
Out:
In : def h():
...: conn =
...: print(id(conn))
...:
In : h()
140065573750024
In : get_value = ctypes.cast(140065573750024, ctypes.py_object).value
In : get_value
Out: (0, 37) import psycopg2
conn = None # 可变对象只能使用全局变量
def f():
global conn
conn = psycopg2.connect(host='xxx', user='xxx', password='xxx')
cursor = conn.cursor()
cursor.execute('select select')
return ba21 发表于 2022-4-7 15:45
import psycopg2
conn = None # 可变对象只能使用全局变量
def f():
但是我并不想污染全局变量, 只是想把函数中报错产生的残留连接关闭
用类似闭包的方法__closure__获取不到 DetConan 发表于 2022-4-7 16:02
但是我并不想污染全局变量, 只是想把函数中报错产生的残留连接关闭
用类似闭包的方法__closure__获取不 ...
就算不想也没别的办法。
你能把全部相关代码写在同一作用域。
或者变向 lst = 存入列表中。把列表当参数传递,调用同样使用列表来调用 本帖最后由 阿奇_o 于 2022-4-7 16:55 编辑
函数的函数体就是个黑盒子,你是不能读取里面的局部变量的, 所以 除了改为全局变量,还有下面两三种方法:
1. 返回conn对象,这样外部就可以获取
2. 把函数逻辑 改写为 类,类实例里可以将连接对象保存为一个实例变量,如 mc = MyConnection(); mc.conn = psycopg2.connect(...)
或尝试改写为 "描述器"(绑定到类变量上),这样就看你具体需要了。
3. 将连接对象放到容器里,并作为函数的参数,函数体内就可以通过该容器找到需要的连接对象进行操作,类似 操作"连接池", 如
conn_pool = # 这只是示例。经典的处理,我记得好像bottle和flask的是采用一个 栈类实现的,需要一个就生产一个连接。
def getConn(conns = conn_pool): # 这其实相当于改为全局变量的情况
cursor = conns.cursor()
cursor.execute('select select')
补充: 至于报错,可能还要看这个模块psycopg2它在处理异常时,是否进行了抛出,它如果没抛出异常,你函数也不会报异常。 阿奇_o 发表于 2022-4-7 16:44
函数的函数体就是个黑盒子,你是不能读取里面的局部变量的, 所以 除了改为全局变量,还有下面两三种方法: ...
这个我能明白, 不仅是数据库连接的情况, 其他的函数都存在这样的问题, 函数报错后局部变量不释放内存, 在报错后执行gc.collect()也不能回收, 不知道是我的版本问题还是所有版本都有这个问题python3.6.12 而且正因为能通过内存地址取到正确的变量, 我才觉得应该有某种方法能正常获取到这个变量的引用, 不然当引用计数为0时就应该跟不报错时的行为一致, 被gc回收掉了 你说,"函数报错后局部变量不释放内存, 在报错后执行gc.collect()也不能回收", 这。。
疑问一,难道是 conn对象在函数里被创建后,就被固定了(已加载的函数局部变量)。。?
嗯,我想应该是 局部变量应该是和这个函数一起绑定的,函数还在(已定义了,存在于命名空间),那么它里面的局部变量也存在着(只是不能从外部获取和修改)。
疑问二,为啥你要手动 gc.collect() ?? 我是从来没用过这。。
阿奇_o 发表于 2022-4-7 17:11
你说,"函数报错后局部变量不释放内存, 在报错后执行gc.collect()也不能回收", 这。。
疑问一,难道是...
对于疑问一: 确实感觉上是跟函数绑定的, 如果重新定义了函数或删除了函数, 也就释放了里面的局部变量
对于疑问二: 我是感觉自动的垃圾回收可能出问题了, 所以才尝试手动执行, 但实际上垃圾回收并不会处理这部分内容, 可能就像是函数的某个属性一样, 引用计数还在 补充:要拿pg连接的id,可以用 conn.xid(1, "gtrid", "bqual") 我特定查了一下。
其他你自己琢磨吧,很多事语言文字是难以说明白的 ^_ 请看置顶帖中的不释放内存问题~
页:
[1]