2013-02-13 3 views
1

У меня есть 2 функции, apply_rule и match. Каждый из них определяется независимо - они не принадлежат ни к одному классу.Испытание загрязнения в unittest

match принимает два обязательных параметра и необязательный параметр, называемый pairs. По умолчанию используется пустой словарь. Ниже приведен код для apply_rule и для match. Обратите внимание, что вызывается match, а необязательный параметр pairs не указан.

def apply_rule(pat, rule): 
    if not isrule(rule): 
    return "Not a valid rule" 

    subs = match(lhs(rule), pat) 
    if subs == {}: 
    return pat 
    else: 
    return substitute(rhs(rule), subs) 


def match(pat, lst, pairs={}): 
    if pat == [] and lst == []: 
    return pairs 
    elif isvariable(pat[0]): 
    if pat[0] not in pairs.keys(): 
     pairs[pat[0]] = lst[0] 
    elif pat[0] in pairs.keys() and lst[0] != pairs[pat[0]]: 
     return False 
    elif pat[0] != lst[0]: 
    return False 
    return match(pat[1:], lst[1:], pairs) 

Прямо сейчас, UnitTest для match терпит неудачу, потому что он "вспоминает" pairs, определенной в тесте на apply_rule.

Однако, если я изменю 3-ю строку в apply_rule на subs = match(lhs(rule), pat, {}), тогда тесты пройдут. Знаете ли вы, почему? Насколько я могу судить, не должно быть никакого способа, чтобы match запоминал значение pairs с того момента, когда оно было вызвано в других тестах.

Ниже приведены единичные испытания для справки.

def test_match(self): 
    self.assertEqual({}, match(['a', 'b', 'c'], ['a', 'b', 'c'])) 

    self.assertEqual(self.dict_with_x, match(['a', '_X', 'c'], ['a', '5', 'c'])) 
    self.assertEqual(self.dict_with_x, match(self.pat_with_xx, self.list_with_55)) 

    self.assertEqual(self.dict_with_xy, match(self.pat_with_xy, self.list_with_5hi)) 

    self.assertFalse(match(self.pat_with_xx, ['a', 'b', 'c', 'd'])) 
    self.assertFalse(match(['a', 'b', 'c'], ['a', 'b', 'd'])) 

def test_apply_and_firerule(self): 
    pattern1 = "my mother thinks I am fat".split(' ') 
    expected = "do you think you are fat ?".split(' ') 
    self.assertEqual(apply_rule(pattern1, self.r1), expected) 

И сообщение об ошибке ...

Traceback (most recent call last): 
    File "pattern_matcher_tests.py", line 65, in test_match 
    self.assertEqual({}, match(['a', 'b', 'c'], ['a', 'b', 'c'])) 
AssertionError: {} != {'_Y': 'fat', '_X': 'mother'} 
- {} 
+ {'_X': 'mother', '_Y': 'fat'} 
+1

http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument http://effbot.org/zone/default -values.htm – dm03514

ответ

1

из effbot

Почему это происходит? #

Значения параметров по умолчанию всегда оцениваются тогда и только тогда, когда выполняется оператор «def», к которому они принадлежат; см:

http://docs.python.org/ref/function.html

для соответствующего раздела в Справочнике по языку.

Что делать вместо этого? #

Обходное решение, как указывалось другими, использовать значение-заполнитель вместо изменения значения по умолчанию. Никто не является общим значением:

+0

Удивительно, я даже не считал, что это была вещь на Python, а не какая-то неувядающая вещь. – bobbypins

+0

'None' - моя ценность. –

Смежные вопросы