2009-11-04 5 views
0

J'ai une classe model avec les méthodes getter et setter, et les méthodes statiques occasionnelles. Je voudrais imposer l'utilisation de chaînes Unicode comme arguments pour des méthodes spécifiques et l'utilisation de décorateurs était la première idée que j'avais. Maintenant, j'ai quelque chose comme ceci:Comment appliquer des arguments Unicode pour les méthodes?

nombre
import types 

class require_unicode(object): 

    def __init__(self, function): 
     self.f = function 

    def __call__(self, string): 
     if not isinstance(string, types.UnicodeType): 
      raise ValueError('String is not unicode') 
     return self.f(string) 

class Foo(object): 

    something = 'bar' 

    @staticmethod 
    @require_unicode 
    def do_another(self, string): 
     return ' '.join(['baz', string]) 

    @require_unicode 
    def set_something(self, string): 
     self.something = string 

foo = Foo() 
foo.set_something('ValueError is raised') 
foo.set_something(u'argument count error') 
foo.do_another('ValueError is raised') 
foo.do_another(u'argument count error') 

Dans le code ci-dessus __call__ de l'appel de méthode à l'intérieur de décorateur échoue en raison d'une mauvaise argument (parce que l'arbitre objet « foo » est manquante?). Avant de faire quelque chose de stupide, je voulais vous demander les gars. Comment cela devrait-il être fait?

Répondre

1

Je pense que votre problème est avec le décorateur @staticmethod, pas avec votre décorateur require_unicode. Staticmethods, contrairement à classmethods, ne reçoit pas la référence à la classe comme premier argument, donc votre signature d'argument est fausse.

Vous devez soit changer do_another pour être un @classmethod, soit supprimer self des arguments.

EDIT: et, vous l'esprit, - @ méthodes décorées classmethod-recevoir de la classe comme premier argument, alors que les méthodes d'instance reçoivent la référence à la instance de la classe (auto). Donc, c'est une bonne idée de nommer le premier argument à une méthode de classe "cls" ou quelque chose, pas "soi" pour ne pas confondre qui que ce soit.

0

Je pense que c'était un peu pythonique - vous ne devriez jamais vérifier le type de vos arguments, mais plutôt vérifier qu'ils ont les méthodes et les attributs nécessaires. Le moyen le plus simple de le faire est de supposer qu'ils sont là et d'obtenir une exception sinon, mais je suppose que vous pourriez aussi faire getattr. Juste ne pas vérifier le type de choses.

+0

Je sais que c'est unpython, mais empêcher les chaînes codées ici me sauverait de beaucoup de problèmes plus tard lors de l'enregistrement des données données dans la base de données. – tuomur

+0

@eclaird: Une fois que vous avez absolument * demandé * unicode, appelez 'unicode()' sur tout ce que vous avez et appelez-le bien. – Teddy

0

Une autre option consiste à utiliser des assertions. Cela dépend si le fait de passer un type non-unicode dans vos méthodes doit être considéré comme une erreur de programmation qui devrait être évidente pendant le développement.

import types 
class Foo: 
    def set_something(self, string): 
     assert isinstance(string, types.UnicodeType), 'String is not unicode' 
     self.something = string 

Cela déclenche une exception AssertionError chaque fois string est pas de type unicode, mais seulement lorsque le interpretter Python est exécuté en mode "deubg". Si vous exécutez Python avec l'option -O, l'affirmation est efficacement ignorée par l'interpréteur.

+0

Absolument, j'ai pensé à cela aussi, mais figurait que les décorateurs seraient plus propres à le faire. – tuomur

+0

Qui vous a l'air plus propre? L'affirmation de l'OMI est d'autant plus évidente que les contrôles sont là au début de la méthode, pas cachés dans une classe qui pourrait être importée d'ailleurs. Vous bénéficiez également des avantages en termes de performances de l'affirmation de devenir un NOP lors de l'exécution de python avec '-O'. – mhawke

Questions connexes