python - 为什么 "__iadd__"在与 "__getitem__"和 "__getattr__"一起使用时表现不同

标签 python

使用以下代码:

class X( object ):

    def __init__( self ):
        self.value = 0

    def __iadd__( self, value ):
        self.value += value
        return self

class Y( object ):

    def __init__( self ):
        self.fields = { 'test': X() }

    def __getitem__( self, key ):
        return( self.fields[ key ] )

    def __getattr__( self, key ):
        return self.fields[ key ]

obj = Y()

obj.test += 1

print( obj.test.value )

obj['test'] += 1

print( obj.test.value )

__iadd____getattr__ 一起使用会起作用,但是在使用 __getitem__ 时会出现错误:

TypeError: 'Y' object does not support item assignment

发生。

我知道 __iadd__ 实际上是 x = x.__iadd__(y),但是我不知道为什么它不能与 __getitem__ 一起使用

谢谢。

最佳答案

obj.test += 1 工作的原因是 obj.__setattr__ 有一个允许它工作的默认实现(虽然可能不是你想要的方式工作)——即,它在实例字典中存储对返回的 X 对象的引用。您可以通过以下方式观看它的发生:

>>> obj = Y()
>>> obj.test
<__main__.X object at 0x0000024BF247B220>
>>> obj.__dict__
{'fields': {'test': <__main__.X object at 0x0000024BF247B220>}}
>>> obj.test += 1
>>> obj.__dict__
{'fields': {'test': <__main__.X object at 0x0000024BF247B220>}, 'test': <__main__.X object at 0x0000024BF247B220>}

请注意,现在有一个 test 属性 在您的 fields 字典之外!两个字典都指向的仍然只有一个 X 对象(因为你的 __iadd__ 返回了 self,没有新的 X 曾经被创造过)。

当你执行 obj.test += 1 时,发生的事情是:

obj.__setattr__("test", obj.__getattr__("test").__iadd__(1))

__setattr__ 调用在 obj.__dict__ 中创建新的“测试”条目。

相反,当您执行 obj["test"] += 1 时,这将转化为:

obj.__setitem__("test", obj.__getitem__("test").__iadd__(1))

__setitem__ 引发了异常——与 __setattr__ 不同,没有默认的 object.__setitem__ 允许 obj[ "test"] = obj["test"] + 1 开始工作。

关于python - 为什么 "__iadd__"在与 "__getitem__"和 "__getattr__"一起使用时表现不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71858949/

相关文章:

python - Matlab filter() 与 SciPy lfilter()

python - 在 BaseHTTPServer 中启动守护进程

python - 在列表(表)的列表中打印字符串

python - 为什么 Python 中存在这种涉及异步的奇怪语法?

python - Scipy 的复数最小平方

python - 用于 python 脚本的 shebang 在 pyenv virtualenv 下运行

python - 在 matplotlib 中动态更新堆积条形图

python - OAuthException : Invalid response from google

python - django迁移中如何获取当前数据库?

python - 为什么导入对我不起作用? - Python