Come si solleva un'eccezione ValueError?


115

Ho questo codice che trova l'indice più grande di un carattere specifico in una stringa, tuttavia vorrei che sollevasse a ValueErrorquando il carattere specificato non si trova in una stringa.

Quindi qualcosa del genere:

contains('bababa', 'k')

risulterebbe in un:

ValueError: could not find k in bababa

Come posso fare questo?

Ecco il codice corrente per la mia funzione:

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

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

  return list[-1]

5
Proprio così, alza ValueError () hahaha
slezica

@ user531225: Puoi accettare un'altra risposta in modo che io possa cancellare la mia. Grazie :)
pyfunc

@ THC4k: così strano che restituisce la posizione dell'occorrenza più a destra invece del conteggio.
John Machin

@ErikAllik: Ovviamente lo ha fatto - ha pubblicato su StackOverflow. Cosa c'è che non va?
Michael Scheper

Risposte:


178

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


2
Lo sapevi che, se non vuoi usare il messaggio, puoi semplicemente farlo al raise ValueErrorposto di raise ValueError()?
Tomasz Gandor

27

Ecco una versione rivista del tuo codice che funziona ancora e inoltre illustra come sollevare un ValueErrornel modo desiderato. A proposito, penso find_last(), find_last_index()o qualcosa di simile sarebbe un nome più descrittivo per questa funzione. Ad aumentare la possibile confusione c'è il fatto che Python ha già un metodo di oggetto contenitore denominato __contains__()che fa qualcosa di leggermente diverso, dal punto di vista dei test di appartenenza.

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'

Aggiornamento: un modo sostanzialmente più semplice

Wow! Ecco una versione molto più concisa, essenzialmente una riga singola, che è probabilmente anche più veloce perché inverte (tramite [::-1]) la stringa prima di eseguire una ricerca in avanti attraverso di essa per il primo carattere corrispondente e lo fa utilizzando il index()metodo della stringa integrato veloce . Per quanto riguarda la tua domanda reale, un piccolo vantaggio bonus che viene fornito con l'uso index()è che solleva già un ValueErrorquando la sottostringa del carattere non viene trovata, quindi non è richiesto nulla di aggiuntivo per farlo accadere.

Eccolo insieme a un rapido unit test:

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

2a funzione: l'OP ha bisogno / vuole un forloop. 1a funzione: FAIL per contains('foo', 'f').
John Machin

1
@ John Machin: Risolto bug che hai trovato nella prima funzione, grazie per averlo portato alla mia attenzione. Non vedo nulla nella domanda dell'OP o nei commenti sottostanti che indichi che hanno bisogno o vogliono un forciclo in una risposta, sebbene uno appaia nel loro codice. Comunque la mia prima funzione mostra loro come fare raisea ValueErrorquando il personaggio non viene trovato, che è quello che hanno chiesto. e ho illustrato come fare nel contesto di un file for. Anche se forper qualche motivo ne vogliono una , penso che altri potrebbero trovare la seconda versione senza almeno un po 'interessante.
martineau

"Voglio usare il ciclo for :-)" era un primo commento alla risposta ora eliminata di @pyfunc
John Machin

1
@ John Machin: Non credo che possa essere ritenuto responsabile per non aver rispettato le richieste nei commenti di risposte cancellate che non ho e non posso vedere. Tuttavia, anche se la mia seconda funzione non utilizza un forciclo, si fa in modo di rispondere alla domanda reale su come raiseun ValueErrorquando il personaggio non si trova nella stringa - cioè chiamando qualcos'altro che fa per voi. C'è anche la prospettiva che l'OP possa superare la loro for-fixation o qualunque cosa sia dopo aver visto una forsoluzione sans- o aver acquisito più familiarità con Python in seguito.
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
>>>

4
>>> response='bababa'
...  if "K" in response.text:
...     raise ValueError("Not found")

1
Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo su come e / o perché risolve il problema migliorerebbe il valore a lungo termine della risposta.
Paperino
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.