2016-12-22 8 views
2

Я выполняю упражнение, которое я придумал в Learn Python the Hard Way (ex 48). Цель состоит в том, чтобы сгруппировать пользовательский ввод, обратившись к нашей лексике. Я использую нос, чтобы проверить свой скрипт, но я получаю несколько ошибок. Я получаю 5 неудач из 6, когда я запускаю nosetests. Я не понимаю, почему я получаю эти ошибки. Любая помощь?Python - разбиение и группировка пользовательского ввода

ошибки
FAIL: tests.ex48_tests.test_verbs 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "c:\python\lib\site-packages\nose\case.py", line 198, in runTest 
    self.test(*self.arg) 
    File "C:\Python\projects\skeleton2\tests\ex48_tests.py", line 13, in test_verbs 
    assert_equal(scan("go").result, [('verb', 'go')]) 
AssertionError: <bound method scan.result of <ex48.lexicon.scan object at 0x03A8F3F0>> != [('verb', 'go')] 

====================================================================== 
FAIL: tests.ex48_tests.test_stops 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "c:\python\lib\site-packages\nose\case.py", line 198, in runTest 
    self.test(*self.arg) 
    File "C:\Python\projects\skeleton2\tests\ex48_tests.py", line 21, in test_stops 
    assert_equal(scan("the").result(), [('stop', 'the')]) 
AssertionError: Lists differ: [('stop', 'the'), ('error', 'the')] != [('stop', 'the')] 

First list contains 1 additional elements. 
First extra element 1: 
('error', 'the') 

- [('stop', 'the'), ('error', 'the')] 
+ [('stop', 'the')] 

====================================================================== 
FAIL: tests.ex48_tests.test_noun 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "c:\python\lib\site-packages\nose\case.py", line 198, in runTest 
    self.test(*self.arg) 
    File "C:\Python\projects\skeleton2\tests\ex48_tests.py", line 29, in test_noun 
    assert_equal(scan("bear").result(), [('noun', 'bear')]) 
AssertionError: Lists differ: [('noun', 'bear'), ('error', 'bear')] != [('noun', 'bear')] 

First list contains 1 additional elements. 
First extra element 1: 
('error', 'bear') 

- [('noun', 'bear'), ('error', 'bear')] 
+ [('noun', 'bear')] 

====================================================================== 
FAIL: tests.ex48_tests.test_numbers 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "c:\python\lib\site-packages\nose\case.py", line 198, in runTest 
    self.test(*self.arg) 
    File "C:\Python\projects\skeleton2\tests\ex48_tests.py", line 35, in test_numbers 
    assert_equal(scan("1234").result(), [('number', 1234)]) 
AssertionError: Lists differ: [('error', '1234')] != [('number', 1234)] 

First differing element 0: 
('error', '1234') 
('number', 1234) 

- [('error', '1234')] 
?  --- - - 

+ [('number', 1234)] 
? ++++ 


====================================================================== 
FAIL: tests.ex48_tests.test_errors 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "c:\python\lib\site-packages\nose\case.py", line 198, in runTest 
    self.test(*self.arg) 
    File "C:\Python\projects\skeleton2\tests\ex48_tests.py", line 45, in test_errors 
    ('noun', 'princess')]) 
AssertionError: Lists differ: [('no[20 chars]r', 'bear'), ('error', 'IAS'), ('noun', 'princ[24 chars]ss')] != [('no[20 chars]r', 'IAS'), ('noun', 'princess')] 

First differing element 1: 
('error', 'bear') 
('error', 'IAS') 

First list contains 2 additional elements. 
First extra element 3: 
('noun', 'princess') 

+ [('noun', 'bear'), ('error', 'IAS'), ('noun', 'princess')] 
- [('noun', 'bear'), 
- ('error', 'bear'), 
- ('error', 'IAS'), 
- ('noun', 'princess'), 
- ('error', 'princess')] 

---------------------------------------------------------------------- 
Ran 6 tests in 0.027s 

FAILED (failures=5) 

lexicon.py

class scan(object): 
    dirs = ['north','south','east','west','down','up','left','right','back'] 
    verbs = ['go','stop','kill','eat'] 
    stops = ['the','in','of','from','at','it'] 
    nouns = ['door','princess','bear','cabinet'] 
    numbers = ['0','1','2','3','4','5','6','7','8','9'] 

    def __init__(self, user_input): 
     self.user_input = user_input 

    def result(self): 
     words = self.user_input.split() 
     results = [] 

     for item in words: 
      if item in scan.dirs: 
       result = ('direction', item.lower()) 
       results.append(result) 
      if item in scan.verbs: 
       result = ('verb', item.lower()) 
       results.append(result) 
      if item in scan.stops: 
       result = ('stop', item.lower()) 
       results.append(result) 
      if item in scan.nouns: 
       result =('noun', item.lower()) 
       results.append(result) 
      if item in scan.numbers: 
       result = ('number', int(item)) 
       results.append(result) 
      if item not in (scan.dirs or scan.verbs or scan.stops or 
          scan.nouns or scan.numbers): 
       result = ('error', item) 
       results.append(result) 

     return results 

