numpy数组子类意外共享实例属性
我遇到了一个奇怪的关于子类 numpy.ndarray 的问题,感觉有点像
父类的实例变量在子类的实例之间持续存在
但我还没能完全理解或者让它在我的例子中正常工作。
我在阅读 稍微更现实的例子 - 向现有数组添加属性时,想要做的几乎就是这个。我想给数组添加一个 attrs 属性,用来存储像单位这样的信息,格式是字典。
这是我现在的代码:
import numpy
class dmarray(numpy.ndarray):
def __new__(cls, input_array, attrs={}):
obj = numpy.asarray(input_array).view(cls)
obj.attrs = attrs
return obj
def __array_finalize__(self, obj):
# see InfoArray.__array_finalize__ for comments
if obj is None:
return
self.attrs = getattr(obj, 'attrs', {})
接下来我想用它来演示这个问题
a = dmarray([1,2,3,4])
b = dmarray([1,2,3,4])
a.attrs['foo'] = 'bar'
print(b.attrs)
#{'foo': 'bar'}
b.attrs is a.attrs
# True # hmm....
所以 b 这个变量获取了我不想要的 attrs。令人烦恼的是,如果你这样做,它就能正常工作:
from datamodel import *
a = dmarray([1,2,3,4], attrs={'foo':'bar'})
b = dmarray([1,2,3,4])
b.attrs
# {}
那么,我到底该如何让这个 dmarray 按照我想要的方式工作呢?
编辑:
好的,这似乎解决了问题,但我不明白为什么。所以让我把问题改成:这到底在做什么,为什么它有效?
class dmarray(numpy.ndarray):
def __new__(cls, input_array, attrs=None):
obj = numpy.asarray(input_array).view(cls)
return obj
def __init__(self, input_array, attrs=None):
if attrs == None:
attrs = {}
self.attrs = attrs
通过把 kwarg 从 __new__()
移到 __init__()
,它就能正常工作。我只是试了一下,想看看“也许这样可以”。
a = dmarray([1,2,3,4])
b = dmarray([1,2,3,4])
a.attrs['foo'] = 'bar'
b.attrs
# {}
1 个回答
18
问题出在这里:
def __new__(cls, input_array, attrs={})
在函数的开头不要这样写 attrs={}
。你可能会得到一个和你想的不一样的结果。这是一个常见的Python陷阱。可以参考这里 Python中的默认参数值
正确的做法是:
def __new__(cls, input_array, attrs=None):
if attrs is None:
attrs = {}