Existe-t-il un moyen de définir facilement une structure de type C en Python? J'en ai assez d'écrire des trucs comme:
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
devrait le faire si vous êtes un scientifique des données ...Réponses:
Utilisez un tuple nommé , qui a été ajouté au module collections dans la bibliothèque standard de Python 2.6. Il est également possible d'utiliser la recette de tuple nommée de Raymond Hettinger si vous devez prendre en charge Python 2.4.
C'est bien pour votre exemple de base, mais couvre également un tas de cas de bord que vous pourriez également rencontrer plus tard. Votre fragment ci-dessus serait écrit comme suit:
Le type nouvellement créé peut être utilisé comme ceci:
Vous pouvez également utiliser des arguments nommés:
la source
Mise à jour : classes de données
Avec l'introduction des classes de données dans Python 3.7, nous sommes très proches.
L'exemple suivant est similaire à l' exemple NamedTuple ci-dessous, mais l'objet résultant est modifiable et il autorise les valeurs par défaut.
Cela fonctionne bien avec le nouveau module de saisie au cas où vous voudriez utiliser des annotations de type plus spécifiques.
J'attendais désespérément ça! Si vous me demandez, les classes de données et la nouvelle déclaration NamedTuple , combinées avec le module de frappe sont une aubaine!
Déclaration NamedTuple améliorée
Depuis Python 3.6, il est devenu assez simple et beau (à mon humble avis), tant que vous pouvez vivre avec l' immuabilité .
Une nouvelle façon de déclarer NamedTuples a été introduite, qui permet également les annotations de type :
la source
dataclass
module est nouveau dans Python 3.7 mais vous le pouvezpip install dataclasses
. C'est le backport sur Python 3.6. pypi.org/project/dataclasses/#description@dataclass
Les détails sont ici: pypi.org/project/dataclasses/#descriptionVous pouvez utiliser un tuple pour beaucoup de choses où vous utiliseriez une structure en C (quelque chose comme les coordonnées x, y ou les couleurs RVB par exemple).
Pour tout le reste, vous pouvez utiliser un dictionnaire ou une classe utilitaire comme celle-ci :
Je pense que la discussion "définitive" est ici , dans la version publiée du livre de recettes Python.
la source
TypeError: this constructor takes no arguments
Peut-être que vous recherchez des structures sans constructeurs:
la source
class Sample:
ne font rien immédiatement; ils définissent des attributs de classe. Ceux-ci peuvent toujours être consultés comme par exempleSample.name
.s1
ets2
à l' exécution. Sauf interdiction contraire, vous pouvezname
à tout moment ajouter ou modifier l' attribut sur n'importe quelle instance d'une classe, que la classe ait ou non unname
attribut. Le plus gros problème fonctionnel de cette opération est probablement que différentes instances de la même classe se comporteront différemment selon que vous l'avez définiename
. Si vous mettez à jourSample.name
, tout objet sansname
propriété explicitement définie renverra le nouveauname
.self
mots-clés et d'une ligne constructeur si vous me demandez. J'apprécierais que Jose modifie sa réponse pour ajouter un message d'avertissement sur le risque de partage accidentel de valeurs entre les instances.Et un dictionnaire?
Quelque chose comme ça:
Ensuite, vous pouvez utiliser ceci pour manipuler des valeurs:
Et les valeurs ne doivent pas nécessairement être des chaînes. Ils peuvent être à peu près n'importe quel autre objet.
la source
pt3.w = 1 print pt3.w
dans un langage avec dict, il est préférable de les utiliser, en particulier pour les objets en cours de sérialisation, car vous pouvez automatiquement utiliser import json pour les enregistrer et d'autres bibliothèques de sérialisation tant que vous n'avez pas d'étranges des choses à l'intérieur de votre dict. Les dictés sont la solution pour séparer les données et la logique et sont meilleurs que les structures pour les personnes qui ne veulent pas écrire de fonctions de sérialisation et de désérialisation personnalisées et ne veulent pas utiliser des sérialiseurs non portables comme le pickle.Vous pouvez accéder aux champs d'une classe à l'aide d'un dictionnaire car les champs d'une classe, ses méthodes et toutes ses propriétés sont stockés en interne à l'aide de dict (au moins en CPython).
... Ce qui nous amène à votre deuxième commentaire. Croire que les textes de Python sont "lourds" est un concept extrêmement non pythoniste. Et la lecture de ces commentaires tue mon Python Zen. Ce n'est pas bon.
Vous voyez, lorsque vous déclarez une classe, vous créez en fait un wrapper assez complexe autour d'un dictionnaire - donc, si vous ajoutez quoi que ce soit, vous ajoutez plus de surcharge qu'en utilisant un simple dictionnaire. Un surcoût qui, soit dit en passant, n'a de toute façon aucun sens. Si vous travaillez sur des applications critiques pour les performances, utilisez C ou quelque chose.
la source
self['member']
est plus long que 3 caractèresself.member
, et ces caractères sont tous relativement peu adaptés au poignet.Vous pouvez sous-classer la structure C disponible dans la bibliothèque standard. Le module ctypes fournit une classe Structure . L'exemple de la documentation:
la source
Je voudrais également ajouter une solution qui utilise des slots :
Vérifiez la documentation pour les emplacements, mais une explication rapide des emplacements est que c'est la façon de python de dire: "Si vous pouvez verrouiller ces attributs et uniquement ces attributs dans la classe de telle sorte que vous vous engagez à ne pas ajouter de nouveaux attributs une fois la classe est instanciée (oui, vous pouvez ajouter de nouveaux attributs à une instance de classe, voir l'exemple ci-dessous), puis je vais supprimer la grande allocation de mémoire qui permet d'ajouter de nouveaux attributs à une instance de classe et d'utiliser exactement ce dont j'ai besoin pour ceux-ci attributs fendus ".
Exemple d'ajout d'attributs à l'instance de classe (n'utilisant donc pas d'emplacements):
Sortie: 8
Exemple d'essayer d'ajouter des attributs à l'instance de classe où les emplacements ont été utilisés:
Sortie: AttributeError: l'objet 'Point' n'a pas d'attribut 'z'
Cela peut effectivement fonctionner comme une structure et utilise moins de mémoire qu'une classe (comme le ferait une structure, même si je n'ai pas recherché exactement combien). Il est recommandé d'utiliser des emplacements si vous créez une grande quantité d'instances de l'objet et n'avez pas besoin d'ajouter d'attributs. Un objet ponctuel en est un bon exemple car il est probable que l'on puisse instancier de nombreux points pour décrire un ensemble de données.
la source
Vous pouvez également passer les paramètres init aux variables d'instance par position
la source
Point3dStruct
déclaration,Point3dStruct(5, 6)
cela ne fonctionnera pas comme prévu. C'est étrange que personne n'ait écrit cela au cours des 6 années.print
>print()
, etattrs[n]
>next(attrs)
(le filtre est maintenant son propre objet itérable et nécessitenext
).Chaque fois que j'ai besoin d'un "objet de données instantané qui se comporte également comme un dictionnaire" (je ne pense pas aux structures C!), Je pense à ce joli hack:
Maintenant, vous pouvez simplement dire:
Parfaitement pratique pour les moments où vous avez besoin d'un "sac de données qui n'est PAS une classe", et pour quand les couples nommés sont incompréhensibles ...
la source
Vous accédez à la structure C-Style en python de la manière suivante.
si vous voulez juste utiliser un objet de cstruct
si vous voulez créer un tableau d'objets de structure
Remarque: au lieu du nom 'cstruct', veuillez utiliser votre nom de structure au lieu de var_i, var_f, var_str, veuillez définir la variable membre de votre structure.
la source
Certaines réponses ici sont massivement élaborées. L'option la plus simple que j'ai trouvée est (depuis: http://norvig.com/python-iaq.html ):
Initialisation:
en ajoutant plus:
edit: Désolé, je n'ai pas vu cet exemple plus bas.
la source
Cela pourrait être un peu tard mais j'ai fait une solution en utilisant les méta-classes Python (version décoratrice ci-dessous aussi).
Quand
__init__
est appelé pendant l'exécution, il saisit chacun des arguments et leur valeur et les affecte en tant que variables d'instance à votre classe. De cette façon, vous pouvez créer une classe de type structure sans avoir à attribuer chaque valeur manuellement.Mon exemple n'a pas de vérification d'erreur, il est donc plus facile à suivre.
Le voici en action.
Je l'ai posté sur reddit et / u / matchu a publié une version décorative plus propre. Je vous encourage à l'utiliser sauf si vous souhaitez étendre la version de la métaclasse.
la source
J'ai écrit un décorateur que vous pouvez utiliser sur n'importe quelle méthode pour que tous les arguments passés, ou toutes les valeurs par défaut, soient affectés à l'instance.
Une démonstration rapide. Notez que j'utilise un argument positionnel
a
, j'utilise la valeur par défaut pourb
et un argument nomméc
. J'imprime ensuite les 3 référencesself
, pour montrer qu'elles ont été correctement attribuées avant la saisie de la méthode.Notez que mon décorateur devrait fonctionner avec n'importe quelle méthode, pas seulement
__init__
.la source
Je ne vois pas cette réponse ici, donc je pense que je vais l'ajouter puisque je penche Python en ce moment et je viens de la découvrir. Le didacticiel Python (Python 2 dans ce cas) donne l'exemple simple et efficace suivant:
En d'autres termes, un objet de classe vide est créé, puis instancié et les champs sont ajoutés dynamiquement.
L'avantage est que c'est vraiment simple. L'inconvénient est qu'il n'est pas particulièrement auto-documenté (les membres prévus ne sont répertoriés nulle part dans la "définition" de la classe), et les champs non définis peuvent causer des problèmes lors de l'accès. Ces deux problèmes peuvent être résolus par:
Maintenant, en un coup d'œil, vous pouvez au moins voir quels domaines le programme attendra.
Les deux sont sujets aux fautes de frappe,
john.slarly = 1000
réussiront. Mais ça marche.la source
Voici une solution qui utilise une classe (jamais instanciée) pour conserver les données. J'aime que cette méthode implique très peu de frappe et ne nécessite pas de packages supplémentaires, etc.
Vous pouvez ajouter plus de champs ultérieurement, si nécessaire:
Pour obtenir les valeurs, les champs sont accessibles comme d'habitude:
la source
Personnellement, j'aime aussi cette variante. Il étend la réponse de @ dF .
Il prend en charge deux modes d'initialisation (qui peuvent être mélangés):
En outre, il imprime mieux:
la source
La solution suivante à une structure est inspirée de l'implémentation namedtuple et de certaines des réponses précédentes. Cependant, à la différence du tuple nommé, il est mutable, dans ses valeurs, mais comme la structure de style c immuable dans les noms / attributs, ce qui n'est pas le cas d'une classe ou d'un dict normal.
Usage:
la source
Il existe un package python exactement à cet effet. voir cstruct2py
cstruct2py
est une bibliothèque python pure pour générer des classes python à partir de code C et les utiliser pour emballer et décompresser des données. La bibliothèque peut analyser les en-têtes C (déclarations de structures, d'unions, d'énumérations et de tableaux) et les émuler en python. Les classes pythoniques générées peuvent analyser et compresser les données.Par exemple:
Nous devons d'abord générer les structures pythoniques:
Maintenant, nous pouvons importer tous les noms du code C:
Nous pouvons également le faire directement:
Utilisation de types et de définitions à partir du code C
La sortie sera:
Pour l'
cstruct2py
exécution de clone :la source
Je pense que le dictionnaire de structure Python convient à cette exigence.
la source
https://stackoverflow.com/a/32448434/159695 ne fonctionne pas en Python3.
https://stackoverflow.com/a/35993/159695 fonctionne en Python3.
Et je l'étends pour ajouter des valeurs par défaut.
la source
Si vous n'avez pas de 3.7 pour @dataclass et avez besoin d'une mutabilité, le code suivant peut fonctionner pour vous. Il est assez auto-documenté et convivial pour l'IDE (auto-complétion), empêche l'écriture deux fois, est facilement extensible et il est très simple de tester que toutes les variables d'instance sont complètement initialisées:
la source
Voici une astuce rapide et sale:
Comment ça fonctionne? Il suffit de réutiliser la classe intégrée
Warning
(dérivée deException
) et de l'utiliser comme si c'était votre propre classe définie.Les bons points sont que vous n'avez pas besoin d'importer ou de définir quoi que ce soit d'abord, que "Avertissement" est un nom court, et qu'il indique également clairement que vous faites quelque chose de sale qui ne devrait pas être utilisé ailleurs qu'un petit script de la vôtre.
Soit dit en passant, j'ai essayé de trouver quelque chose d'encore plus simple,
ms = object()
mais sans succès (ce dernier exemple ne fonctionne pas). Si vous en avez un, je suis intéressé.la source
La meilleure façon que j'ai trouvée pour ce faire était d'utiliser une classe de dictionnaire personnalisée comme expliqué dans ce post: https://stackoverflow.com/a/14620633/8484485
Si la prise en charge de la saisie semi-automatique iPython est nécessaire, définissez simplement la fonction dir () comme ceci:
Vous définissez ensuite votre pseudo struct comme ceci: (celui-ci est imbriqué)
Vous pouvez ensuite accéder aux valeurs dans my_struct comme ceci:
print(my_struct.com1.inst)
=>
[5]
la source
NamedTuple est confortable. mais personne ne partage les performances et le stockage.
Si vous
__dict__
n'utilisez pas, veuillez choisir entre__slots__
(performances et stockage supérieurs) etNamedTuple
(clair pour la lecture et l'utilisation)Vous pouvez consulter ce lien ( Utilisation des créneaux horaires ) pour obtenir plus d'
__slots__
informations.la source