lexicon_test.py

from nose.tools import * 
from ex48.lexicon import scan 


def test_direction(): 
    assert_equal(scan('north').result(), [('direction', 'north')]) 
    result = scan("north east south").result() 
    assert_equal(result, [('direction', 'north'), 
          ('direction', 'east'), 
          ('direction', 'south')]) 

def test_verbs(): 
    assert_equal(scan("go").result, [('verb', 'go')]) 
    result = scan("go kill eat").result() 
    assert_equal(result, [('verb', 'go'), 
          ('verb', 'eat') 
          ('verb', 'kill')]) 


def test_stops(): 
    assert_equal(scan("the").result(), [('stop', 'the')]) 
    result = scan("the in of").result() 
    assert_equal(result, [('stop', 'the'), 
          ('stop', ' in'), 
          ('stop', 'of')]) 


def test_noun(): 
    assert_equal(scan("bear").result(), [('noun', 'bear')]) 
    result = scan("bear princess").result() 
    assert_equal(result, [('noun', 'bear'), 
          ('noun', 'princess')]) 

def test_numbers(): 
    assert_equal(scan("1234").result(), [('number', 1234)]) 
    result = scan("3 91234").result() 
    assert_equal(result, [('number', 3), 
          ('number', 91234)]) 

def test_errors(): 
    assert_equal(scan("ASDFADFASDF").result(), [('error', 'ASDFADFASDF')]) 
    result = scan("bear IAS princess").result() 
    assert_equal(result, [('noun', 'bear'), 
          ('error', 'IAS'), 
          ('noun', 'princess')]) 
+0

не хотите, чтобы слово 'lower' перед тем, как вы проверите' if item in scan. '? – depperm

+0

Уменьшите сообщение до одного неудачного вопроса и включите сообщение об ошибке. Всегда предоставляйте ** минимальный ** неудачный пример, только усилия могут помочь вам найти вашу ошибку. http://stackoverflow.com/help/mcve – Anthon

+0

'if item not in (scan.dirs или scan.verbs или scan.stops или scan.nouns или scan.numbers):' не делает то, что вы хотите, чтобы он делал , –

ответ

1

У вас есть несколько опечаток в вашем коде и пару логики ошибки.

Вот исправленная версия вашего кода, измененная для работы без модуля nose (которого у меня нет).

class scan(object): 
    dirs = ['north','south','east','west','down','up','left','right','back'] 
    verbs = ['go','stop','kill','eat'] 
    stops = ['the','in','of','from','at','it'] 
    nouns = ['door','princess','bear','cabinet'] 
    numbers = ['0','1','2','3','4','5','6','7','8','9'] 

    def __init__(self, user_input): 
     self.user_input = user_input 

    def result(self): 
     words = self.user_input.split() 
     results = [] 

     for item in words: 
      if item in scan.dirs: 
       result = ('direction', item.lower()) 
       results.append(result) 
      elif item in scan.verbs: 
       result = ('verb', item.lower()) 
       results.append(result) 
      elif item in scan.stops: 
       result = ('stop', item.lower()) 
       results.append(result) 
      elif item in scan.nouns: 
       result =('noun', item.lower()) 
       results.append(result) 
      elif all(c in scan.numbers for c in item): 
       result = ('number', int(item)) 
       results.append(result) 
      else: 
       result = ('error', item) 
       results.append(result) 

     return results 

def assert_equal(u, v): 
    print(u, v, u == v) 

def test_direction(): 
    assert_equal(scan('north').result(), [('direction', 'north')]) 
    result = scan("north east south").result() 
    assert_equal(result, [('direction', 'north'), 
          ('direction', 'east'), 
          ('direction', 'south')]) 

def test_verbs(): 
    assert_equal(scan("go").result(), [('verb', 'go')]) 
    result = scan("go kill eat").result() 
    assert_equal(result, [('verb', 'go'), 
          ('verb', 'kill'), 
          ('verb', 'eat')]) 


def test_stops(): 
    assert_equal(scan("the").result(), [('stop', 'the')]) 
    result = scan("the in of").result() 
    assert_equal(result, [('stop', 'the'), 
          ('stop', 'in'), 
          ('stop', 'of')]) 


