python - 在从 __init__ 调用的函数中声明变量是否仍然使用 key 共享字典?

标签 python python-3.x dictionary python-internals

出于清晰和组织的原因,我尝试始终在 __init__ 中声明类属性。最近,由于PEP 412,我了解到严格遵循这种做法也有额外的非美学好处。为 Python 3.3 添加。具体来说,如果所有属性都在 __init__ 中定义,那么对象可以通过共享它们的键和哈希来减少空间。

我的问题是,当在 __init__ 调用的函数中声明属性时,是否会发生对象 key 共享?

这是一个例子:

class Dog:
    def __init__(self):
        self.height = 5
        self.weight = 25

class Cat:
    def __init__(self):
        self.set_shape()

    def set_shape(self):
        self.height = 2
        self.weight = 10

在这种情况下,Dog 的所有实例将共享键 heightweightCat 的实例是否也共享键 heightweight(彼此之间,当然不是 Dog ).

顺便说一句,您将如何测试它?

请注意,Brandon Rhodes 在他的 Dictionary Even Mightier talk 中谈到了 key 共享:

If a single key is added that is not in the prototypical set of keys, you loose the key sharing

最佳答案

does object key-sharing happen when attributes are declared in a function that is called by __init__?

是的,无论您从何处设置属性,假设在初始化后两者都具有相同的键集,实例字典使用共享键字典实现。两种情况都减少了内存占用。

您可以使用 sys.getsizeof 获取实例字典的大小,然后将其与从中创建的类似字典进行比较,从而对此进行测试。 dict.__sizeof__ 的实现基于此进行区分以返回不同的大小:

# on 64bit version of Python 3.6.1
print(sys.getsizeof(vars(c)))
112
print(getsizeof(dict(vars(c))))
240

所以,要找出答案,您需要做的就是比较这些。

至于您的编辑:

"If a single key is added that is not in the prototypical set of keys, you loose the key sharing"

正确,这是我(目前)发现破坏共享 key 用法的两件事之一:

  1. 在实例字典中使用非字符串键。这只能以愚蠢的方式完成。 (你可以使用 vars(inst).update 来完成)
  2. 同一类的两个实例的字典内容有偏差,可以通过修改实例字典来解决。 (添加到其中的单个键不在原型(prototype)键集中)

    我不确定在添加单个 键时是否会发生这种情况,这是一个可能会更改的实现细节。 (附录:见 Martijn 的评论)

有关这方面的相关讨论,请参阅我在此处进行的问答:Why is the __dict__ of instances so small in Python 3?

这两件事都会导致 CPython 使用“普通”字典。当然,这是不应依赖的实现细节。您可能会或可能不会在 Python 的其他实现和/或 CPython 的 future 版本中找到它。

关于python - 在从 __init__ 调用的函数中声明变量是否仍然使用 key 共享字典?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44705535/

相关文章:

python - 根据条件从现有数据框创建新数据框

Pythonic 方式 : Utility functions in class or module

python - JWT 如何与 django-phonenumber-field 一起工作

python - 如何返回每个分类实例的概率?

python-3.x - 导入 functools 时,pylint 错误 'TreeRebuilder3k' 对象没有属性 'visit_joinedstr'

swift - 我如何将字典作为函数参数传递?

python - 将嵌套字典转换为Python中的列表?

c# - 在我的代码中的字典中使用许多字典

python - 以编程方式逐像素生成视频

python - 正则表达式找到一对相邻的数字,它们周围有不同的数字