.


:




:

































 

 

 

 





Like many programming languages, Python has an assert statement. Heres how it works.

, Python . .

>>> assert 1 + 1 == 2 ①
>>> assert 1 + 1 == 3 ②
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
>>> assert 2 + 2 == 5, "Only for very large values of 2" ③
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Only for very large values of 2


① assert . , 1 + 1 == 2 True, assert .

② False, assert .

③ , AssertionError.

,

assert len(unique_characters) <= 10, 'Too many letters'

if len(unique_characters) > 10:
raise AssertionError('Too many letters')


. , , .

-

-, , .

>>> unique_characters = {'E', 'D', 'M', 'O', 'N', 'S', 'R', 'Y'}
>>> gen = (ord(c) for c in unique_characters) ①
>>> gen ②
<generator object <genexpr> at 0x00BADC10>
>>> next(gen) ③
69
>>> next(gen)
68
>>> tuple(ord(c) for c in unique_characters) ④
(69, 68, 77, 79, 78, 83, 82, 89)

① -, . , , .

② - .

③ next(gen) .

④ , , , - tuple(), list(), set(). - "" ord(c) for c in unique_characters tuple() , Python , -.

- cpu ram. , ( tuple() set()), !

, :

def ord_map(a_string):
for c in a_string:
yield ord(c)

gen = ord_map(unique_characters)

- , .

 

)

( )

. . , , ( ). . , ! , , . !

. , : . , , .

:

1. .

2. : , , .

3. , , 1 3999. , , , 6, 1000. 1 3999.

4. 0 .

5. .

6. .

, roman.py. , to_roman() from_roman(). to_roman() 1 3999 ,

. - : , , to_roman() , . : , , .

(test-driven-development, TDD). to_roman(), from_roman() , , . Python -, unittest.

, . -, . , . - , .

  • . , .
  • , , .
  • , - , . ( , , commit.)
  • , , . ( code sprints ( ?:)???). , , , . .)

.

(test case) .

  • , .
  • , ,
  • , ( )

.

, () : 1. to_roman() 1 3999

, ... , -. , __init__(). , . __main__, . - , .

import roman1
import unittest
class KnownValues(unittest.TestCase): ①
known_values = ((1, 'I'),
(2, 'II'),
(3, 'III'),
(4, 'IV'),
(5, 'V'),
(6, 'VI'),
(7, 'VII'),
(8, 'VIII'),
(9, 'IX'),
(10, 'X'),
(50, 'L'),
(100, 'C'),
(500, 'D'),
(1000, 'M'),
(31, 'XXXI'),
(148, 'CXLVIII'),
(294, 'CCXCIV'),
(312, 'CCCXII'),
(421, 'CDXXI'),
(528, 'DXXVIII'),
(621, 'DCXXI'),
(782, 'DCCLXXXII'),
(870, 'DCCCLXX'),
(941, 'CMXLI'),
(1043, 'MXLIII'),
(1110, 'MCX'),
(1226, 'MCCXXVI'),
(1301, 'MCCCI'),
(1485, 'MCDLXXXV'),
(1509, 'MDIX'),
(1607, 'MDCVII'),
(1754, 'MDCCLIV'),
(1832, 'MDCCCXXXII'),
(1993, 'MCMXCIII'),
(2074, 'MMLXXIV'),
(2152, 'MMCLII'),
(2212, 'MMCCXII'),
(2343, 'MMCCCXLIII'),
(2499, 'MMCDXCIX'),
(2574, 'MMDLXXIV'),
(2646, 'MMDCXLVI'),
(2723, 'MMDCCXXIII'),
(2892, 'MMDCCCXCII'),
(2975, 'MMCMLXXV'),
(3051, 'MMMLI'),
(3185, 'MMMCLXXXV'),
(3250, 'MMMCCL'),
(3313, 'MMMCCCXIII'),
(3408, 'MMMCDVIII'),
(3501, 'MMMDI'),
(3610, 'MMMDCX'),
(3743, 'MMMDCCXLIII'),
(3844, 'MMMDCCCXLIV'),
(3888, 'MMMDCCCLXXXVIII'),
(3940, 'MMMCMXL'),
(3999, 'MMMCMXCIX')) ②
def test_to_roman_known_values(self): ③
'''to_roman should give known result with known input'''
for integer, numeral in self.known_values:
result = roman1.to_roman(integer) ④
self.assertEqual(numeral, result) ⑤
if __name__ == '__main__':
unittest.main()

