英文:
Python requests, request in __del__
问题
我正在为某个应用程序构建API客户端包装器。
因此,我创建了一个Client类来处理请求。
我尝试在析构函数中发送注销请求,以便如果程序结束时不会忘记注销。
这是我尝试过的:
```python
import requests
class Client:
def __init__(self):
# 一些初始化操作
def login(self):
requests.get(login_url_path, headers=some_headers)
def logout(self):
requests.post(logout_url_path, headers=some_headers)
def __del__(self):
self.logout()
if __name__ == '__main__':
client = Client()
client.login()
结果显示:
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/api.py", line 115, in post
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/api.py", line 59, in request
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/sessions.py", line 577, in request
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/sessions.py", line 759, in merge_environment_settings
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/utils.py", line 825, in get_environ_proxies
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/utils.py", line 809, in should_bypass_proxies
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 2647, in proxy_bypass
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 2624, in proxy_bypass_macosx_sysconf
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 2566, in _proxy_bypass_macosx_sysconf
ImportError: sys.meta_path is None, Python is likely shutting down
问题似乎是当析构函数被调用时,由于Python正在关闭,某些导入不再存在。
这是否是一个预期的问题?有没有解决方法?
<details>
<summary>英文:</summary>
I am building an API client wrapper for some application.
Therefore I created a Client class that will handle the requests.
I was trying to send a logout request in the destructor, such that logout can not be forgotten if the program is ended.
Here is what I tried:
```python
import requests
class Client:
def __init__(self):
# some stuff
def login(self):
requests.get(login_url_path, headers=some_headers)
def logout(self):
requests.post(logout_url_path, headers=some_headers)
def __del__(self):
self.logout()
if __name__ is '__main__':
client = Client()
client.login()
This results in:
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/api.py", line 115, in post
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/api.py", line 59, in request
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/sessions.py", line 577, in request
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/sessions.py", line 759, in merge_environment_settings
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/utils.py", line 825, in get_environ_proxies
File "/Users/me/Library/Python/3.9/lib/python/site-packages/requests/utils.py", line 809, in should_bypass_proxies
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 2647, in proxy_bypass
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 2624, in proxy_bypass_macosx_sysconf
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 2566, in _proxy_bypass_macosx_sysconf
ImportError: sys.meta_path is None, Python is likely shutting down
The problem appears to be that some imports no longer exit when the destructor is called as python is shutting down.
Is this an expected issue? Is there a work around?
答案1
得分: 0
关于__del__()
方法的详细信息,请参见以下问题链接:
https://stackoverflow.com/q/1481488/5040035
简而言之,当对象实例被垃圾回收时,__del__()
方法会被调用。在您的示例中,当脚本结束并且解释器开始关闭时,会发生这种情况,此时后者的状态是不可预测的。
如果您希望在不再需要Client实例后确保进行一些清理操作,一种常见的方法是为其添加上下文管理器功能,示例如下:
class Client:
...
def __enter__(self): # 进入“with”块时调用
return self
def __exit__(self, exc_type, exc_val, exc_tb): # 退出“with”块时调用
self.logout()
然后,您可以像这样使用客户端实例:
with Client() as client_instance:
client_instance.login()
# 使用客户端执行其他操作...
# 在退出“with”块后,我们知道
# client_instance.__exit__() 已经被调用。
通过这种方式使用客户端,您可以确保在脚本不再需要它时自动调用logout()
。
英文:
For details on the __del__()
method, see the following question:
https://stackoverflow.com/q/1481488/5040035
In short, __del__()
is called when an object instance is garbage collected. In your example this happens when your script comes to an end and the interpreter starts shutting down, at which point the latter's state is unpredictable.
If you want to make sure some cleanup operation takes place after the Client instance is no longer needed, a common approach is to add context manager capabilities to it, example:
class Client:
...
def __enter__(self): # Called upon entering the "with" block
return self
def __exit__(self, exc_type, exc_val, exc_tb): # Called when exiting the "with" block
self.logout()
Then you can use a client instance like this:
with Client() as client_instance:
client_instance.login()
# and some more stuff using the client...
# After exiting the "with" block, we know that
# client_instance.__exit__() has already been called.
By using the client like this, you assure that logout()
is automatically called when the script no longer needs it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论