Возможно ли иметь функцию в Python, где fun(1+1) поступает в функцию как '1+1', а не как 2?
Здравый смысл подсказывает, что это невозможно, потому что нет способа предотвратить вычисление 1+1 до того, как оно будет передано в функцию.
Но тот же здравый смысл подсказывает, что следующий PHP-код не должен работать, потому что unset($arr[0]) должен быть таким же, как unset(99). Но это работает, и последнее является синтаксической ошибкой.
$arr = [99, 1, 2, 3, 99];
unset($arr[0]); # remove the first element
$arr = array_values($arr); # reindex from 0
echo $arr == [1, 2, 3, 99]; # yes
Так что, возможно, в Python тоже есть лазейка для подобных странностей.
Я хотел бы использовать это для написания более коротких тестов. На данный момент у меня есть:
with pytest.raises(ZeroDivisionError):
1/0
with pytest.raises(ZeroDivisionError):
0/0
with pytest.raises(ZeroDivisionError):
0**-1
with pytest.raises(FooError):
Foo(round_hole=SquarePeg)
with pytest.raises(FooError):
Foo(give_me_five=6)
Вместо этого я бы предпочел написать:
shorter(ZeroDivisionError, [1/0, 0/0, 0**-1])
shorter(FooError, [
Foo(round_hole=SquarePeg),
Foo(give_me_five=6)
])
Я, конечно, мог бы передавать строки, но недостаток утраченной подсветки синтаксиса свел бы на нет преимущество краткости.
Редактировать 1: Возможно, не такая уж плохая идея «открыть» тестовый файл из тестового режима в режим записи, сделав замену строк, например
', # expr\n ' на '", # expr\n "'.
# write mode
shorter(FooError, [ # except
Foo(round_hole=SquarePeg), # expr
Foo(give_me_five=6) # expr
])
# test mode
shorter(FooError, [ # except
"Foo(round_hole=SquarePeg)", # expr
"Foo(give_me_five=6)" # expr
])
Редактировать 2: На самом деле лямбда-подход, предложенный Хофлингом, работает нормально. Обычно отсутствие аргументов вызывает ошибку прямо в тестовом файле. Чтобы избежать этого, используйте __init__(self, arg=None) вместо просто __init__(self, arg).
Определение более коротких и примеров классов:
import pytest
from inspect import isclass
def shorter(expected, values):
if isclass(expected) and issubclass(expected, Exception):
for value in values:
with pytest.raises(expected):
value()
else:
for value in values:
assert value == expected
class Hand():
def __init__(self, give_me_five=None):
if give_me_five is None:
raise NoArgError
if give_me_five != 5:
raise NotFiveError
self.twice_five = 2 * give_me_five
class NoArgError(ValueError):
"""You need to provide and argument."""
class NotFiveError(ValueError):
"""The argument must be 5."""
Пример тестового файла:
from .other_file import shorter, Hand, NoArgError, NotFiveError
def test_errors():
check(NoArgError, [
lambda: Hand()
])
check(NotFiveError, [
lambda: Hand(0),
lambda: Hand(6),
lambda: Hand(''),
lambda: Hand('5')
])
def test_values():
check(10, [
Hand(5).twice_five
])
Подробнее здесь: https://stackoverflow.com/questions/613 ... o-a-string