【问题标题】:__setattr__ to prohibit changes to instance/self variables?__setattr__ 禁止更改实例/自变量?
【发布时间】:2021-10-20 07:19:17
【问题描述】:

我有一个 Fraction 类,它的 init 创建实例变量 self.num = numself.denom=denom

    def __init__(self,num=0,denom=1):
        assert isinstance(num, int), "Numerator and denominator must be an integer"
        assert isinstance(denom, int), "Numerator and denominator must be an integer"
        assert denom != 0, "Denominator cannot be 0."
        self.num = num
        self.denom = denom

我正在尝试编写它的__setattr__ 方法,以禁止通过引发 NameError 初始化实例变量后对其进行更改:

    def __setattr__(self,name,value):
        if name not in Fraction.__dict__:
            self.__dict__[name] = value
        else:
            raise NameError

通过打印Fraction.__dict__,我可以看到 dict 包含 Fractions 方法,而不是 num、denom 及其各自的值。所以我然后尝试这样做:if name not in Fraction().__dict__:,我最终遇到了无限递归错误。如何访问包含实例变量的字典?

【问题讨论】:

  • 听起来你想要self.__dict__if 中,而不仅仅是在以后的作业中。
  • 成员 numdenum 绑定到您的类的实例。因此,您必须使用self.__dict__ 而不是Fraction.__dict__
  • 你也可以使用 drozen 数据类。
  • 啊,我不敢相信我忽略了这一点。标记的答案和这些 cmets 都以不同的方式解决了我的问题。谢谢大家。

标签: python class setattr


【解决方案1】:

您应该改用__slots__ 来将属性限制在您想要的范围内。

https://docs.python.org/3/reference/datamodel.html#slots

__slots__ 允许我们显式声明数据成员(如属性)并拒绝创建 __dict____weakref__(除非在 __slots__ 中显式声明或在父级中可用。)

[...] 如果没有__dict__ 变量,则无法为实例分配__slots__ 定义中未列出的新变量。尝试分配给未列出的变量名称会引发 AttributeError。 [...]

所以基本上在你的班级中添加这个,最好是在顶部的某个地方(就在class 行之后和 init 之前):

__slots__ = 'num', 'denom'

并删除您的 setattr :)

【讨论】:

  • 我明白了。这也简单得多。谢谢。
  • 当心。插槽并非旨在防止向对象添加新属性,而是一种优化功能 - 请阅读有关这一点的官方 Python 文档。具体来说,子类将获得一个__dict__ 特殊属性,该属性将允许动态创建新属性。
  • @SergeBallesta 文档链接已经在我的回答中,我只引用了与问题相关的部分。 :) 但至于你提到的,来自那些相同的文档:The action of a __slots__ declaration is not limited to the class where it is defined. __slots__ declared in parents are available in child classes. However, child subclasses will get a __dict__ and __weakref__ unless they also define __slots__ (which should only contain names of any additional slots).
猜你喜欢
  • 2017-09-10
  • 1970-01-01
  • 2016-05-07
  • 2016-12-19
  • 2014-10-21
  • 1970-01-01
  • 1970-01-01
  • 2020-08-24
相关资源
最近更新 更多