Comment lever une ValueError?

115

J'ai ce code qui trouve le plus grand index d'un caractère spécifique dans une chaîne, mais je voudrais qu'il déclenche un ValueErrorlorsque le caractère spécifié ne se produit pas dans une chaîne.

Donc quelque chose comme ça:

contains('bababa', 'k')

entraînerait un:

ValueError: could not find k in bababa

Comment puis-je faire ceci?

Voici le code actuel de ma fonction:

def contains(string,char):
  list = []

  for i in range(0,len(string)):
      if string[i] == char:
           list = list + [i]

  return list[-1]
user531225
la source
5
Juste comme ça, augmentez ValueError () hahaha
slezica
@ user531225: Pouvez-vous accepter une autre réponse pour que je puisse supprimer la mienne. Merci :)
pyfunc
@ THC4k: Tellement bizarre que cela renvoie la position de l'occurrence la plus à droite au lieu du compte.
John Machin
@ErikAllik: Évidemment, il l'a fait - il a posté sur StackOverflow. Qu'est-ce qui ne va pas avec ça?
Michael Scheper

Réponses:

178

raise ValueError('could not find %c in %s' % (ch,str))

NPE
la source
2
Saviez-vous que si vous ne voulez pas utiliser le message, vous pouvez simplement le faire à la raise ValueErrorplace raise ValueError()?
Tomasz Gandor
27

Voici une version révisée de votre code qui fonctionne toujours et qui illustre comment élever un ValueErrorcomme vous le souhaitez. À propos, je pense find_last(), find_last_index()ou quelque chose de similaire serait un nom plus descriptif pour cette fonction. Ajout à la confusion possible est le fait que Python a déjà une méthode d'objet conteneur nommée __contains__()qui fait quelque chose d'un peu différent, en ce qui concerne les tests d'appartenance.

def contains(char_string, char):
    largest_index = -1
    for i, ch in enumerate(char_string):
        if ch == char:
            largest_index = i
    if largest_index > -1:  # any found?
        return largest_index  # return index of last one
    else:
        raise ValueError('could not find {!r} in {!r}'.format(char, char_string))

print(contains('mississippi', 's'))  # -> 6
print(contains('bababa', 'k'))  # ->
Traceback (most recent call last):
  File "how-to-raise-a-valueerror.py", line 15, in <module>
    print(contains('bababa', 'k'))
  File "how-to-raise-a-valueerror.py", line 12, in contains
    raise ValueError('could not find {} in {}'.format(char, char_string))
ValueError: could not find 'k' in 'bababa'

Mise à jour - Un moyen nettement plus simple

Hou la la! Voici une version beaucoup plus-essentiellement en une ligne qui est probablement plus rapide concise car elle inverse (via [::-1]) la chaîne avant de faire une recherche en avant à travers elle pour le premier caractère correspondant et il le fait en utilisant la chaîne intégrée rapide index()méthode . En ce qui concerne votre question réelle, un petit avantage supplémentaire qui vient avec l'utilisation index()est qu'il déclenche déjà un ValueErrorlorsque la sous-chaîne de caractères n'est pas trouvée, donc rien de plus n'est nécessaire pour que cela se produise.

Le voici avec un test unitaire rapide:

def contains(char_string, char):
    #  Ending - 1 adjusts returned index to account for searching in reverse.
    return len(char_string) - char_string[::-1].index(char) - 1

print(contains('mississippi', 's'))  # -> 6
print(contains('bababa', 'k'))  # ->
Traceback (most recent call last):
  File "better-way-to-raise-a-valueerror.py", line 9, in <module>
    print(contains('bababa', 'k'))
  File "better-way-to-raise-a-valueerror", line 6, in contains
    return len(char_string) - char_string[::-1].index(char) - 1
ValueError: substring not found
Martineau
la source
2ème fonction: l'OP a besoin / veut une forboucle. 1ère fonction: FAIL pour contains('foo', 'f').
John Machin
1
@John Machin: Correction d'un bug que vous avez trouvé dans la 1ère fonction, merci de l'avoir porté à mon attention. Je ne vois rien dans la question du PO ou dans les commentaires ci-dessous qui indique qu'ils ont besoin ou veulent une forboucle dans une réponse, bien que l'une apparaisse dans leur propre code. Quoi qu'il en soit ma 1ère leur montre comment la fonction d' raiseun ValueErrorlorsque le personnage ne se trouve pas qui est ce qu'ils ont demandé. et j'ai illustré comment faire dans le contexte d'un for. Même s'ils en veulent forpour une raison quelconque, je pense que d'autres pourraient trouver la 2ème version sans une au moins assez intéressante.
martineau
"Je veux utiliser une boucle for :-)" était un des premiers commentaires sur la réponse maintenant supprimée de @pyfunc
John Machin
1
@John Machin: Je ne pense pas que je puisse être tenu responsable de ne pas honorer les demandes dans les commentaires de réponses supprimées que je n'ai pas et que je ne peux pas voir. Cependant, même si ma 2ème fonction ne pas utiliser une forboucle, il ne d'une manière de répondre à la question réelle sur la façon d' raiseun ValueErrorlorsque le personnage ne se trouve pas dans la chaîne - à savoir en appelant quelque chose d' autre qui le fait pour vous. Il y a aussi la possibilité que l'OP puisse surmonter leur for-fixation ou quoi que ce soit après avoir vu une forsolution sans-solution ou se familiariser plus tard avec Python.
martineau
12
>>> def contains(string, char):
...     for i in xrange(len(string) - 1, -1, -1):
...         if string[i] == char:
...             return i
...     raise ValueError("could not find %r in %r" % (char, string))
...
>>> contains('bababa', 'k')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in contains
ValueError: could not find 'k' in 'bababa'
>>> contains('bababa', 'a')
5
>>> contains('bababa', 'b')
4
>>> contains('xbababa', 'x')
0
>>>
John Machin
la source
4
>>> response='bababa'
...  if "K" in response.text:
...     raise ValueError("Not found")
Kaushik Dey
la source
1
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire sur la façon et / ou pourquoi il résout le problème améliorerait la valeur à long terme de la réponse.
Donald Duck