2010-05-26 3 views
7

Je crée un environnement de type shell. Ma méthode originale de gestion de l'entrée de l'utilisateur consistait à utiliser des commandes de mappage de dictionnaire (chaînes) pour les méthodes de diverses classes, en utilisant le fait que les fonctions sont des objets de première classe dans python. Par souci de flexibilité (surtout pour les commandes d'analyse syntaxique), je pense à changer ma configuration de telle sorte que j'utilise getattr (commande), pour récupérer la méthode dont j'ai besoin et passer des arguments à la fin de mon analyseur Un autre avantage de cette approche est de ne pas avoir à mettre à jour mon dictionnaire de commandes (actuellement implémenté statiquement) chaque fois que j'ajoute une nouvelle méthode/commande.Est-ce une mauvaise pratique d'utiliser généreusement getattr de python?

Ma question est double. Premièrement, getattr at-il les mêmes problèmes que eval? Deuxièmement, vais-je prendre un coup à l'efficacité de ma coquille? Est-ce que le nombre de méthodes/commandes que j'ai? Je regarde actuellement 30 commandes, qui pourraient éventuellement doubler.

+1

si vous n'avez pas regardé pyparsing http://pyparsing.wikispaces.com/ vous devriez vraiment, il n'y a pas vraiment de raison d'écrire votre propre analyseur en python pour quelque chose. –

+2

Fuzzy, je suis sûr que je peux penser à un, et c'est ce que je fais pour: l'apprentissage. Avant de commencer ce projet en cours, je ne comprenais pas les implications des fonctions étant des objets de première classe. J'apprécie cependant la référence. Je vais regarder dedans. – Wilduck

Répondre

20

La différence entre l'accès direct aux attributs et l'utilisation de getattr() devrait être assez négligeable. Vous pouvez faire la différence entre les deux de bytecode de versions en utilisant le module dis de Python pour comparer les deux approches:

>>> import dis 
>>> dis.dis(lambda x: x.foo) 
    1   0 LOAD_FAST    0 (x) 
       3 LOAD_ATTR    0 (foo) 
       6 RETURN_VALUE   
>>> dis.dis(lambda x: getattr(x, 'foo')) 
    1   0 LOAD_GLOBAL    0 (getattr) 
       3 LOAD_FAST    0 (x) 
       6 LOAD_CONST    0 ('foo') 
       9 CALL_FUNCTION   2 
      12 RETURN_VALUE 

Il ne, cependant, le son que vous développez une coquille qui est très similaire à la façon dont la bibliothèque Python cmd fait des coquilles de ligne de commande. cmd vous permet de créer des coquilles qui exécute les commandes en faisant correspondre le nom de la commande à une fonction définie sur un objet cmd.Cmd comme ceci:

import cmd 

class EchoCmd(cmd.Cmd): 
    """Simple command processor example.""" 

    def do_echo(self, line): 
     print line 

    def do_EOF(self, line): 
     return True 

if __name__ == '__main__': 
    EchoCmd().cmdloop() 

Vous pouvez en savoir plus sur le module soit à la documentation ou à http://www.doughellmann.com/PyMOTW/cmd/index.html

+1

+1 pour le "dis check". – EOL

+0

Merci pour cette réponse. Comme dans mon commentaire ci-dessus, j'écris vraiment cette coquille à des fins d'apprentissage. À l'avenir, si j'ai vraiment besoin d'écrire un shell à des fins de production, j'utiliserai cmd. Je ne savais pas à propos de dis, merci pour la référence. – Wilduck

6

est-ce que getattr a les mêmes problèmes que eval?

Non - le code utilisant eval() est terriblement ennuyeux à maintenir, et peut avoir de sérieux problèmes de sécurité. Appeler getattr(x, "foo") est juste une autre façon d'écrire x.foo.

vais-je prendre un coup à l'efficacité de ma coquille

Il sera imperceptiblement plus lent si la commande ne se trouve pas, mais pas assez à la matière. Vous ne le remarquerez que si vous faites des benchmarks, avec des dizaines de milliers d'entrées.

Questions connexes