在 Python 中使用重载加法运算符时出现内存错误
Posted
技术标签:
【中文标题】在 Python 中使用重载加法运算符时出现内存错误【英文标题】:Memory error when using overloaded addition operator in Python 【发布时间】:2021-05-21 11:38:55 【问题描述】:我在P1
类中重载了加法运算符,使实例可以直接相加。但是,在执行p1 + p2
时会发生内存错误。 p1.data + p2.data
可以给出正确的结果。
class P1:
def __init__(self):
self.data = np.zeros((512,512),dtype='float64')
def __setitem__(self, key, value):
self.data[key] = value
def __getitem__(self, item):
return self.data[item]
def __add__(self, other):
return self.data + other
def __radd__(self, other):
return other + self.data
p1 = P1()
p2 = P1()
p1 + p2
Traceback (most recent call last):
File "D:\professional\Anaconda_install\lib\site-packages\IPython\core\interactiveshell.py", line 3418, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-224-a0c3d63f397c>", line 1, in <module>
p1 + p2
File "<ipython-input-221-ba43c19b29b0>", line 12, in __add__
return self.data + other
File "<ipython-input-221-ba43c19b29b0>", line 15, in __radd__
return other + self.data
MemoryError: Unable to allocate 2.00 MiB for an array with shape (512, 512) and data type float64
谁能帮我解释一下?
【问题讨论】:
【参考方案1】:发生过载是因为您在 __add__
和 __radd__
中说的是 other
而不是 other.data
,这会创建一个 Feedback Loop。
具体来说,您首先调用p1.__add__(p2)
,这会导致解释器查找p2.__radd__(p1)
,这会重复该过程,因为p2.__radd__(p1)
会查找p1.__add__(p2)
。
也就是说,它永远不会返回,因为它会查找内容,在找到更多数据后保存值以完成计算,并在这个无休止的过程中耗尽可用内存。
解决方案:
import numpy as np
class P1:
def __init__(self):
self.data = np.zeros((512,512),dtype='float64')
def __setitem__(self, key, value):
self.data[key] = value
def __getitem__(self, item):
return self.data[item]
def __add__(self, other):
# return self.data + other.data
return np.array([*self.data, *other.data])
def __radd__(self, other):
# return other.data + self.data
return np.array([*other.data, *self.data])
虽然从技术上讲,您可以只交换__add__
或__radd__
之一,并且运算符重载仍然有效。
【讨论】:
感谢您的解释。为什么当 self.data 是一个值时它会起作用,而当 self.data 是一个数组时它会失败?您能否详细解释一下当口译员致电p2.__radd__(p1)
和p1.__add__(p2)
时会发生什么?
因为 python 列表没有__radd__
属性。我个人无法详细介绍解释器,但 __add__
和 __radd__
只是“魔术”或“dunder”(双下划线)方法,它们为拥有它们的类提供了 @987654338 的“语法糖” @ 和 b + a
,分别。每当您在对象上使用运算符符号时,解释器都会查找其魔术方法,以便它知道要做什么。如果找不到,则会引发错误。从技术上讲,您可以将任何旧东西放在那里
编辑了帖子,应该会更好。我没有意识到列表没有__radd__
。以上是关于在 Python 中使用重载加法运算符时出现内存错误的主要内容,如果未能解决你的问题,请参考以下文章