Пообщайтесь с разработчиками Python достаточно долго, и вы узнаете все о Zen Of Python Тима Питера.
Zen , который вы можете легко прочитать , выполнив import this
в Python REPL, представляет 19 из 20 руководящих принципов, лежащих в основе дизайна Python. Недавно я стал ценить один афоризм больше, чем другие: «Явное лучше, чем неявное».
Самая распространенная интерпретация, которую я видел — настолько распространенная, что в настоящее время она присутствует в избранном фрагменте кода Google при поиске фразы — заключается в том, что подробный код лучше, чем краткий код, потому что многословие, по-видимому, является ключом к удобочитаемости… или что-то в этом роде.
Конечно, использование более подходящих имен переменных и замена магических чисел именованными константами (или, в случае Python, «константами») — это здорово. Но когда вы в последний раз выискивали неявные входные данные в своем коде и делали их явными?
Как распознать неявные входы и выходы
Сколько входов и выходов имеет следующая функция?
def find_big_numbers(): with open("numbers.txt", "r") as f: for line in f: if line.strip().isnumeric(): number = float(line) if number > 100: print(number)
find_big_numbers()
не имеет параметров и всегда возвращает None
. Если бы вы не могли видеть тело функции и не могли получить доступ к стандартному потоку вывода , вы бы вообще поверили, что эта функция что-то делает?
И все же, find_big_numbers()
имеет два входа и еще один выход, кроме None
:
-
numbers.txt
— это неявный ввод . Без него функция работать не будет, но без чтения тела функции узнать, что файл нужен, невозможно. - Магическое число
100
в строке 6 является неявным вводом . Вы не можете определить «большое число» без него, но нет способа узнать этот порог, не читая тело функции. - Значения могут выводиться или не выводиться на
stdout
, в зависимости от содержимогоnumbers.txt
. Это неявный вывод , поскольку функция не возвращает эти значения.
Неявные результаты часто называют побочными эффектами .
Попробуй сам
Определите все входные и выходные данные функции is_adult
в этом фрагменте кода:
from datetime import date birthdays = { "miles": date(2000, 1, 14), "antoine": date(1987, 3, 25), "julia": date(2009, 11, 2), } children = set() adults = set() def is_adult(name): birthdate = birthdays.get(name) if birthdate: today = date.today() days_old = (today - birthdate).days years_old = days_old // 365 if years_old >= 18: print(f"{name} is an adult") adults.add(name) return True else: print(f"{name} is not an adult") children.add(name) return False
Почему следует избегать неявного ввода и вывода
Одной из веских причин является их склонность нарушать принцип наименьшего удивления .
Конечно, не все неявные входы и выходы плохи. Такой метод, как .write()
, который файловые объекты Python используют для записи данных в файл, имеет неявный вывод: файл. Нет никакого способа устранить это. Но это не удивительно. Запись в файл – это все.
С другой стороны, такая функция, как is_adult()
из предыдущего фрагмента кода, делает много удивительных вещей. Менее экстремальных примеров предостаточно.
Избегание неявного ввода и вывода также улучшает тестируемость и возможность повторного использования вашего кода. Чтобы увидеть, как это сделать, давайте рефакторим функцию find_big_numbers()
из предыдущей.
Как удалить неявный ввод и вывод
Вот снова find_big_numbers()
, поэтому вам не нужно прокручивать вверх:
def find_big_numbers(): with open("numbers.txt", "r") as f: for line in f: if line.strip().isnumeric(): number = float(line) if number > 100: print(number)
Ранее мы идентифицировали два неявных ввода, файл numbers.txt
и число 100
, и один неявный вывод, значения, напечатанные в stdout
. Давайте сначала поработаем над входными данными.
Вы можете переместить имя файла и пороговое значение в параметры функции:
def find_big_numbers(path, threshold=100): with open(path, "r") as f: for line in f: if line.strip().isnumeric(): number = float(line) if number > threshold: print(number)
Это уже значительно улучшило тестируемость и возможность повторного использования. Если вы хотите попробовать это на другом файле, передайте путь в качестве аргумента. (В качестве бонуса файл теперь может находиться где угодно на вашем компьютере.) При необходимости вы также можете изменить порог для «больших чисел».
Но результат трудно проверить.
Если вы хотите знать, что функция выдала правильные значения, вам нужно перехватить stdout
. Это возможно. Но почему бы просто не вернуть список всех значений:
def find_big_numbers(path, threshold=100): big_numbers = [] with open(path, "r") as f: for line in f: if line.strip().isnumeric(): number = float(line) if number > threshold: big_numbers.append(number) return big_numbers
Теперь find_big_numbers()
имеет явный оператор return
, который возвращает список больших чисел, найденных в файле.
find_big_numbers()
. Как бы вы его почистили? Вы можете проверить find_big_numbers()
, вызвав его с путем к файлу, содержимое которого известно, и сравнив возвращаемый список со списком правильных значений:
# test_nums.txt looks like: # 29 # 375 # 84 >>> expected_nums = [375.0] >>> actual_nums = find_big_numbers("test_nums.txt") >>> assert(actual_nums == expected_nums)
find_big_numbers()
теперь также более удобна для повторного использования. Вы не ограничены выводом чисел на stdout
. Вы можете отправить эти большие числа, куда хотите.
Неявные входные данные — это данные, используемые функцией или программой, которые не передаются явно в качестве аргументов. Вы можете исключить неявные входные данные, преобразовав их в параметры.
Неявные выходные данные — это данные, отправленные куда-то за пределы функции или программы, которые не возвращаются явно. Вы можете удалить явные выходные данные, заменив их подходящими возвращаемыми значениями.
Нельзя избежать всех неявных операций ввода и вывода, таких как функции, целью которых является чтение или запись данных из файлов и баз данных или отправка электронной почты. Тем не менее, устранение как можно большего количества неявных входных и выходных данных улучшает тестируемость и возможность повторного использования вашего кода.
find_big_numbers()
?Любопытно, что случилось с 20-й строкой в Zen of Python? В интернете гуляют всевозможные теории. Это кажется мне достаточно вероятным.
Узнайте больше о неявных вводах и выводах в превосходной книге Эрика Норманда Grokking Simplicity. Получите мгновенный доступ от Manning * или закажите его на Amazon *.
* Партнерская ссылка. Дополнительную информацию см. в раскрытии информации об аффилированных лицах .
Хотите больше подобного?
Одно электронное письмо каждую субботу с одним действенным советом.
Всегда меньше 5 минут вашего времени.
Подпишитесь сейчас