① TestCase unittest. , .

② "/", . 10 , (3999), , , . , .

③ , . , - , - .

④ to_roman(). (, , , , .) , (API) to_roman(): ( ). API , . , - , to_roman(). . to_roman() . to_roman() , .

⑤ , to_roman() , , , , . , AssertEqual TestCase () . to_roman() (result) , (numeral), assertEqual . , assertEqual . , to_roman() , assertEqual , test_to_roman_known_values , , to_roman() .

, to_roman(). -, , , . , , ! Unit testing : , . , , - , .

# roman1.py
def to_roman(n):
'''convert integer to Roman numeral'''
pass ①

① API to_roman(), . ( .) , Python - pass, ... . romantest1.py on . -v, (verbose), , . , :

you@localhost:~/diveintopython3/examples$ python3 romantest1.py -v
test_to_roman_known_values (__main__.KnownValues) ①
to_roman should give known result with known input... FAIL ②
======================================================================
FAIL: to_roman should give known result with known input
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest1.py", line 73, in test_to_roman_known_values
self.assertEqual(numeral, result)
AssertionError: 'I'!= None ③
----------------------------------------------------------------------
Ran 1 test in 0.016s ④
FAILED (failures=1) ⑤

① unittest.main(), . - romantest.py. ; , mfr + . , unittest.TestCase.

② unittest - . , .

③ , . assertEqual() (AssertionError), 'I' to_roman(1), . ( , None, null Python.)

④ , unittest , .

⑤ , . Unittest . assertXYZ, assertEqual assertRaises, , . - , .

, to_roman().

roman_numeral_map = (('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)) ①
def to_roman(n):
'''convert integer to Roman numeral'''
result = ''
for numeral, integer in roman_numeral_map:
while n >= integer: ②
result += numeral
n -= integer
return result

① roman_numeral_map - , : ; ( , M I); . - (, ). ; CM ( ). to_roman().

② , roman_numeral_map, - . roman_numeral_map, , . , , .

, to_roman(), print() :

while n >= integer:
result += numeral
n -= integer
print('subtracting {0} from input, adding {1} to output'.format(integer, numeral))

:

>>> import roman1
>>> roman1.to_roman(1424)
subtracting 1000 from input, adding M to output
subtracting 400 from input, adding CD to output
subtracting 10 from input, adding X to output
subtracting 10 from input, adding X to output
subtracting 4 from input, adding IV to output
'MCDXXIV'

, to_roman() , . ?

you@localhost:~/diveintopython3/examples$ python3 romantest1.py -v
test_to_roman_known_values (__main__.KnownValues)
to_roman should give known result with known input... ok
----------------------------------------------------------------------
Ran 1 test in 0.016s
OK

1. ! to_roman() known values. , , , , (3999), , (3888). , .

? . ?

; , . - .

>>> import roman1
>>> roman1.to_roman(4000)
'MMMM'
>>> roman1.to_roman(5000)
'MMMMM'
>>> roman1.to_roman(9000) ①
'MMMMMMMMM'

1. , ! , , , . - ; , . " ", . "" - .

, ? - : to_roman() OutOfRangeError, 3999. ?

class ToRomanBadInput(unittest.TestCase): ①
def test_too_large(self): ②
'''to_roman should fail with large input'''
self.assertRaises(roman2.OutOfRangeError, roman2.to_roman, 4000) ③

1. , - unittest.TestCase. ( ), , . " " , - .

2. , - , - .

3. unittest.TestCase assertRaises, : , . ( , assertRaises , .)

. to_roman() , ( try-catch), assertRaises . - , (roman2.OutOfRangeError), (to_roman()), (4000). assertRaises to_roman() , roman2.OutOfRangeError.

, to_roman() ; . , , Python ?

, ?

you@localhost:~/diveintopython3/examples$ python3 romantest2.py -v
test_to_roman_known_values (__main__.KnownValues)
to_roman should give known result with known input... ok
test_too_large (__main__.ToRomanBadInput)
to_roman should fail with large input... ERROR ①
======================================================================
ERROR: to_roman should fail with large input
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest2.py", line 78, in test_too_large
self.assertRaises(roman2.OutOfRangeError, roman2.to_roman, 4000)
AttributeError: 'module' object has no attribute 'OutOfRangeError' ②
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (errors=1)

1. ( ), "", . . : , . , , , . - , . , .

2. ? . OutOfRangeError. , assertRaises(), . , assertRaises() . - to_roman() OutOfRangeError.

- OutOfRangeError roman2.py.

class OutOfRangeError(ValueError): ①
pass ②

1. - . out of range . ValueError. ( Exception), .

2. - , . pass , Python.

.

you@localhost:~/diveintopython3/examples$ python3 romantest2.py -v
test_to_roman_known_values (__main__.KnownValues)
to_roman should give known result with known input... ok
test_too_large (__main__.ToRomanBadInput)
to_roman should fail with large input... FAIL ①
======================================================================
FAIL: to_roman should fail with large input
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest2.py", line 78, in test_too_large
self.assertRaises(roman2.OutOfRangeError, roman2.to_roman, 4000)
AssertionError: OutOfRangeError not raised by to_roman ②
----------------------------------------------------------------------
Ran 2 tests in 0.016s
FAILED (failures=1)

1. - , . ! , assertRaises() to_roman() .

2. , to_roman() OutOfRangeError, " ". ! , , , .

.

def to_roman(n):
'''convert integer to Roman numeral'''
if n > 3999:
raise OutOfRangeError('number out of range (must be less than 4000)') ①
result = ''
for numeral, integer in roman_numeral_map:
while n >= integer:
result += numeral
n -= integer
return result

1. : 3999, OutOfRangeError. , , ( , - ).

? :

you@localhost:~/diveintopython3/examples$ python3 romantest2.py -v
test_to_roman_known_values (__main__.KnownValues)
to_roman should give known result with known input... ok
test_too_large (__main__.ToRomanBadInput)
to_roman should fail with large input... ok ①
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK

1. ! . , , , 2 "", "". , .

, ""

"" . , 0.

>>> import roman2
>>> roman2.to_roman(0)
''
>>> roman2.to_roman(-1)
''

. .

class ToRomanBadInput(unittest.TestCase):
def test_too_large(self):
'''to_roman should fail with large input'''
self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 4000) ①

def test_zero(self):
'''to_roman should fail with 0 input'''
self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 0) ②

