【问题标题】:response of `vars(self)` is missing attributes`vars(self)` 的响应缺少属性
【发布时间】:2017-11-29 06:47:52
【问题描述】:

我已经定义了一个类,需要把它的大部分属性交给一个函数来处理。所以我想与其制造一个巨大的混乱并命名它们,我会做processSomething(vars(self)) 并交出一本包含所有属性和值的漂亮字典。

但我发现几乎所有的属性都不见了。

我已经停止了调试器中的代码并运行了一些测试:

>>> vars(self).keys()
dict_keys(['date_expire', 'tokenUrl', 'settings', 'requestSession', 'ttlDays'])

这些是 5 个。虽然我预计有大约 20 个属性,但根据 __slots__ 我的类在这里的定义:

__slots__ = (
    'token',        # the invitation-token to load the username with
    'request',      # the http-request which is currently being serviced
    'inhibit',      
     #... many lines deleted
    'templateObj',  # an instance of myMail.template.Template
    'emailBody',    # what will be sent via SMTP
    'warningsAr',   # messages for the client
)

我可以在调试器窗口中看到属性并且可以直接访问它们。我已阅读 manual of vars() 并找不到任何开关。有趣的是,dir(self) 显示所有属性名称,但没有值。所以我不能用那个。但我认为 vars 和 dir 应该显示相同?

我想我会建立一个解决方法,但我真的很想了解这里发生了什么。你能帮忙吗?

【问题讨论】:

    标签: python python-3.x slots


    【解决方案1】:

    vars() 返回实例的__dict__ 命名空间。但是__slots__ 属性没有存储在__dict__ 命名空间中。这就是他们的全部意义。

    相反,Python 在实例内存结构中为每个值创建专用的指针槽,并在类对象上使用 descriptors 来检索这些值。所以inst.attr 被翻译成type(inst).attr.__get__(inst) 来返回那个值。

    来自__slots__ documentation:

    __slots__ 声明采用一系列实例变量,并在每个实例中保留足够的空间来保存每个变量的值。节省空间是因为 __dict__ 不是为每个实例创建的。

    [...]

    请注意,拥有__dict__ 无论如何 通常表明您忘记让子类对其属性使用__slots__,或者您继承自未使用@ 的基Python 类987654336@ 本身。正确使用__slots__ 应该会导致实例没有__dict__ 命名空间;他们的目标是通过避免字典所需的稀疏哈希表(这会浪费空间)来减少内存。

    再次从文档中:

    • 从没有__slots__ 的类继承时,该类的__dict__ 属性将始终可访问,因此子类中的__slots__ 定义毫无意义。

    [...]

    • __slots__ 声明的操作仅限于定义它的类。因此,子类将具有 __dict__,除非它们还定义了 __slots__(它必须只包含任何其他插槽的名称)。

    如果您想列出所有可用的实例字段,则必须在类中包含 __slots__ 枚举,而不仅仅是查看 vars():

    from itertools import chain
    
    def slots_for_instance(inst):
        def _slots_for_class(c):
            slots = getattr(c, '__slots__', ())
            if isinstance(slots, str):
                # __slots__ can be a string naming a single attribute
                slots = (slots,)
        return set(chain.from_iterable(
            getattr(_slots_for_class(c) for c in type(inst).__mro__))
    

    【讨论】:

    猜你喜欢
    • 2018-04-06
    • 1970-01-01
    • 2018-08-24
    • 2018-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    相关资源
    最近更新 更多