I am having a weird subclass numpy.ndarray issue that feels like
Values of instance variables of superclass persist across instances of subclass
But I have not been able to understand fully or make it work for for my example.
Reading through Slightly more realistic example - attribute added to existing array I am trying to do pretty much exactly this. I want to add an attrs attribute to an array to hold information such as units in a dictionary.
Here is what I have:
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', {})
So then to use it and demonstrate the issue
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....
So b is picking up attrs that I don't want it to. Annoyingly it works fine if you do this:
from datamodel import *
a = dmarray([1,2,3,4], attrs={'foo':'bar'})
b = dmarray([1,2,3,4])
b.attrs
# {}
So how in the world do I make this dmarray work how I want it to?
Edit: OK so this seems to fix the problem but I don't understand why. So lets change the question to what this is doing and why it works?
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
So by removing the kwarg from __new__()
and putting it in __init__()
it works. I just tried this as a "well it might work"
a = dmarray([1,2,3,4])
b = dmarray([1,2,3,4])
a.attrs['foo'] = 'bar'
b.attrs
# {}
The problem is here:
def __new__(cls, input_array, attrs={})
Never do this attrs={}
in a function header. The expected result is (probably) not what you think it is. This is a common Python Pitfall. See here Default Parameter Values in Python
The right way how to do this:
def __new__(cls, input_array, attrs=None):
if attrs is None:
attrs = {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With