def test_negative(self):
'''to_roman should fail with negative input'''
self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, -1) ③

1. test_too_large() . , .

2. : test_zero(). test_too_large(), assertRaises(), unittest.TestCase, to_roman() "0", , , OutOfRangeError.

3. test_negative() , -1 to_roman(). OutOfRangeError ( ), .

, :

you@localhost:~/diveintopython3/examples$ python3 romantest3.py -v
test_to_roman_known_values (__main__.KnownValues)
to_roman should give known result with known input... ok
test_negative (__main__.ToRomanBadInput)
to_roman should fail with negative input... FAIL
test_too_large (__main__.ToRomanBadInput)
to_roman should fail with large input... ok
test_zero (__main__.ToRomanBadInput)
to_roman should fail with 0 input... FAIL
======================================================================
FAIL: to_roman should fail with negative input
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest3.py", line 86, in test_negative
self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, -1)
AssertionError: OutOfRangeError not raised by to_roman
======================================================================
FAIL: to_roman should fail with 0 input
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest3.py", line 82, in test_zero
self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 0)
AssertionError: OutOfRangeError not raised by to_roman
----------------------------------------------------------------------
Ran 4 tests in 0.000s
FAILED (failures=2)

. , . , .

def to_roman(n):
'''convert integer to Roman numeral'''
if not (0 < n < 4000): ①
raise OutOfRangeError('number out of range (must be 1..3999)') ②

result = ''
for numeral, integer in roman_numeral_map:
while n >= integer:
result += numeral
n -= integer
return result

1. Python: . " ((0 < n) (n < 4000))", . "" .

2. . , , .

, , , .

you@localhost:~/diveintopython3/examples$ python3 romantest3.py -v
test_to_roman_known_values (__main__.KnownValues)
to_roman should give known result with known input... ok
test_negative (__main__.ToRomanBadInput)
to_roman should fail with negative input... ok
test_too_large (__main__.ToRomanBadInput)
to_roman should fail with large input... ok
test_zero (__main__.ToRomanBadInput)
to_roman should fail with 0 input... ok
----------------------------------------------------------------------
Ran 4 tests in 0.016s
OK

...

- .

