Je suis désolé s'il s'agit d'une question ABSOLUMENT sophomorique, mais je suis curieux de savoir quelles sont les meilleures pratiques, et je n'arrive pas à trouver une bonne réponse sur Google.
En Python, j'utilise généralement une classe vide comme conteneur de structure de données super-catchall (un peu comme un fichier JSON), et j'ajoute des attributs en cours de route:
class DataObj:
"Catch-all data object"
def __init__(self):
pass
def processData(inputs):
data = DataObj()
data.a = 1
data.b = "sym"
data.c = [2,5,2,1]
Cela me donne une énorme flexibilité, car l'objet conteneur peut essentiellement stocker n'importe quoi. Donc, si de nouvelles exigences surgissent, je vais simplement l'ajouter comme autre attribut à l'objet DataObj (que je passe dans mon code).
Cependant, récemment, j'ai été impressionné (par les programmeurs FP) que c'est une pratique horrible, car cela rend très difficile la lecture du code. Il faut parcourir tout le code pour comprendre quels attributs DataObj possède réellement.
Question : Comment puis-je réécrire cela pour une plus grande maintenabilité sans sacrifier la flexibilité?
Y a-t-il des idées de programmation fonctionnelle que je peux adopter?
Je recherche les meilleures pratiques.
Remarque : une idée est de pré-initialiser la classe avec tous les attributs que l'on s'attend à rencontrer, par exemple
class DataObj:
"Catch-all data object"
def __init__(self):
data.a = 0
data.b = ""
data.c = []
def processData(inputs):
data = DataObj()
data.a = 1
data.b = "sym"
data.c = [2,5,2,1]
Est-ce vraiment une bonne idée? Et si je ne connais pas mes attributs a priori?
Réponses:
Non. La flexibilité est précisément ce qui cause le problème. Si n'importe quel code n'importe où peut changer les attributs d'un objet, la maintenabilité est déjà en morceaux. Idéalement, chaque classe a un ensemble d'attributs qui sont gravés dans la pierre après
__init__
et les mêmes pour chaque instance. Pas toujours possible ou sensé, mais cela devrait être le cas chaque fois que vous n'avez pas vraiment de bonnes raisons de l'éviter.Ce n'est pas une bonne idée. Bien sûr, l'attribut est là, mais peut avoir une valeur fausse, ou même une valeur valide qui couvre le code n'affectant pas la valeur (ou une faute d'orthographe).
AttributeError
est effrayant, mais obtenir de mauvais résultats est pire. Les valeurs par défaut sont généralement bonnes, mais pour choisir une valeur par défaut raisonnable (et décider ce qui est requis), vous devez savoir à quoi sert l'objet.Ensuite, vous êtes foutu dans tous les cas et devez utiliser un dict ou une liste au lieu de coder en dur les noms d'attribut. Mais je suppose que vous vouliez dire "... au moment où j'écris la classe des conteneurs". Ensuite, la réponse est: "Vous pouvez modifier des fichiers en même temps, duh." Besoin d'un nouvel attribut? Ajoutez un attribut frigging à la classe de conteneur. Il y a plus de code utilisant cette classe et il n'a pas besoin de cet attribut? Envisagez de diviser les choses en deux classes distinctes (utilisez des mixins pour rester SEC), alors rendez-le facultatif si cela a du sens.
Si vous avez peur d'écrire des classes de conteneurs répétitives: appliquez judicieusement la métaprogrammation, ou utilisez
collections.namedtuple
si vous n'avez pas besoin de muter les membres après la création (vos amis FP seront ravis).la source
Vous pouvez toujours utiliser la classe Bunch d' Alex Martelli . Dans ton cas:
De cette façon, au moins il est clair pour le lecteur que les données ne sont qu'un magasin de données stupide et on peut voir immédiatement quelles valeurs sont stockées sous quel nom, car tout se passe sur une seule ligne.
Et oui, faire les choses de cette façon est parfois une bonne idée.
la source
J'utiliserais probablement la deuxième approche, éventuellement en utilisant
None
pour indiquer des données invalides. Il est vrai qu'il est difficile de lire / maintenir si vous ajoutez des attributs plus tard. Cependant, plus d'informations sur le but de cette classe / objet donneraient un aperçu de la raison pour laquelle la première idée est une mauvaise conception: où auriez-vous jamais une classe complètement vide sans méthodes ou données par défaut? Pourquoi ne sauriez-vous pas quels sont les attributs de la classe?Il est possible que
processData
cela soit mieux en tant que méthode (process_data
pour suivre les conventions de dénomination python), car elle agit sur la classe. Compte tenu de l'exemple, il semble que cela pourrait être mieux en tant que structure de données (où undict
peut suffire).Étant donné un exemple réel, vous pourriez envisager de poser la question à CodeReview , où ils pourraient aider à refactoriser le code.
la source