2011-04-07 18 views
9

Estoy teniendo un problema numpy.ndarray subclase raro que se siente como
Values of instance variables of superclass persist across instances of subclass
Pero no he sido capaz de entender completamente o hacer que funcione para mi ejemplo.conjunto de subclases de acciones unexpedly numpy atributos a través de las instancias

Leyendo a través de Slightly more realistic example - attribute added to existing array Estoy tratando de hacer exactamente esto. Quiero agregar un atributo attrs a una matriz para contener información como unidades en un diccionario.

Aquí es lo que tengo:

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', {}) 

Entonces usarlo y demostrar el problema

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.... 

Así b está recogiendo attrs que yo no quiero que haga. Era un fastidio que funciona bien si usted hace esto:

from datamodel import * 
a = dmarray([1,2,3,4], attrs={'foo':'bar'}) 
b = dmarray([1,2,3,4]) 
b.attrs 
# {} 

Entonces, ¿cómo en el mundo puedo hacer este trabajo dmarray la forma que yo quiero que?


Editar: bien así que esto parece solucionar el problema, pero no entiendo por qué. Entonces, cambiemos la pregunta a qué está haciendo esto y por qué funciona.

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 

Así que quitando el kwarg de __new__() y ponerlo en __init__() funciona. Acabo de intentar esto como un "bien podría funcionar"

a = dmarray([1,2,3,4]) 
b = dmarray([1,2,3,4]) 
a.attrs['foo'] = 'bar' 
b.attrs 
# {} 
+0

Un colega mencionó que él pensaba que el problema es probablemente .Ver(), hmm qué más puedo utilizar allí? –

+2

Suena un poco como [esta advertencia importante] (http://docs.python.org/tutorial/controlflow.html#default-argument-values). – lafras

+0

Gracias, El problema fue ciertamente el atributo = {}, pero se manifestó de una manera que no esperaba y seguí mirando .copy() –

Respuesta

16

El problema está aquí:

def __new__(cls, input_array, attrs={}) 

Nunca haga esto attrs={} en una cabecera de la función. El resultado esperado es (probablemente) no lo que piensas que es. Este es un Pitfall Pitfall común. Vea aquí Default Parameter Values in Python

La forma correcta de cómo hacer esto:

def __new__(cls, input_array, attrs=None): 
    if attrs is None: 
     attrs = {} 
+0

Correcto, esta es la respuesta. Mire más allá de .copy() y no use el valor predeterminado de la forma en que lo hice. Gracias. –

+0

O puede hacer esto: 'attrs = attrs o {}' – devxoul

+0

@devxoul - idea genial, pero eso no me parece particularmente seguro. Muchas cosas se consideran 'False' en Python, ¿no es así? No confiaría en esa construcción. – Fenikso

Cuestiones relacionadas