>>> import roman3
>>> roman3.to_roman(0.5) ①
''
>>> roman3.to_roman(1.0) ②
'I'

1. , .

2. , .

. .

- . -, NotIntegerError.

# roman4.py
class OutOfRangeError(ValueError): pass
class NotIntegerError(ValueError): pass

NotIntegerError.

class ToRomanBadInput(unittest.TestCase):
.
.
.
def test_non_integer(self):
'''to_roman should fail with non-integer input'''
self.assertRaises(roman4.NotIntegerError, roman4.to_roman, 0.5)

, .

you@localhost:~/diveintopython3/examples$ python3 romantest4.py -v
test_to_roman_known_values (__main__.KnownValues)
to_roman should give known result with known input... ok
test_negative (__main__.ToRomanBadInput)
to_roman should fail with negative input... ok
test_non_integer (__main__.ToRomanBadInput)
to_roman should fail with non-integer input... FAIL
test_too_large (__main__.ToRomanBadInput)
to_roman should fail with large input... ok
test_zero (__main__.ToRomanBadInput)
to_roman should fail with 0 input... ok
======================================================================
FAIL: to_roman should fail with non-integer input
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest4.py", line 90, in test_non_integer
self.assertRaises(roman4.NotIntegerError, roman4.to_roman, 0.5)
AssertionError: NotIntegerError not raised by to_roman
----------------------------------------------------------------------
Ran 5 tests in 0.000s
FAILED (failures=1)

.

def to_roman(n):
'''convert integer to Roman numeral'''
if not (0 < n < 4000):
raise OutOfRangeError('number out of range (must be 1..3999)')
if not isinstance(n, int): ①
raise NotIntegerError('non-integers can not be converted') ②
result = ''
for numeral, integer in roman_numeral_map:
while n >= integer:
result += numeral
n -= integer
return result

1. isinstance() , (, - ).

2. n , NotIntegerError.

, .

you@localhost:~/diveintopython3/examples$ python3 romantest4.py -v
test_to_roman_known_values (__main__.KnownValues)
to_roman should give known result with known input... ok
test_negative (__main__.ToRomanBadInput)
to_roman should fail with negative input... ok
test_non_integer (__main__.ToRomanBadInput)
to_roman should fail with non-integer input... ok
test_too_large (__main__.ToRomanBadInput)
to_roman should fail with large input... ok
test_zero (__main__.ToRomanBadInput)
to_roman should fail with 0 input... ok
----------------------------------------------------------------------
Ran 5 tests in 0.000s
OK

to_roman() , , from_roman().

, . . , ; , . , , .

. , , , from_roman() .

. . known_values:

def test_from_roman_known_values(self):
'''from_roman should give known result with known input'''
for integer, numeral in self.known_values:
result = roman5.from_roman(numeral)
self.assertEqual(integer, result)

. to_roman() from_roman() . , . " ", to_roman() , from_roman(), :

n = from_roman(to_roman(n)) for all values of n

all values [1, 3999]. , to_roman(), from_roman() :

class RoundtripCheck(unittest.TestCase):
def test_roundtrip(self):
'''from_roman(to_roman(n))==n for all n'''
for integer in range(1, 4000):
numeral = roman5.to_roman(integer)
result = roman5.from_roman(numeral)
self.assertEqual(integer, result)

- , from_roman():

you@localhost:~/diveintopython3/examples$ python3 romantest5.py
E.E....
======================================================================
ERROR: test_from_roman_known_values (__main__.KnownValues)
from_roman should give known result with known input
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest5.py", line 78, in test_from_roman_known_values
result = roman5.from_roman(numeral)
AttributeError: 'module' object has no attribute 'from_roman'
======================================================================
ERROR: test_roundtrip (__main__.RoundtripCheck)
from_roman(to_roman(n))==n for all n
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest5.py", line 103, in test_roundtrip
result = roman5.from_roman(numeral)
AttributeError: 'module' object has no attribute 'from_roman'
----------------------------------------------------------------------
Ran 7 tests in 0.019s
FAILED (errors=2)

:

# roman5.py
def from_roman(s):
'''convert Roman numeral to integer'''

( ? , , . . Python. , . ; !)

:

