Python 请求,在 `__del__` 中的请求

huangapple go评论93阅读模式
英文:

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 &#39;__main__&#39;:
    client = Client()
    client.login()

This results in:

File &quot;/Users/me/Library/Python/3.9/lib/python/site-packages/requests/api.py&quot;, line 115, in post
  File &quot;/Users/me/Library/Python/3.9/lib/python/site-packages/requests/api.py&quot;, line 59, in request
  File &quot;/Users/me/Library/Python/3.9/lib/python/site-packages/requests/sessions.py&quot;, line 577, in request
  File &quot;/Users/me/Library/Python/3.9/lib/python/site-packages/requests/sessions.py&quot;, line 759, in merge_environment_settings
  File &quot;/Users/me/Library/Python/3.9/lib/python/site-packages/requests/utils.py&quot;, line 825, in get_environ_proxies
  File &quot;/Users/me/Library/Python/3.9/lib/python/site-packages/requests/utils.py&quot;, line 809, in should_bypass_proxies
  File &quot;/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py&quot;, line 2647, in proxy_bypass
  File &quot;/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py&quot;, line 2624, in proxy_bypass_macosx_sysconf
  File &quot;/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/urllib/request.py&quot;, 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 &quot;with&quot; block
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):  # Called when exiting the &quot;with&quot; 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 &quot;with&quot; 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.

huangapple
  • 本文由 发表于 2023年3月9日 19:02:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/75683701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定