【问题标题】:Why use getattr instead of hasattr for sys.frozen?为什么对 sys.frozen 使用 getattr 而不是 hasattr?
【发布时间】:2019-12-08 17:54:24
【问题描述】:

我能找到的每个文档和答案都说,为了检查程序是否“冻结”(例如 exe),我们可以通过以下方式使用getattr(sys, 'frozen', False)

import sys
if getattr(sys, 'frozen', False):
    print('program is frozen exe')
else:
    print('program is a .py script')

如果frozen 属性不存在而不是抛出AttributeError,则默认返回False。来自控制台的示例:

>>> getattr(sys, 'frozen')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'sys' has no attribute 'frozen'
>>> getattr(sys, 'frozen', False)
False
>>> hasattr(sys, 'frozen')
False

这一切都很好,但是有一个较短的版本可以完成相同的工作,除非我遗漏了什么:

hasattr(sys, 'frozen')

它只返回TrueFalse 而无需指定默认值。尽管这更短并且可能更具可读性,但每个在线文档和答案都使用 getattr 代替。我确信我可能忽略了一个聪明的区别,这就是我问这个问题的原因。

引用getattr的示例来源:

【问题讨论】:

  • hasattr 只会告诉您该属性是否存在,如果存在则不会返回其值。
  • 添加到@ThierryLathuille 的答案,因此通过使用getattr,您将获得frozen 属性的值,如果它是True,则只执行if 部分。如果你想使用 hasattr,请使用 if hasattr(sys,'frozen') and sys['frozen']:
  • 如果属性存在且其值为False...?
  • 我明白你的意思。是否有任何示例说明何时强制 sys.frozen 存在并成为 False 有用?或者任何可以做到这一点的包/扩展/程序?
  • 感谢您的提问,我发现PyInstaller 手册中缺少True,导致运行时出错:pyinstaller.readthedocs.io/en/stable/runtime-information.html

标签: python pyinstaller executable cx-freeze sys


【解决方案1】:

PyInstaller 文档本身使用getattr 样式的代码块here,因此通过复制粘贴效果,它会激增。

那么问题就变成了:为什么 PyInstaller 文档会这样做呢?正如其他人在 cmets 中所说,sys.frozen 理论上可以设置为False 或其他一些falsy 值,在这种情况下,hasattr(sys, 'frozen') 仍将返回True

>>> class Stuff:
...     pass
... 
>>> x = Stuff()
>>> x.yes = True
>>> hasattr(x, 'yes')
True
>>> getattr(x, 'yes', False)
True
>>> x.no = False
>>> hasattr(x, 'no')
True
>>> getattr(x, 'no', False)
False

但是,正如 PyInstaller 所使用的那样,是否可以设置 sys.frozen,但使用虚假值?让我们查看源代码:

$ git clone git://github.com/pyinstaller/pyinstaller
Cloning into 'pyinstaller'...
...
$ cd pyinstaller
$ git grep '\(sys\.frozen\|frozen = \)' PyInstaller
PyInstaller/loader/pyiboot01_bootstrap.py:    sys.frozen = True
PyInstaller/utils/win32/winutils.py:            # True if "sys.frozen" is currently set.
PyInstaller/utils/win32/winutils.py:            is_sys_frozen = hasattr(sys, 'frozen')
PyInstaller/utils/win32/winutils.py:            # Current value of "sys.frozen" if any.
PyInstaller/utils/win32/winutils.py:            sys_frozen = getattr(sys, 'frozen', None)
PyInstaller/utils/win32/winutils.py:            sys.frozen = '|_|GLYH@CK'
PyInstaller/utils/win32/winutils.py:            # If "sys.frozen" was previously set, restore its prior value.
PyInstaller/utils/win32/winutils.py:                sys.frozen = sys_frozen
PyInstaller/utils/win32/winutils.py:                del sys.frozen

所以这个变量只在两种情况下设置:

  1. True,同时加载/引导;和
  2. '|_|GLYH@CK' 临时在一个实用方法中。

它永远不会从 PyInstaller 收到虚假值。

所以在实践中,使用hasattr(sys, 'frozen') 可以正常工作。从正确性的角度来看,它只是感觉不对,因为它是一个处理不正确的边缘情况,这可能是 PyInstaller 文档使用getattr 的原因:它更多的是future-proof

【讨论】:

    猜你喜欢
    • 2014-09-18
    • 1970-01-01
    • 2018-08-03
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    • 2011-05-03
    相关资源
    最近更新 更多