tuple ordereddict dict python class python-3.x namedtuple

python - ordereddict - No se puede establecer el atributo para las subclases de namedtuple



named tuple c# (4)

Parece que this o this son temas relacionados, pero aún no he descubierto las cosas :)

Estoy tratando de crear una subclase de namedtuple de namedtuple y proporcionar inicializadores diferentes para poder construir objetos de diferentes maneras. Por ejemplo:

>>> from collections import namedtuple >>> class C(namedtuple("C", "x, y")) : ... __slots__ = () ... def __init__(self, obj) : # Initialize a C instance by copying values from obj ... self.x = obj.a ... self.y = obj.b ... def __init__(self, x, y) : # Initialize a C instance from the parameters ... self.x = x ... self.y = y

Sin embargo, eso no funciona:

>>> c = C(1, 2) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 7, in __init__ AttributeError: can''t set attribute

Después de hurgarme (por ejemplo, ver this hilo) intenté usar constructores en lugar de inicializadores:

>>> from collections import namedtuple >>> class C(namedtuple("C", "x, y")) : ... __slots__ = () ... def __new__(cls, obj) : ... self = super(C, cls).__new__(cls, obj.a, obj.b) ... def __new__(cls, x, y) : ... self = super(C, cls).__new__(cls, x, y)

que parecía construir un objeto pero luego no puedo leer sus atributos:

>>> c = C(1,2) >>> c.x, c.y Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: ''NoneType'' object has no attribute ''x''

¿A dónde me voy mal aquí? ¿Cómo puedo crear una subclase con múltiples constructores o inicializadores?


Dos cosas: una, realmente no estás obteniendo mucho de tu nombre aquí, por lo que puedo decir. Así que tal vez debería cambiar a una clase normal. Además, no puede sobrecargar el

Segundo, otras posibilidades que podrían ayudarte con tu problema:

Patrón de diseño de fábrica : en lugar de colocar los diferentes parámetros en el constructor, tenga una clase que tome diferentes tipos de parámetros y llame al constructor con los argumentos apropiados, fuera del objeto. recordtype : un objeto mutable con nombre, que permite valores predeterminados pero también le permitiría escribir su subclase de la manera que originalmente quería. bunch : no es exactamente una tupla con nombre, pero le permite crear objetos un tanto arbitrarios.


Hay una solución alternativa para cambiar el atributo de un grupo con nombre.

import collections def updateTuple(NamedTuple,nameOfNamedTuple): ## Convert namedtuple to an ordered dictionary, which can be updated NamedTuple_asdict = NamedTuple._asdict() ## Make changes to the required named attributes NamedTuple_asdict[''path'']= ''www.google.com'' ## reconstruct the namedtuple using the updated ordered dictionary updated_NamedTuple = collections.namedtuple(nameOfNamedTuple, NamedTuple_asdict.keys())(**NamedTuple_asdict) return updated_NamedTuple Tuple = collections.namedtuple("Tuple", "path") NamedTuple = Tuple(path=''www.yahoo.com'') NamedTuple = updateTuple(NamedTuple, "Tuple")


Las tuplas nombradas son inmutables, por lo que no puede manipularlas en el inicializador __init__ . Su única opción es anular el método __new__ :

class C(namedtuple(''C'', ''x, y'')): __slots__ = () def __new__(cls, obj): return super(C, cls).__new__(cls, obj.x, obj.y)

Tenga en cuenta que debido a que __new__ es un método de fábrica para las nuevas instancias, debe devolver la instancia recién creada. Si no usa return en el método __new__ , el valor de retorno predeterminado es None , lo que le da su error.

Demostración con un objeto con atributos x e y :

>>> class C(namedtuple(''C'', ''x, y'')): ... __slots__ = () ... def __new__(cls, obj): ... return super(C, cls).__new__(cls, obj.x, obj.y) ... >>> O.x, O.y (10, 20) >>> C(O) C(x=10, y=20)

Python no admite la sobrecarga de métodos; por lo general, usa argumentos de palabras clave opcionales o métodos de clase adicionales como métodos de fábrica.

El módulo datetime , por ejemplo, tiene varios métodos de fábrica para permitirle crear objetos que no se ajusten al constructor estándar. datetime.datetime.fromtimestamp() crea una instancia de datetime.datetime partir de un solo valor numérico, y también lo hace datetime.datetime.fromordinal() ; Excepto que interpretan el número de diferentes maneras.

Si quieres apoyar argumentos variables, haz:

class C(namedtuple(''C'', ''x, y'')): __slots__ = () def __new__(cls, x, y=None): if y is None: # assume attributes x, y = x.x, x.y return super(C, cls).__new__(cls, x, y)

Aquí, y es un argumento opcional, el valor predeterminado es None si no lo proporciona la persona que llama:

>>> C(3, 5): C(x=3, y=5) >>> C(O) C(x=10, y=20)

La alternativa, utilizando un método de clase, sería:

class C(namedtuple(''C'', ''x, y'')): @classmethod def from_attributes(cls, obj): return cls(obj.x, obj.y)

Ahora hay dos métodos de fábrica; uno por defecto y uno nombrado:

>>> C(3, 5): C(x=3, y=5) >>> C.from_attributes(O) C(x=10, y=20)


Te sugiero que uses el método docs.python.org/2/library/…

from collections import namedtuple C = namedtuple(''C'', ''x, y'') c = C(x=10, y=20) # c.x = 30 won''t work c = c._replace(x=30)