you@localhost:~/diveintopython3/examples$ python3 romantest5.py
F.F....
======================================================================
FAIL: test_from_roman_known_values (__main__.KnownValues)
from_roman should give known result with known input
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest5.py", line 79, in test_from_roman_known_values
self.assertEqual(integer, result)
AssertionError: 1!= None
======================================================================
FAIL: test_roundtrip (__main__.RoundtripCheck)
from_roman(to_roman(n))==n for all n
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest5.py", line 104, in test_roundtrip
self.assertEqual(integer, result)
AssertionError: 1!= None
----------------------------------------------------------------------
Ran 7 tests in 0.002s
FAILED (failures=2)

from_roman():

def from_roman(s):
"""convert Roman numeral to integer"""
result = 0
index = 0
for numeral, integer in roman_numeral_map:
while s[index:index+len(numeral)] == numeral: ①
result += integer
index += len(numeral)
return result

, to_roman(). roman_numeral_map, , , , , .

, from_roman(), :

def from_roman(s):
"""convert Roman numeral to integer"""
result = 0
index = 0
for numeral, integer in roman_numeral_map:
while s[index:index+len(numeral)] == numeral:
result += integer
index += len(numeral)
print('found', numeral, 'of length', len(numeral), ', adding', integer)
>>> import roman5
>>> roman5.from_roman('MCMLXXII')
found M, of length 1, adding 1000
found CM of length 2, adding 900
found L of length 1, adding 50
found X of length 1, adding 10
found X of length 1, adding 10
found I of length 1, adding 1
found I of length 1, adding 1
1972

:

you@localhost:~/diveintopython3/examples$ python3 romantest5.py
.......
----------------------------------------------------------------------
Ran 7 tests in 0.060s
OK


. . -, from_roman() ( , ); -, "" . , to_roman() from_roman() . ( , . , to_roman() , - , from_roman() "" , - , . , .)

""

Now that the from_roman() function works properly with good input, it's time to fit in the last piece of the puzzle: making it work properly with bad input. That means finding a way to look at a string and determine if it's a valid Roman numeral. This is inherently more difficult than validating numeric input in the to_roman() function, but you have a powerful tool at your disposal: regular expressions. (If youre not familiar with regular expressions, now would be a good time to read the regular expressions chapter.) As you saw in Case Study: Roman Numerals, there are several simple rules for constructing a Roman numeral, using the letters M, D, C, L, X, V, and I. Let's review the rules: 1. Sometimes characters are additive. I is 1, II is 2, and III is 3. VI is 6 (literally, 5 and 1), VII is 7, and VIII is 8. 2. The tens characters (I, X, C, and M) can be repeated up to three times. At 4, you need to subtract from the next highest fives character. You can't represent 4 as IIII; instead, it is represented as IV (1 less than 5). 40 is written as XL (10 less than 50), 41 as XLI, 42 as XLII, 43 as XLIII, and then 44 as XLIV (10 less than 50, then 1 less than 5). 3. Sometimes characters are the opposite of additive. By putting certain characters before others, you subtract from the final value. For example, at 9, you need to subtract from the next highest tens character: 8 is VIII, but 9 is IX (1 less than 10), not VIIII (since the I character can not be repeated four times). 90 is XC, 900 is CM. 4. The fives characters can not be repeated. 10 is always represented as X, never as VV. 100 is always C, never LL. 5. Roman numerals are read left to right, so the order of characters matters very much. DC is 600; CD is a completely different number (400, 100 less than 500). CI is 101; IC is not even a valid Roman numeral (because you can't subtract 1 directly from 100; you would need to write it as XCIX, 10 less than 100, then 1 less than 10). Thus, one useful test would be to ensure that the from_roman() function should fail when you pass it a string with too many repeated numerals. How many is too many depends on the numeral.

class FromRomanBadInput(unittest.TestCase):
def test_too_many_repeated_numerals(self):
'''from_roman should fail with too many repeated numerals'''
for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)

Another useful test would be to check that certain patterns arent repeated. For example, IX is 9, but IXIX is never valid.

def test_repeated_pairs(self):
'''from_roman should fail with repeated pairs of numerals'''
for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)

A third test could check that numerals appear in the correct order, from highest to lowest value. For example, CL is 150, but LC is never valid, because the numeral for 50 can never come before the numeral for 100. This test includes a randomly chosen set of invalid antecedents: I before M, V before X, and so on.

def test_malformed_antecedents(self):
'''from_roman should fail with malformed antecedents'''
for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV', 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)

