En Python 3.4+, ¿por qué debería usar namedtuple sobre SimpleNamespace cuando no uso dict? Parecen muy similares

11

En un momento u otro, puede encontrar funciones con muchos argumentos. A veces tiene sentido combinar algunos de los argumentos en super-argumentos. A menudo he hecho esto con dictos, pero ahora estoy buscando mejores formas de hacerlo.

Me gustaría girar ...

def do_something(ax, ay, az, bu, bv, c):
    # Do something

... dentro ...

def do_something(a, b, c):
    # Do something

... donde ay bcontienen sus subvariaciones.

Una forma de hacer esto es hacer:

A = namedtuple('A', 'x, y, z')
a = A(ax, ay, az)
B = namedtuple('B', 'u, v')
b = B(bu, bv)

Sin embargo, esto parece más simple:

a = SimpleNamespace(x=ax, y=ay, z=az)
b = SimpleNamespace(u=bu, v=bv)

¿Cuál es el inconveniente? El hecho de que ay bno están bien escritos? ¿No son objetos A y B?

(Por cierto, no te preocupes por los nombres de las variables. Normalmente no uso como nombres cortos de variables).

André Christoffer Andersen
fuente
1
No hay inconvenientes per se, son solo cosas diferentes. Para empezar, las tuplas nombradas son inmutables, mientras que los espacios de nombres son mutables. ¿Es mutable mejor o peor que inmutable? Depende de lo que necesite o desee, en muchos casos simplemente no importa. Su función probablemente funcionaría con cualquier objeto con los atributos requeridos, cómo construirlo depende de la persona que llama.
Deja de dañar a Mónica
@Goyo Gracias. El "inconveniente" era una manera torpe de decirlo. No quise decir que uno es inherentemente mejor que el otro. Solo quería los pros y los contras. Gracias de nuevo.
André Christoffer Andersen
1
¿No debería verse la cuarta línea como "b = B (bu, bv)"?
Alen Siljak
@AlenSiljak Sí, debería. Lo arreglaré ahora.
André Christoffer Andersen

Respuestas:

21

SimpleNamespacees básicamente una bonita fachada encima de un diccionario. Le permite usar propiedades en lugar de claves de índice. Esto es bueno ya que es súper flexible y fácil de manipular.

La desventaja de esa flexibilidad es que no proporciona ninguna estructura. No hay nada que impida que alguien llame SimpleNamespace(x=ax, y=ay)(y del a.zen algún momento más tarde). Si esta instancia se pasa a su función, la excepción ocurre cuando intenta acceder al campo.

Por el contrario, le namedtuplepermite crear un tipo estructurado. El tipo tendrá un nombre y sabrá qué campos se supone que debe tener. No podrá crear una instancia sin cada uno de esos campos y no se pueden eliminar más adelante. Además, la instancia es inmutable, por lo que sabrá que el valor en a.xsiempre será el mismo.

Depende de usted decidir si necesita la flexibilidad que SimpleNamespacele brinda, o si prefiere tener la estructura y las garantías proporcionadas namedtuple.

muestreador
fuente
2

Realmente me gusta la respuesta sobre estructurado versus no, así que solo proporciono un ejemplo concreto a continuación.

SimpleNamespaceaceptará claves que comienzan con _. Si está buscando una forma rápida y fácil de convertir, digamos, JSON que no controla en objetos con nombres de campo, esto es muy útil:

d = {"_id": 2342122, "text": "hi there!"} # Elasticsearch gives this id!
e = SimpleNamespace(**d) # works
Name = namedtuple("Name", sorted(d)) # ValueError so we can't do Name(**d)

Tenga en cuenta que puede ver que namedtuplenos da un objeto extra completo que SimpleNamespacenunca lo hará. Cada uno SimpleNamespacees realmente un "copo de nieve único", mientras que namedtupleexiste sin ser instanciado con ningún valor concreto. Donde sea que necesite abstracciones que se generalicen en valores concretos, probablemente debería preferirlo.

Alex Moore-Niemi
fuente
1

Resumen de SimpleNamespace

Permite inicializar atributos mientras se construye el objeto:

sn = SimpleNamespace(a=1, b=2)

Proporciona una legible

repr(): eval(repr(sn)) == sn

Anula la comparación predeterminada. En lugar de comparar por id(), compara los valores de los atributos en su lugar.

Vlad Bezden
fuente