【问题标题】:Why does an empty string in Python sometimes take up 49 bytes and sometimes 51?为什么 Python 中的空字符串有时会占用 49 个字节,有时会占用 51 个字节?
【发布时间】:2018-12-22 23:01:23
【问题描述】:

我在三个环境中测试了sys.getsize('')sys.getsize(' '),其中两个sys.getsize('') 给了我51 个字节(比第二个多一个字节)而不是49 个字节:

截图:

Win8 + Spyder + CPython 3.6:

Win8 + Spyder + IPython 3.6:

Win10(VPN 远程)+ PyCharm + CPython 3.7:

第一次编辑

我在 Python.exe 中进行了第二次测试,而不是 Spyder 和 PyCharm(这两个仍然显示 51),一切似乎都很好。显然我没有解决这个问题的专业知识,所以我把它留给你们:)

Win10 + Python 3.7 控制台与 PyCharm 使用相同的解释器:

Win8 + IPython 3.6 + Spyder 使用相同的解释器:

【问题讨论】:

  • 我最迫切的问题是“为什么重要?”。但无论如何,Spyder 也会将其放入共享命名空间
  • @roganjosh 实际上我认为这并不重要,因为我作为数据分析师的工作并没有要求我深入研究对象模型,但我正在摸索以了解背后的原因这。我希望我有其他操作系统,例如Linux 对此进行测试。 BTW 这和你说的“共享命名空间”有关系吗?
  • 我的工作也是数据科学家/数据分析师。这种行为无关紧要,但我不想使您的问题无效(好奇心很好)。 Spyder 有一个复杂的命名空间,你一定已经从你的主脚本观察到控制台中的东西是如何可用的......
  • @AndreyTyukin 不,我只是想看看其他人以前是否遇到过这种奇怪的事情,更重要的是,如果一个空字符串确实比一个字符的字符串多 1 个字节,这意味着我的对字符串对象的理解可能是完全错误的。如果您认为这很正常,那么对不起,因为我不是专业的软件开发人员,这对我来说确实很奇怪。现在我已经解决了这个问题,因为 Python.exe 控制台的第二次测试显示 49。
  • 最有可能的候选者似乎是字符串在第一次需要时缓存使用 UTF-8 编码的版本。

标签: python


【解决方案1】:

这听起来像是在检索字符串对象的 wchar 表示。从 CPython 3.7 开始,CPython Unicode 表示的工作方式,一个空字符串通常存储在“紧凑 ASCII”表示中,64 位构建的紧凑 ASCII 字符串的基本数据和填充工作到 48 个字节,加上一个字节的字符串数据(只是空终止符)。可以看到相关的头文件here

目前(这是 4.0 中的 scheduled for removal),还有一个选项可以检索字符串的 wchar_t 表示。在具有 2 字节 wchar_t 的平台上,空字符串的 wchar 表示为 2 字节(再次只是空终止符)。 wchar 表示在第一次访问时缓存在字符串中,str.__sizeof__ 会在存在时说明这些额外数据,总共 51 个字节。

【讨论】:

  • getsizeof() 在内部确实引用了__sizeof__。这是正确答案
  • @NicholasHumphrey:有些东西正在检索您的 IPython 测试中的 wchar 表示。 (此外,您的 IPython 测试也使用 CPython;CPython 是 IPython 运行的解释器实现。)
  • 这在很大程度上与问题无关,但看到对“[Python] 4.0”的引用让我感到焦虑......
  • @MikeCaron 和其他人:不要害怕。对“4.0”的引用意味着“2.7 支持结束(2020 年 1 月)之后的某个未来版本。一些弃用后的删除已被延迟,以使那些喜欢较小步骤的人更容易迁移。大约 6 年前在 3.3 中弃用的东西可能会在 3.5 中消失。我们不再允许对虚构的“4.0”的新引用。我刚刚在bugs.python.org/issue35616 中建议我们将这项政策“向后移植”到较早的通知,正是为了避免没有人需要的“焦虑”。
  • @KellyBundy:48 个字节,加上 1 个字节的 ASCII 空终止符用于 ASCII 表示,加上 2 个字节的 wchar_t 空终止符用于 wchar_t 表示。
【解决方案2】:

https://docs.python.org/3.5/library/sys.html#sys.getsizeof

sys 是特定于系统的,因此很容易有所不同。这一点常常被大家所忽视。多年来,python 中所有系统特定的东西都被倾倒在 sys 包中。例如,sys.getwindowsversion() 根据定义是不可移植的,但它就在那里。它就像跨平台编码的完美世界中的无底洞。你所看到的是 Python 的一个有趣的块。

来自getsizeof 文档:

只考虑直接归因于对象的内存消耗,而不考虑它所引用的对象的内存消耗。 getsizeof() 调用对象的 __sizeof__ 方法,如果对象由垃圾收集器管理,则会增加额外的垃圾收集器开销。

当使用垃圾收集时,操作系统会添加这些额外的位。如果您阅读 Python 和 GC Q & A When are objects garbage collected in python?,人们已经深入阐述了 GC 以及它将如何影响内存/引用计数和位等等。

我希望这能解释它的来源。如果您不使用system 级别属性而是使用更多pythonic 属性,那么您将获得一致的大小。

【讨论】:

  • 不是GC数据。 GC 永远不会跟踪字符串对象;他们没有这些数据。此外,对于提问者测试的所有配置,相同的对象都会有 GC 数据。
  • 那么我将得到纠正。它可能不是GC。然而,表示上的差异仍然适用并且是系统特定的。可能是操作系统+运行时
猜你喜欢
  • 1970-01-01
  • 2020-07-24
  • 2022-07-06
  • 2019-08-12
  • 2012-03-12
  • 2011-04-26
  • 1970-01-01
  • 2018-09-07
相关资源
最近更新 更多