def test_noun(): 
    assert_equal(scan("bear").result(), [('noun', 'bear')]) 
    result = scan("bear princess").result() 
    assert_equal(result, [('noun', 'bear'), 
          ('noun', 'princess')]) 

def test_numbers(): 
    assert_equal(scan("1234").result(), [('number', 1234)]) 
    result = scan("3 91234").result() 
    assert_equal(result, [('number', 3), 
          ('number', 91234)]) 

def test_errors(): 
    assert_equal(scan("ASDFADFASDF").result(), [('error', 'ASDFADFASDF')]) 
    result = scan("bear IAS princess").result() 
    assert_equal(result, [('noun', 'bear'), 
          ('error', 'IAS'), 
          ('noun', 'princess')]) 

tests = (
    test_direction, 
    test_verbs, 
    test_stops, 
    test_noun, 
    test_numbers, 
    test_errors, 
) 

for test in tests: 
    print('\n' + test.__name__) 
    test() 

выход

test_direction 
[('direction', 'north')] [('direction', 'north')] True 
[('direction', 'north'), ('direction', 'east'), ('direction', 'south')] [('direction', 'north'), ('direction', 'east'), ('direction', 'south')] True 

test_verbs 
[('verb', 'go')] [('verb', 'go')] True 
[('verb', 'go'), ('verb', 'kill'), ('verb', 'eat')] [('verb', 'go'), ('verb', 'kill'), ('verb', 'eat')] True 

test_stops 
[('stop', 'the')] [('stop', 'the')] True 
[('stop', 'the'), ('stop', 'in'), ('stop', 'of')] [('stop', 'the'), ('stop', 'in'), ('stop', 'of')] True 

test_noun 
[('noun', 'bear')] [('noun', 'bear')] True 
[('noun', 'bear'), ('noun', 'princess')] [('noun', 'bear'), ('noun', 'princess')] True 

test_numbers 
[('number', 1234)] [('number', 1234)] True 
[('number', 3), ('number', 91234)] [('number', 3), ('number', 91234)] True 

test_errors 
[('error', 'ASDFADFASDF')] [('error', 'ASDFADFASDF')] True 
[('noun', 'bear'), ('error', 'IAS'), ('noun', 'princess')] [('noun', 'bear'), ('error', 'IAS'), ('noun', 'princess')] True 

Первая логическая ошибка была замечена я

if item not in (scan.dirs or scan.verbs or scan.stops 
    or scan.nouns or scan.numbers): 

Это не тест, если item не в какой-либо из тех, списки. Вместо этого он сначала вычисляет

scan.dirs or scan.verbs or scan.stops or scan.nouns or scan.numbers 

используя стандартные правила для or оператора Python. scan.dirs является непустым списком, поэтому результатом этого выражения является scan.dirs.

Так что if утверждение эквивалентно

if item not in scan.dirs: 

, который явно не то, что вы собираетесь делать.

Для получения дополнительной информации о том, как or и and работают на Python, см. this answer Я написал в начале этого года.

Мы могли реализовать этот тест с использованием

if not any(item in seq for seq in (scan.dirs, scan.verbs, scan.stops, 
    scan.nouns, scan.numbers)): 

, но нам не нужно, чтобы сделать это. Вместо этого мы меняем большинство из этих if s на elif s, а затем все, что не получается успешно отсканировано, должно быть ошибкой, поэтому мы можем обрабатывать это в блоке else.

Вторая ошибка большой логики - это ваш номерный тест.Вы пытаетесь увидеть, если номер строки мульти-значный является допустимым (положительное) целое с

if item in scan.numbers: 

но тест будет успешным, только если item это одна цифра.

Вместо этого мы должны проверить, что _all_digits из числа являются, по сути, цифр, и вот что

all(c in scan.numbers for c in item) 

делает.

Однако есть лучший способ: мы просто используем метод .isdigit в str типа в:

if item.isdigit(): 

я не использовал, что в моем коде, потому что я хотел использовать списки сканирования. Кроме того, .isdigit не может обрабатывать отрицательные числа или десятичные точки, но вы можете легко добавить '-' и '.' в scan.numbers.

+0

Спасибо, что это определенно сработало. Я не понимал, сколько опечаток, которые я сделал в этом тестовом сценарии. –

+0

Я действительно никогда не знал о ключе «все», я предпочитаю метод isdigit(), поскольку scan.numbers должен находиться только в пределах 0-9. –

+0

@Jephthah 'all' и его« сестра »функция' any' являются _very_ полезными для общего тестирования нескольких элементов. Но когда есть встроенные специальные тесты, которые делают то, что вы хотите, например 'isdigit', вы, безусловно, должны их использовать. –