2010-03-26 5 views
19

Quelle est la bonne façon de faire une vérification d'erreur dans une classe? Élever des exceptions? Définition d'un dictionnaire de variables d'instance "errors" contenant toutes les erreurs et le renvoyant?Façon correcte en Python pour élever les erreurs lors de la définition des variables

Est-il mauvais d'imprimer des erreurs d'une classe? Dois-je retourner False si je déclenche une exception?

Je veux juste m'assurer que je fais les choses correctement. Ci-dessous un exemple de code:

@property 
def password(self): 
    return self._password 

@password.setter 
def password(self,password): 
    # Check that password has been completed 
    try: 
     # Check that password has a length of 6 characters 
     if (len(password) < 6): 
      raise NameError('Your password must be greater \ 
          than 6 characters') 

    except NameError: 
     print 'Please choose a password' 
     return False 

    except TypeError: 
     print 'Please choose a password' 
     return False                                 

    #Set the password 
    self._password = password 

    #Encrypt the password 
    password_md5 = md5.new() 
    password_md5.update(password) 
    self._password_md5 = password_md5.hexdigest() 
+1

Trop de choses nommées 'mot de passe 'dans ce code. (la première fonction, la deuxième fonction, et l'argument de la deuxième fonction.) pyflakes sera votre ami. – keturn

+0

@keturn: il s'agit d'un modèle affiché dans la docs pour la fonction 'property()'. Regardez l'exemple de code dans les documents qui utilisent le décorateur '.setter' (https://docs.python.org/3/library/functions.html#property). A l'intérieur de la méthode setter, le mot de passe est une variable locale (paramètre). Les autres noms sont dans un espace de noms différent (ils appartiennent à la classe). – jfs

Répondre

28

Votre code est hors contexte donc n'est pas évident le bon choix.Après quelques conseils:

  • Ne pas utiliser NameError exception, il est utilisé quand un nom, comme l'exception dit lui-même, ne se trouve pas dans la portée locale ou globale, utilisez ValueError ou TypeError si les préoccupations d'exception la valeur ou le type du paramètre;

  • Ne pas imprimer les messages d'erreur. Lever des exceptions significatives avec un message d'erreur significatif:

    raise ValueError("password must be longer than 6 characters") 
    
  • De retour d'une valeur d'un setter n'a pas de sens alors que la cession ne constitue pas une expression, dire que vous ne pouvez pas vérifier la valeur d'une cession:

    if (user.password = 'short'): ... 
    
  • Augmentez simplement une exception dans le setter et laissez le code qui définit la propriété le gérer.

Exemple:

class Test: 

    minlen = 6 

    @property 
    def password(self): 
     return self._password 

    @password.setter 
    def password(self, value): 
     if not isinstance(value, basestring): 
      raise TypeError("password must be a string") 
     if len(value) < self.minlen: 
      raise ValueError("password must be at least %d character len" % \ 
           self.minlen) 
     self._password = value 

Regardez aussi this forms handling library, il les validateurs, here an example, sont des entités dans leur propre: elles peuvent être définies de façon dynamique avec un contrôle plus élevé et moins de code couplé, mais peut-être cela est beaucoup plus que ce dont vous avez besoin.

+1

C'était vraiment utile. Je vous remercie. – ensnare

+0

@mg, Great post (et grandes initiales!) Dans l'ensemble, mais je suis préoccupé par l'exemple à la fin. Vous semblez avoir inventé un décorateur de mot de passe, dont l'usage est assez étrange; voulez-vous dire '@ property' et nommer la première méthode' password'? De plus, vous devrez utiliser des classes de style nouveau si vous voulez utiliser les propriétés, c'est-à-dire changer la première ligne de l'exemple en 'class Test (object):' ou hériter d'une autre classe new-style. (Même si vous n'utilisiez pas encore les propriétés, vous devriez utiliser des classes de style nouveau.) –

+0

@Mike Graham: putain, la fatigue pourrait jouer de mauvaises blagues. vous avez raison pour le nom de propriété, la forme exacte est celle utilisée à l'origine par ensare, je préfère le bon vieux 'password = property (...)' mais je serais cohérent avec ensare sans vraiment connaître la nouvelle syntaxe 2.6. La deuxième observation n'est pas vraie: les propriétés peuvent être utilisées avec des classes de style –

10

La méthode standard de signaler une erreur en python consiste à lever une exception et laisser la poignée de code l'appelant. Soit laisser le TypeError & TypeError continuer vers le haut, ou les attraper et déclencher une exception InvalidPassword que vous définissez. Bien qu'il soit possible de renvoyer un indicateur succès/échec ou un code d'erreur de la fonction comme vous l'avez fait, il est déconseillé - il est facile pour l'appelant d'oublier de vérifier la valeur de retour et de perdre des erreurs. De plus, vous renvoyez une valeur d'un accesseur de propriété - cela n'a aucun sens en Python car les affectations ne sont pas des expressions et ne peuvent pas renvoyer de valeur.

Vous ne devez également jamais imprimer un message pour l'utilisateur dans votre gestion des exceptions - que se passe-t-il si vous souhaitez ultérieurement utiliser la fonction ou la classe dans un programme d'interface graphique? Dans ce cas, votre relevé d'impression n'aura nulle part où imprimer. Consigner une erreur dans un fichier journal (en utilisant le module de journalisation de Python) est souvent utile pour le débogage.

4

Généralement, vous devez indiquer les erreurs qui se propagent en utilisant des exceptions. Si vous découvrez une erreur de quelque chose que vous venez de vérifier et que vous pouvez la traiter immédiatement, il n'est pas nécessaire de déclencher une exception.

Dans le cas particulier d'un setter, par exemple, renvoyer False ou toute autre chose n'aidera pas. La définition des variables d'instance que vous devez vérifier est très sous-optimale, car vous pourriez manquer une erreur sur l'accident.

print n'est généralement pas une bonne réponse à une erreur. Dans ce cas, il semble que vous souhaitiez indiquer à l'utilisateur final qu'il doit utiliser un mot de passe différent. Il semble que vous devriez appeler une méthode qui provoque la page Web avec le formulaire pour expliquer à l'utilisateur ce qui s'est mal passé; vous pouvez appeler la méthode qui le fait dans votre classe ou déclencher une exception qui se propagera et sera éventuellement capturée et utilisée à cette fin. (Ceci est un conseil général Je ne sais pas assez sur Pylons pour vous dire comment il veut que vous fassiez ceci.)

Vous ne devriez pas augmenter vos propres exceptions NameError. NameError prettymuch indique toujours une faute de frappe dans votre programme, et en tant que tel, vous ne voulez généralement pas l'attraper. En l'attrapant, vous introduisez une incertitude inutile dans un programme. Cela ressemble à ce qu'il pourrait être quelque chose de plus comme ValueError ou une sous-classe de celui-ci (class InvalidPasswordError(ValueError): pass).

Je ne comprends pas pourquoi vous vérifiez TypeError. Vous devriez toujours comprendre ce qui aurait causé une exception que vous avez attrapé. Si vous faites dans ce cas, c'est génial; Je ne peux pas comprendre quelle erreur soulèverait TypeError que vous pourriez traiter avec soin en demandant à l'utilisateur.

Votre technique de réception du mot de passe en clair et de stockage de son hachage md5 n'est pas très sécurisée. Vous devriez regarder quelque chose comme AuthKit qui pourrait rendre ce processus plus sûr et abstrait.

Questions connexes