Each of these tests relies the from_roman() function raising a new exception, InvalidRomanNumeralError, which we havent defined yet.

def test_malformed_antecedents(self):
# roman6.py
class InvalidRomanNumeralError(ValueError): pass

All three of these tests should fail, since the from_roman() function doesnt currently have any validity checking. (If they dont fail now, then what the heck are they testing?)

you@localhost:~/diveintopython3/examples$ python3 romantest6.py
FFF.......
======================================================================
FAIL: test_malformed_antecedents (__main__.FromRomanBadInput)
from_roman should fail with malformed antecedents
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest6.py", line 113, in test_malformed_antecedents
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
AssertionError: InvalidRomanNumeralError not raised by from_roman
======================================================================
FAIL: test_repeated_pairs (__main__.FromRomanBadInput)
from_roman should fail with repeated pairs of numerals
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest6.py", line 107, in test_repeated_pairs
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
AssertionError: InvalidRomanNumeralError not raised by from_roman
======================================================================
FAIL: test_too_many_repeated_numerals (__main__.FromRomanBadInput)
from_roman should fail with too many repeated numerals
----------------------------------------------------------------------
Traceback (most recent call last):
File "romantest6.py", line 102, in test_too_many_repeated_numerals
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
AssertionError: InvalidRomanNumeralError not raised by from_roman
----------------------------------------------------------------------
Ran 10 tests in 0.058s
FAILED (failures=3)

Good deal. Now, all we need to do is add the regular expression to test for valid Roman numerals into the from_roman() function.

CD

...

you@localhost:~/diveintopython3/examples$ python3 romantest7.py
..........
----------------------------------------------------------------------
Ran 10 tests in 0.066s
OK

... ... "", .

 

, . , . ? - .

>>> import roman7>>> roman7.from_roman('') ①0

① , . from_roman ( ) InvalidRomanNumeralError.

, .

class FromRomanBadInput(unittest.TestCase):... def testBlank(self): '''from_roman should fail with blank string''' self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, '') ①

① : from_roman() , InvalidRomanNumeralError. ; , , , .

, :

you@localhost:~/diveintopython3/examples$ python3 romantest8.py -vfrom_roman should fail with blank string... FAILfrom_roman should fail with malformed antecedents... okfrom_roman should fail with repeated pairs of numerals... okfrom_roman should fail with too many repeated numerals... okfrom_roman should give known result with known input... okto_roman should give known result with known input... okfrom_roman(to_roman(n))==n for all n... okto_roman should fail with negative input... okto_roman should fail with non-integer input... okto_roman should fail with large input... okto_roman should fail with 0 input... ok ======================================================================FAIL: from_roman should fail with blank string----------------------------------------------------------------------Traceback (most recent call last): File "romantest8.py", line 117, in test_blank self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, '')AssertionError: InvalidRomanNumeralError not raised by from_roman ----------------------------------------------------------------------Ran 11 tests in 0.171s FAILED (failures=1)

.

def from_roman(s): '''convert Roman numeral to integer''' if not s: ① raise InvalidRomanNumeralError('Input can not be blank') if not re.search(romanNumeralPattern, s): raise InvalidRomanNumeralError('Invalid Roman numeral: {}'.format(s)) ② result = 0 index = 0 for numeral, integer in romanNumeralMap: while s[index:index+len(numeral)] == numeral: result += integer index += len(numeral) return result

① 2 : .

② , , . Python 3.1 . , {0} format(), {} Python . : {} {0}, {} {1} .

you@localhost:~/diveintopython3/examples$ python3 romantest8.py -vfrom_roman should fail with blank string... ok ①from_roman should fail with malformed antecedents... okfrom_roman should fail with repeated pairs of numerals... okfrom_roman should fail with too many repeated numerals... okfrom_roman should give known result with known input... okto_roman should give known result with known input... okfrom_roman(to_roman(n))==n for all n... okto_roman should fail with negative input... okto_roman should fail with non-integer input... okto_roman should fail with large input... okto_roman should fail with 0 input... ok ----------------------------------------------------------------------Ran 11 tests in 0.156s OK ②

① , .

② , , . , !

. ( ) ; , , . , , , (, ) . , . , - - , . , , , "" . .





:


: 2016-11-18; !; : 487 |


:

:

, .
==> ...

888 - | 795 -


© 2015-2024 lektsii.org - -

: 0.147 .