Есть ли необходимость в "строгом использовании" компилятора Python?
Существуют инструменты статического анализа для Python, но проверки во время компиляции, как правило, диаметрально противоположны философии связывания во время выполнения, которую придерживается Python. Можно обернуть стандартный интерпретатор Python инструментом статического анализа, чтобы применить некоторые ограничения типа " использовать строгие", но мы не видим широкого распространения такой вещи.
Есть ли что-то в Python, что делает "строгое" поведение ненужным или особенно нежелательным?
В качестве альтернативы, является ли "использование строгого" поведения ненужным в Perl, несмотря на его широкое распространение?
Примечание: под "необходимым" я подразумеваю "практически необходимый", а не строго необходимый. Очевидно, что вы можете писать на Perl без "строгого использования", но (из того, что я видел) большинство программистов на Perl его используют.
Примечание: Оболочка интерпретатора Python не требует ограничений типа "использовать строгие" - вы можете использовать псевдопрагму, аналогичную "использовать строгий", которая будет игнорироваться обычным интерпретатором. Я не говорю о добавлении функции уровня языка.
Обновление: Объяснение того, что "использует строгий" делает в Perl для комментариев. (Ссылка на официальные документы есть в первом абзаце.)
Директива "use strict" имеет три отдельных компонента, только два из которых действительно интересны:
использовать строгие переменные: Статически проверяет использование лексически ограниченных переменных в вашей программе. (Имейте в виду, что в Python есть в основном только
global
сфера иlocal
объем). Многие линтеры Python проверяют подобные вещи. Поскольку это единственный статический анализ, который они могут выполнить, линтеры предполагают, что вы используете прямую лексическую область видимости, и предупреждают вас о вещах, которые кажутся неправильными в этом смысле, пока вы не скажете им замолчать; т.е.FOO = 12 foo += 3
Если вы ничего не делаете со своими пространствами имен, это может быть полезно для проверки на опечатки.
использовать строгие ссылки: предотвращает разыменование символьного пространства имен. Ближайший аналог Python использует
locals()
а такжеglobals()
сделать символьную привязку и поиск идентификатора.использовать строгие сабвуферы: нет реального аналога в Python.
12 ответов
"философия связывания во время выполнения, которую использует Python... делает" использование строгого "поведения ненужным [и] особенно нежелательным"
Довольно хорошее резюме. Благодарю.
Это по сути это. Инструменты статического анализа не помогают Python в достаточной степени оправдывать себя.
редактировать
"Я прошу нас проанализировать, почему нам это не нужно, и, соответственно, почему программисты Perl думают, что им это нужно".
Причина, почему это именно та причина, которую вы уже дали. Нам это не нужно, потому что это не помогает. Понятно, что вам не нравится этот ответ, но больше сказать нечего. Проверка времени компиляции или предварительной компиляции просто не помогает.
Однако, поскольку вы нашли время, чтобы задать вопрос снова, я предоставлю больше доказательств того ответа, который вы уже дали.
Я пишу на Java почти так же, как пишу на Python. Статическая проверка типов в Java не предотвращает никаких логических проблем; это не способствует выполнению требований к производительности; это не помогает удовлетворить случаи использования. Это даже не уменьшает объем модульного тестирования.
В то время как статическая проверка типов обнаруживает случайное неправильное использование метода, вы обнаруживаете это так же быстро в Python. В Python вы найдете его во время модульного тестирования, потому что он не будет работать. Примечание: я не говорю, что неправильные типы обнаруживаются с помощью множества хитрых модульных тестов, я говорю, что большинство проблем с неправильными типами обнаруживаются в необработанных исключениях, когда вещь просто не может пройти достаточно далеко, чтобы проверить утверждения.
Причина, по которой Pythonistas не тратит время на статическую проверку, проста. Нам это не нужно. Это не предлагает никакой ценности. Это уровень анализа, который не имеет экономической выгоды. Это больше не дает мне возможности решать реальные проблемы, которые возникают у реальных людей с их реальными данными.
Посмотрите на наиболее популярные вопросы SO Python, связанные с языком (не проблемным доменом или библиотекой).
Есть ли разница между "foo is None" и "foo == None"? - ==
против is
, Никакая статическая проверка не может помочь с этим. Также см. Есть ли разница между `==` и `is` в Python?
Что ** (двойная звезда) и * (звезда) делают для параметров? - *x
дает список, **x
дает словарь. Если вы этого не знаете, ваша программа немедленно умирает, когда вы пытаетесь сделать что-то неподходящее для этих типов."Что если ваша программа никогда не делает ничего" неуместного "". Тогда ваша программа работает. 'достаточно.
Как я могу представить Enum в Python? - это призыв к какому-то типу ограниченного домена. Класс со значениями на уровне класса в значительной степени выполняет эту работу."Что если кто-то изменит назначение". Легко построить. Override __set__
поднять исключение. Да, статическая проверка может обнаружить это. Нет, на практике не бывает, чтобы кто-то запутался в константе enum и переменной; и когда они делают, это легко определить во время выполнения."Что если логика никогда не будет выполнена". Ну, это плохой дизайн и плохое юнит-тестирование. Выдача ошибки компилятора и неверная логика, которая никогда не тестировалась, ничем не лучше, чем то, что происходит в динамическом языке, когда он никогда не тестируется.
Выражения генератора и понимание списка - статическая проверка не помогает решить этот вопрос.
Почему 1 +++ 2 = 3? - статическая проверка не заметит это. 1+++2 в C совершенно законно, несмотря на все проверки компилятора. Это не то же самое в Python, как в C, но так же законно. И так же запутанно.
Изменения в списках отражены в списках неожиданно - это полностью концептуально. Статическая проверка также не может помочь решить эту проблему. Эквивалент Java также будет компилироваться и вести себя плохо.
Ну, я не большой программист на Python, но я бы сказал, что ответ "ДА".
Любой динамический язык, который позволяет вам создавать переменную с любым именем в любое время, может использовать "строгую" прагму.
Строгие переменные (один из параметров для строгого в Perl, "использовать строгий" включает их все сразу) в Perl требует, чтобы все переменные были объявлены до их использования. Что означает, что этот код:
my $strict_is_good = 'foo';
$strict_iS_good .= 'COMPILE TIME FATAL ERROR';
Генерирует фатальную ошибку во время компиляции.
Я не знаю, как заставить Python отклонить этот код во время компиляции:
strict_is_good = 'foo';
strict_iS_good += 'RUN TIME FATAL ERROR';
Вы получите исключение во время выполнения, что strict_iS_good
не определено Но только когда код выполняется. Если ваш тестовый комплект не имеет 100% покрытия, вы можете легко отправить эту ошибку.
Каждый раз, когда я работаю на языке, который не имеет такого поведения (например, PHP), я нервничаю. Я не идеальная машинистка. Простая, но трудно опознаваемая опечатка может привести к сбою в работе вашего кода способами, которые трудно отследить.
Итак, для повторения, YES Python может использовать "строгую" прагму для включения проверок времени компиляции для вещей, которые можно проверять во время компиляции. Я не могу думать о каких-либо других проверках, чтобы добавить, но лучший программист Python, вероятно, мог бы подумать о некоторых.
Заметьте, я сосредотачиваюсь на прагматическом эффекте от stict vars в Perl, и примыкаю к некоторым деталям. Если вы действительно хотите узнать все подробности, смотрите perldoc для строгого.
Обновление: ответы на некоторые комментарии
Джейсон Бейкер: Статические шашки, такие как Пилинт, полезны. Но они представляют собой дополнительный шаг, который можно и часто пропускают. Встраивание некоторых базовых проверок в компилятор гарантирует, что эти проверки выполняются последовательно. Если эти проверки контролируются прагмой, даже возражение, касающееся стоимости проверок, становится спорным.
popcnt: я знаю, что python будет генерировать исключение во время выполнения. Я так и сказал. Я рекомендую проверять время компиляции, где это возможно. Пожалуйста, перечитайте пост.
mpeters: Ни один компьютерный анализ кода не может найти все ошибки - это равносильно решению проблемы остановки. Хуже того, чтобы найти опечатки в назначениях, ваш компилятор должен знать ваши намерения и находить места, где ваши намерения отличаются от вашего кода. Это довольно явно невозможно.
Однако это не означает, что никакая проверка не должна быть сделана. Если есть классы проблем, которые легко обнаружить, то имеет смысл их перехватить.
Я не достаточно знаком с Pylint и Pychecker, чтобы сказать, какие классы ошибок они будут ловить. Как я уже сказал, я очень неопытен с python.
Эти программы статического анализа полезны. Тем не менее, я считаю, что если они не дублируют возможности компилятора, компилятор всегда будет в состоянии "знать" о программе больше, чем любая статическая проверка. Кажется расточительным не использовать это для уменьшения ошибок, где это возможно.
Обновление 2:
cdleary - теоретически, я согласен с вами, статический анализатор может выполнить любую проверку, которую может выполнить компилятор. А в случае с Python этого должно быть достаточно.
Однако, если ваш компилятор достаточно сложен (особенно если у вас много прагм, которые меняют способ компиляции, или если, как и в Perl, вы можете запускать код во время компиляции), то статический анализатор должен приблизиться к сложности компилятора / интерпретатора, чтобы сделать анализ.
Хех, все эти разговоры о сложных компиляторах и выполнении кода во время компиляции показывают мой опыт работы с Perl.
Насколько я понимаю, Python не имеет прагм и не может запускать произвольный код во время компиляции. Таким образом, если я не ошибаюсь или эти функции не добавлены, достаточно статического анализатора в статическом анализаторе. Конечно, было бы полезно форсировать эти проверки при каждом выполнении. Конечно, я бы сделал это с помощью прагмы.
Добавив прагмы к миксу, вы пошли по скользкому пути, и сложность вашего анализатора должна возрасти пропорционально мощности и гибкости, которые вы предоставляете в своих прагмах. Если вы не будете осторожны, вы можете закончить как Perl, и тогда "только Python может анализировать Python", будущее, которое я бы не хотел видеть.
Возможно, ключ командной строки был бы лучшим способом добавить принудительный статический анализ;)
(Ни в коем случае не намерены оспаривать возможности Python, когда я говорю, что он не может работать с поведением во время компиляции, как Perl. У меня есть догадка, что это тщательно продуманное проектное решение, и я вижу в этом мудрость. Perl Чрезвычайная гибкость во время компиляции - это, ИМХО, большая сила и ужасная слабость языка; я вижу мудрость и в этом подходе.)
В Python есть что-то, что может изменить синтаксис скрипта:
from __future__ import print_function
и различные другие функции будущего, которые имеют синтаксическое значение. Просто синтаксис Python был более строгим, стабильным и более четким, чем исторический Perl; Такие вещи, которые "строгие ссылки" и "строгие подписчики" запрещают, никогда не существовали в Python.
"строгие переменные" в первую очередь предназначены для того, чтобы не допустить опечаток и пропущенных "моих" от создания случайных глобальных переменных (ну, переменные пакета в терминах Perl). Это не может произойти в Python, поскольку пустые назначения по умолчанию соответствуют локальному объявлению, а открытые неназначенные символы приводят к исключению.
(Все еще существует случай, когда пользователи случайно пытаются выполнить сквозную запись в глобальную переменную, не объявляя ее "глобальным" оператором, вызывая либо случайную локальную, либо, чаще, UnboundLocalError. Это имеет тенденцию быть изученным довольно быстро, но это Это спорный случай, когда может потребоваться объявление ваших местных жителей. Хотя немногие опытные программисты на Python возьмут на себя бремя читабельности.)
Другие языковые и библиотечные изменения, которые не включают синтаксис, обрабатываются через систему предупреждений.
Я думаю, что есть некоторая путаница с тем, что делает "use strict", из комментариев, которые я вижу. Он не включает проверки типов времени компиляции (чтобы быть похожим на Java). В этом смысле программисты Perl согласны с программистами на Python. Как сказал С.Лотт выше, эти типы проверок не защищают от логических ошибок, не уменьшают количество модульных тестов, которые вам нужно написать, и мы также не большие поклонники программирования бондажа.
Вот список того, что делает "use strict":
Использование символических ссылок является ошибкой во время выполнения. Это мешает вам сойти с ума (но иногда полезные вещи, как)
$var = 'foo';
$foo = 'bar';
print $$var; # this would contain the contents of $foo unless run under strict
Использование необъявленных переменных является ошибкой во время выполнения (это означает, что вам нужно использовать "my", "our" или "local", чтобы объявить область действия вашей переменной перед ее использованием).
Все голые слова считаются синтаксическими ошибками во время компиляции. Голые слова - это слова, которые не были объявлены как символы или подпрограммы. В основном это запрещает то, что было сделано исторически, но считается ошибкой.
Этот оригинальный ответ является правильным, но, возможно, не объясняет ситуацию в практическом смысле.
Существуют инструменты статического анализа для Python, но проверки во время компиляции, как правило, диаметрально противоположны философии связывания во время выполнения, которую придерживается Python.
"Perly Use Use" предоставляет в Perl возможность гарантировать, что неправильно написанное или имя переменной (обычно) перехватывается во время компиляции. Это повышает надежность кода и ускоряет разработку. Но чтобы сделать такую вещь стоящей, вам нужно объявить переменные. И стиль Python, кажется, препятствует этому.
Таким образом, в Python вы никогда не узнаете о неправильно написанной переменной, пока не заметите во время выполнения, что задание, которое, по вашему мнению, вы сделали, не выполняется, или что выражение, по-видимому, принимает неожиданное значение. На обнаружение таких ошибок может уйти много времени, особенно когда программы становятся большими и люди вынуждены поддерживать код, разработанный другими.
Java и C/C++ делают еще один шаг, проверяя тип. Мотивация практическая, а не философская. Как вы можете поймать как можно больше ошибок как можно скорее, и быть уверенным, что все ошибки устранены перед выпуском кода в производство? Кажется, что каждый язык использует определенную стратегию и работает с ней, основываясь на том, что они считают важным. В языке, подобном Perl, где привязка во время выполнения не поддерживается, имеет смысл воспользоваться преимуществом "строгого использования", чтобы упростить разработку.
У Python нет настоящей лексической области видимости, поэтому строгие переменные не будут очень разумными. Он не имеет символических ссылок AFAIK, поэтому он не нуждается в строгих ссылках. У него нет голых слов, поэтому ему не нужны строгие переменные.
Честно говоря, я скучаю только по лексическому контексту. Два других я бы посчитал бородавками в Perl.
Я считаю 'use strict'
в Perl больше похоже на прагму, как вы намекали: она меняет поведение компилятора.
Философия языка Perl отличается от философии Python. Например, вам дано более чем достаточно веревки, чтобы повеситься в Perl.
Ларри Уолл хорошо разбирается в лингвистике, поэтому мы получили от Perl то, что называется TIMTOWTDI (скажем, tim-toe-dee
) принцип против дзен питона:
Должен быть один - и желательно только один - очевидный способ сделать это.
Вы можете очень легко использовать Pylint и PyChecker, чтобы придумать свой собственный вкус use strict
для питона (или что-то аналогичное perl -cw *scriptname*
) но из-за различных философий в дизайне языка, вы не встретите это на практике широко.
Основываясь на вашем комментарии к первому постеру, вы знакомы с питоном import this
, Там есть много вещей, которые освещают, почему вы не видите эквивалент use strict
в Python. Если вы медитируете на коане, найденном в Дзэн Питона, вы можете найти просветление для себя.:)
Очень трудно писать большие программы без "строгого использования" на Perl. Если вы не используете "строгий", если вы снова используете переменную и неправильно пишете ее, пропуская букву, программа все равно запускается. И без тестовых случаев, чтобы проверить ваши результаты, вы никогда не найдете таких ошибок. Это может занять очень много времени, чтобы выяснить, почему вы получаете неправильные результаты по этой причине.
Некоторые из моих Perl-программ состоят из 5000 строк на 10 000 строк кода, разбитых на десятки модулей. Никто не может по-настоящему заниматься производственным программированием без "строгого использования". Я бы никогда не допустил, чтобы производственный код устанавливался на фабрике с языками, не поддерживающими "объявления переменных".
Вот почему в Perl 5.12.x теперь используется "строгий режим" в качестве поведения по умолчанию. Вы можете отключить их.
PHP доставил мне немало проблем из-за отсутствия принудительного объявления переменных. Поэтому вам нужно ограничиться небольшими программами с этим языком.
Просто мнение...
abcParsing
Я обнаружил, что мне действительно важно обнаруживать ссылки на необъявленные переменные. Eclipse имеет интеграцию с Pylint через PyDev и, хотя Pylint далек от совершенства, он делает разумную работу в этом.
Это идет вразрез с динамической природой Python, и мне иногда приходится добавлять #IGNORE, когда мой код что-то умный. Но я нахожу, что это случается достаточно редко, и я этим доволен.
Но я мог видеть, как полезность некоторой подобной пилинту функциональности стала доступной в форме флага командной строки. Вроде как переключатель -3 в Python 2.6, который определяет точки несовместимости между кодами Python 2.x и 3.x.
Perl - это язык без ограничений, как они сказали:) . Таким образом, вы можете использовать переменную до объявления; Например: если вы используете имя переменной "is_array", но вводите "is_arrby", компилятор не сообщит об ошибке без "use strict" . Поэтому, когда кодируете длинную программу на Perl, лучше использовать выражение "использовать строгий". Конечно, менее 50 строк для запуска одноразового скрипта, в этом нет необходимости:)
Кажется, что идеал "Pythonic" кода служит для той же цели, что и use strict
,
У меня нет опыта работы с Perl, но насколько я знаю, в python нет функции, которую нужно отключить, чтобы ваш код был "более надежным", поэтому в этом смысле, я думаю, вы можете сказать, что это не нужно