You are here: Partenza > Dive Into Python > Test delle unità di codice > roman.py, fase 4 | << >> | ||||
Dive Into PythonPython per programmatori esperti |
Ora che la funzione toRoman è completa, è tempo di cominciare a scrivere il codice di fromRoman. Grazie alla nostra struttura dati dettagliata che mappa i singoli numeri romani elementari negli interi corrispondenti, la cosa non è più difficile dell'aver scritto la funzione toRoman.
Se non lo avete ancora fatto, potete scaricare questo ed altri esempi usati in questo libro.
"""Convert to and from Roman numerals""" #Define exceptions class RomanError(Exception): pass class OutOfRangeError(RomanError): pass class NotIntegerError(RomanError): pass class InvalidRomanNumeralError(RomanError): pass #Define digit mapping romanNumeralMap = (('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100), ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1)) # toRoman function omitted for clarity (it hasn’t changed) def fromRoman(s): """convert Roman numeral to integer""" result = 0 index = 0 for numeral, integer in romanNumeralMap: while s[index:index+len(numeral)] == numeral: result += integer index += len(numeral) return result
Lo schema qui è lo stesso che in toRoman. Si itera sulla struttura dati che definisce i numeri romani (una tupla di tuple) ed invece che cercare il valore intero più alto, fino a che ciò risulta possibile, cerchiamo il numero romano “più alto”, sempre fino a che ciò risulta possibile. |
Se non è chiaro come funziona fromRoman, potete aggiungere un'istruzione di stampa alla fine del ciclo while:
while s[index:index+len(numeral)] == numeral: result += integer index += len(numeral) print 'found', numeral, ', adding', integer
>>> import roman4 >>> roman4.fromRoman('MCMLXXII') found M , adding 1000 found CM , adding 900 found L , adding 50 found X , adding 10 found X , adding 10 found I , adding 1 found I , adding 1 1972
fromRoman should only accept uppercase input ... FAIL toRoman should always return uppercase ... ok fromRoman should fail with malformed antecedents ... FAIL fromRoman should fail with repeated pairs of numerals ... FAIL fromRoman should fail with too many repeated numerals ... FAIL fromRoman should give known result with known input ... ok toRoman should give known result with known input ... ok fromRoman(toRoman(n))==n for all n ... ok toRoman should fail with non-integer input ... ok toRoman should fail with negative input ... ok toRoman should fail with large input ... ok toRoman should fail with 0 input ... ok
Due notizie importanti qui. La prima è che fromRoman funziona per input validi, almeno per i valori noti che usiamo per il test. | |
La seconda è che il nostro test di consistenza è anch'esso superato con successo. Combinato con il test sui valori noti, possiamo essere ragionevolmente sicuri che sia toRoman che fromRoman funzionino in modo corretto con tutti i valori noti. (La cosa non è garantita: è teoricamente possibile che toRoman abbia un baco che produca il numero romano sbagliato per qualche particolare insieme di input e che fromRoman abbia un baco reciproco rispetto al primo che produca lo stesso insieme di valori interi per i quali toRoman produce i numeri romani sbagliati. A seconda dell'uso previsto delle funzioni e dei loro requisiti, questo può essere o meno una preoccupazione reale; se lo è, potete scrivete un test sufficientemente comprensivo da escludere tale preoccupazione.) |
====================================================================== FAIL: fromRoman should only accept uppercase input ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 156, in testFromRomanCase roman4.fromRoman, numeral.lower()) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ====================================================================== FAIL: fromRoman should fail with malformed antecedents ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 133, in testMalformedAntecedent self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ====================================================================== FAIL: fromRoman should fail with repeated pairs of numerals ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 127, in testRepeatedPairs self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ====================================================================== FAIL: fromRoman should fail with too many repeated numerals ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 122, in testTooManyRepeatedNumerals self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ---------------------------------------------------------------------- Ran 12 tests in 1.222s FAILED (failures=4)
<< roman.py, fase 3 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |
roman.py, fase 5 >> |