¿Hay alguna manera de definir convenientemente una estructura tipo C en Python? Estoy cansado de escribir cosas como:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
MyStruct = namedtuple("MyStruct", "field1 field2 field3")
pandas.Series(a=42).a
debería hacerlo si eres un científico de datos ...Respuestas:
Utilice una tupla con nombre , que se agregó a módulo de colecciones en la biblioteca estándar en Python 2.6. También es posible usar la tupla llamada Raymond Hettinger receta de si necesita admitir Python 2.4.
Es bueno para su ejemplo básico, pero también cubre un montón de casos extremos que podría encontrar más tarde también. Su fragmento anterior se escribiría como:
El tipo recién creado se puede usar así:
También puede usar argumentos con nombre:
fuente
Actualización : clases de datos
Con la introducción de las clases de datos en Python 3.7 nos acercamos mucho.
El siguiente ejemplo es similar al ejemplo de NamedTuple a continuación, pero el objeto resultante es mutable y permite valores predeterminados.
Esto funciona muy bien con el nuevo módulo de escritura en caso de que desee utilizar anotaciones de tipo más específicas.
¡He estado esperando desesperadamente esto! Si me preguntas, ¡las clases de datos y la nueva declaración NamedTuple , combinadas con el módulo de escritura , son una bendición!
Declaración mejorada de NamedTuple
Desde Python 3.6 se volvió bastante simple y hermoso (en mi humilde opinión), siempre que puedas vivir con inmutabilidad .
Se introdujo una nueva forma de declarar NamedTuples , que también permite anotaciones de tipo :
fuente
dataclass
módulo es nuevo en Python 3.7 pero puedespip install dataclasses
. Es el backport en Python 3.6. pypi.org/project/dataclasses/#description@dataclass
Los detalles están aquí: pypi.org/project/dataclasses/#descriptionPuede usar una tupla para muchas cosas en las que usaría una estructura en C (algo así como coordenadas x, y o colores RGB, por ejemplo).
Para todo lo demás, puede usar el diccionario o una clase de utilidad como esta :
Creo que la discusión "definitiva" está aquí , en la versión publicada del Python Cookbook.
fuente
TypeError: this constructor takes no arguments
Quizás esté buscando estructuras sin constructores:
fuente
class Sample:
no hacen nada de inmediato; establecen atributos de clase. Siempre se puede acceder a ellos como, por ejemploSample.name
.s1
ys2
en tiempo de ejecución. A menos que esté prohibido, puede agregar o modificar elname
atributo en cualquier instancia de cualquier clase en cualquier momento, ya sea que la clase tenga o no unname
atributo. Probablemente el mayor problema funcional al hacer esto es que diferentes instancias de la misma clase se comportarán de manera diferente dependiendo de si se ha configuradoname
. Si actualizaSample.name
, cualquier objeto sin unaname
propiedad establecida explícitamente devolverá el nuevoname
.self
palabras clave y una línea de constructor si me preguntas. Agradecería que José pudiera editar su respuesta para agregar un mensaje de advertencia sobre el riesgo de compartir accidentalmente valores entre instancias.¿Qué tal un diccionario?
Algo como esto:
Entonces puede usar esto para manipular valores:
Y los valores no tienen que ser cadenas. Pueden ser prácticamente cualquier otro objeto.
fuente
pt3.w = 1 print pt3.w
en un lenguaje con dictos, es mejor usarlos, especialmente para los objetos que se serializan, ya que puede usar automáticamente import json para guardarlos y otras bibliotecas de serialización siempre que no tenga extraños cosas dentro de tu dict. Los dictos son la solución para mantener separados los datos y la lógica y son mejores que las estructuras para las personas que no desean escribir funciones personalizadas de serialización y deserialización y no desean utilizar serializadores no portátiles como pickle.Puede acceder a los campos de una clase usando un diccionario porque los campos de una clase, sus métodos y todas sus propiedades se almacenan internamente usando dicts (al menos en CPython).
... Lo que nos lleva a su segundo comentario. Creer que los dictados de Python son "pesados" es un concepto extremadamente no pitonista. Y leer esos comentarios mata a mi Python Zen. Eso no es bueno.
Verá, cuando declara una clase, en realidad está creando una envoltura bastante compleja alrededor de un diccionario, por lo que, en todo caso, está agregando más sobrecarga que utilizando un diccionario simple. Una sobrecarga que, por cierto, no tiene sentido en ningún caso. Si está trabajando en aplicaciones críticas de rendimiento, use C o algo así.
fuente
self['member']
es 3 caracteres más largo queself.member
, y esos personajes son relativamente poco amigables para la muñeca.Puede subclasificar la estructura C que está disponible en la biblioteca estándar. El módulo ctypes proporciona una clase de estructura . El ejemplo de los documentos:
fuente
También me gustaría agregar una solución que use ranuras :
Definitivamente revise la documentación de las ranuras, pero una explicación rápida de las ranuras es que es la forma en que Python dice: "Si puede bloquear estos atributos y solo estos atributos en la clase de modo que se comprometa a no agregar ningún atributo nuevo una vez que la clase se crea una instancia (sí, puede agregar nuevos atributos a una instancia de clase, consulte el ejemplo a continuación), luego eliminaré la gran asignación de memoria que permite agregar nuevos atributos a una instancia de clase y usaré justo lo que necesito para estos atributos ranurados ".
Ejemplo de agregar atributos a la instancia de clase (por lo tanto, no usar ranuras):
Salida: 8
Ejemplo de intentar agregar atributos a la instancia de clase donde se usaron las ranuras:
Salida: AttributeError: el objeto 'Punto' no tiene atributo 'z'
Esto puede funcionar efectivamente como una estructura y usa menos memoria que una clase (como lo haría una estructura, aunque no he investigado exactamente cuánto). Se recomienda usar ranuras si va a crear una gran cantidad de instancias del objeto y no necesita agregar atributos. Un objeto de punto es un buen ejemplo de esto, ya que es probable que uno pueda instanciar muchos puntos para describir un conjunto de datos.
fuente
También puede pasar los parámetros de inicio a las variables de instancia por posición
fuente
Point3dStruct
declaración,Point3dStruct(5, 6)
no funcionará como se esperaba. Es extraño que nadie haya escrito esto en los 6 años.print
>print()
yattrs[n]
>next(attrs)
(el filtro ahora es su propio objeto iterable y requierenext
).Siempre que necesito un "objeto de datos instantáneos que también se comporta como un diccionario" (¡ no pienso en estructuras de C!), Pienso en este lindo truco:
Ahora solo puedes decir:
Perfectamente útil para aquellos momentos en que necesita una "bolsa de datos que NO es una clase", y para cuando las tuplas nombradas son incomprensibles ...
fuente
Accede a la estructura C-Style en python de la siguiente manera.
si solo quieres usar objeto de cstruct
si quieres crear una matriz de objetos de cstruct
Nota: en lugar del nombre 'cstruct', utilice su nombre de estructura en lugar de var_i, var_f, var_str, defina la variable miembro de su estructura.
fuente
Algunas de las respuestas aquí son masivamente elaboradas. La opción más simple que he encontrado es (de: http://norvig.com/python-iaq.html ):
Inicializando:
agregando más:
editar: Lo siento, no vi este ejemplo ya más abajo.
fuente
Esto puede ser un poco tarde, pero hice una solución usando Python Meta-Classes (versión de decorador a continuación también)
Cuando
__init__
se llama durante el tiempo de ejecución, toma cada uno de los argumentos y su valor y los asigna como variables de instancia a su clase. De esta manera, puede crear una clase de estructura sin tener que asignar cada valor manualmente.Mi ejemplo no tiene verificación de errores, por lo que es más fácil de seguir.
Aquí está en acción.
Lo publiqué en reddit y / u / matchu publicó una versión de decorador que es más limpia. Te animo a que lo uses a menos que quieras expandir la versión de la metaclase.
fuente
Escribí un decorador que puede usar en cualquier método para que todos los argumentos pasados o los valores predeterminados se asignen a la instancia.
Una rápida demostración. Tenga en cuenta que uso un argumento posicional
a
, uso el valor predeterminado parab
y un argumento con nombrec
. Luego imprimo las 3 referenciasself
, para mostrar que se han asignado correctamente antes de ingresar el método.Tenga en cuenta que mi decorador debería funcionar con cualquier método, no solo
__init__
.fuente
No veo esta respuesta aquí, así que creo que la agregaré ya que estoy inclinado Python en este momento y acabo de descubrirlo. El tutorial de Python (Python 2 en este caso) da el siguiente ejemplo simple y efectivo:
Es decir, se crea un objeto de clase vacío, luego se instancia y los campos se agregan dinámicamente.
La ventaja de esto es realmente simple. La desventaja es que no es particularmente autodocumentado (los miembros previstos no están listados en ninguna parte de la "definición" de clase), y los campos no definidos pueden causar problemas cuando se accede a ellos. Esos dos problemas pueden resolverse mediante:
Ahora, de un vistazo, al menos puede ver qué campos esperará el programa.
Ambos son propensos a errores tipográficos,
john.slarly = 1000
tendrán éxito. Aún así, funciona.fuente
Aquí hay una solución que usa una clase (nunca instanciada) para almacenar datos. Me gusta que de esta manera se trate de escribir muy poco y no requiera ningún paquete adicional, etc.
Puede agregar más campos más tarde, según sea necesario:
Para obtener los valores, se accede a los campos como de costumbre:
fuente
Personalmente, también me gusta esta variante. Extiende la respuesta de @ dF .
Admite dos modos de inicialización (que se pueden combinar):
Además, se imprime mejor:
fuente
La siguiente solución a una estructura está inspirada en la implementación de namedtuple y algunas de las respuestas anteriores. Sin embargo, a diferencia del namedtuple, es mutable, en sus valores, pero al igual que la estructura de estilo c inmutable en los nombres / atributos, que no es una clase o dict normal.
Uso:
fuente
Hay un paquete de Python exactamente para este propósito. ver cstruct2py
cstruct2py
es una biblioteca de python pura para generar clases de python a partir de código C y usarlas para empacar y desempaquetar datos. La biblioteca puede analizar los encabezados C (estructuras, uniones, enumeraciones y declaraciones de matrices) y emularlos en Python. Las clases pitónicas generadas pueden analizar y empaquetar los datos.Por ejemplo:
Primero necesitamos generar las estructuras pitónicas:
Ahora podemos importar todos los nombres del código C:
También podemos hacer eso directamente:
Usando tipos y definiciones del código C
El resultado será:
Para
cstruct2py
ejecutar clon :fuente
Creo que el diccionario de estructura Python es adecuado para este requisito.
fuente
https://stackoverflow.com/a/32448434/159695 no funciona en Python3.
https://stackoverflow.com/a/35993/159695 funciona en Python3.
Y lo extiendo para agregar valores predeterminados.
fuente
Si no tiene un 3.7 para @dataclass y necesita mutabilidad, el siguiente código podría funcionar para usted. Es bastante autodocumentado y compatible con IDE (autocompletado), evita escribir dos veces, es fácilmente extensible y es muy simple probar que todas las variables de instancia están completamente inicializadas:
fuente
Aquí hay un truco rápido y sucio:
¿Cómo funciona? Simplemente reutilice la clase incorporada
Warning
(derivada deException
) y úsela como si fuera su propia clase definida.Lo bueno es que no necesita importar o definir nada primero, que "Advertencia" es un nombre corto, y que también deja en claro que está haciendo algo sucio que no debe usarse en otro lugar que no sea un pequeño script suyo.
Por cierto, intenté encontrar algo aún más simple,
ms = object()
pero no pude (este último ejemplo no funciona). Si tienes uno, estoy interesado.fuente
La mejor manera de hacer esto fue utilizar una clase de diccionario personalizada como se explica en esta publicación: https://stackoverflow.com/a/14620633/8484485
Si se necesita el soporte de autocompletado de iPython, simplemente defina la función dir () de esta manera:
Luego define su pseudoestructura de la siguiente manera: (esta está anidada)
Luego puede acceder a los valores dentro de my_struct de esta manera:
print(my_struct.com1.inst)
=>
[5]
fuente
NamedTuple es cómodo. pero allí nadie comparte el rendimiento y el almacenamiento.
Si
__dict__
no está usando, elija entre__slots__
(mayor rendimiento y almacenamiento) yNamedTuple
(claro para leer y usar)Puede revisar este enlace ( Uso de ranuras ) para obtener más
__slots__
información.fuente