Есть ли необходимость в "строгом использовании" компилятора Python? - PullRequest
30 голосов
/ 05 марта 2009

Существуют инструменты статического анализа для Python , но проверки во время компиляции, как правило, диаметрально противоположны философии связывания во время выполнения , которую придерживается Python. возможно обернуть стандартный интерпретатор Python инструментом статического анализа, чтобы обеспечить соблюдение некоторых " строгих " подобных ограничений, но мы не видим широкого распространения такой вещи.

Есть ли в Python что-то, что делает "строгое" поведение ненужным или особенно нежелательным?

В качестве альтернативы, является ли поведение «строгое использование» ненужным в Perl, несмотря на его широкое распространение?

Примечание. Под «необходимым» я подразумеваю «практически необходимый», а не строго необходимый. Очевидно, что вы можете написать Perl без "строгого использования", но (из того, что я видел) большинство программистов на Perl делают , используют его.

Примечание: Оболочка интерпретатора Python не должна требовать «использовать строгие» подобные ограничения - вы можете использовать псевдопрагму, аналогичную «используйте строгий», которая будет игнорироваться обычным интерпретатором. Я не говорю о добавлении функции уровня языка.

<ч />

Обновление: Объяснение того, что «использует строгий» делает в Perl для комментариев. (Ссылка на официальные документы приведена в первом абзаце.)

В директиве «использовать строгое» есть три отдельных компонента, только два из которых действительно интересны:

  • использовать строгие переменные: Статически проверяет использование переменной лексической области в вашей программе. (Имейте в виду, что в Python есть только global scope и local scope). Многие линтеры Python проверяют подобные вещи. Поскольку это единственный статический анализ, который они могут выполнить, линтеры предполагают, что вы используете прямую лексическую область видимости, и предупреждают вас о вещах, которые кажутся неправильными в этом смысле, пока вы не скажете им замолчать; т.е. * * тысяча тридцать три

    FOO = 12
    foo += 3
    

    Если вы ничего не делаете со своими пространствами имен, это может быть полезно для проверки на опечатки.

  • использовать строгие ссылки: предотвращает разыменование символьного пространства имен. Ближайший аналог Python использует locals() и globals() для символьной привязки и поиска идентификатора.

  • использовать строгие подпрограммы: в Python нет реального аналога.

Ответы [ 12 ]

35 голосов
/ 05 марта 2009

Ну, я не большой программист на 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), я нервничаю. Я не идеальная машинистка. Простая, но трудно опознаваемая опечатка может привести к сбою в работе вашего кода способами, которые трудно отследить.

Итак, повторюсь, ДА Python может использовать "строгую" прагму для включения проверок времени компиляции для вещей, которые можно проверять во время компиляции. Я не могу думать о каких-либо других проверках, которые можно добавить, но, вероятно, о некоторых из них мог бы подумать лучший программист Python.

Примечание Я сосредотачиваюсь на прагматическом эффекте от stict vars в Perl и примыкаю к ​​некоторым деталям. Если вы действительно хотите узнать все подробности, см. в perldoc для строгого .

Обновление: ответы на некоторые комментарии

Джейсон Бейкер : Статические шашки, такие как Пилинт, полезны. Но они представляют собой дополнительный шаг, который можно и часто пропускают. Встраивание некоторых базовых проверок в компилятор гарантирует, что эти проверки выполняются последовательно. Если эти проверки контролируются прагмой, даже возражение, касающееся стоимости проверок, становится спорным.

popcnt : я знаю, что python сгенерирует исключение во время выполнения. Я так и сказал. Я рекомендую проверять время компиляции, где это возможно. Пожалуйста, перечитайте пост.

mpeters : Ни один компьютерный анализ кода не может найти все ошибки - это равносильно решению проблемы остановки. Хуже того, чтобы находить опечатки в назначениях, вашему компилятору необходимо знать ваши намерения и находить места, где ваши намерения отличаются от вашего кода. Это совершенно очевидно невозможно.

Однако это не означает, что никакая проверка не должна выполняться. Если есть классы проблем, которые легко обнаружить, то имеет смысл их ловить.

Я недостаточно знаком с pylint и pychecker, чтобы сказать, какие классы ошибок они будут обнаруживать. Как я уже сказал, я очень неопытен с python.

Эти программы статического анализа полезны. Тем не менее, я считаю, что если они не дублируют возможности компилятора, компилятор всегда будет в состоянии «знать» о программе больше, чем любая статическая проверка. Кажется расточительным не использовать это для уменьшения ошибок, где это возможно.

Обновление 2:

cdleary - Теоретически, я согласен с вами, статический анализатор может выполнить любую проверку, которую может выполнить компилятор. А в случае с Python этого должно быть достаточно.

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

Хех, все эти разговоры о сложных компиляторах и выполнении кода во время компиляции показывают мой фон Perl.

Насколько я понимаю, Python не имеет прагм и не может запускать произвольный код во время компиляции. Таким образом, если я не ошибаюсь или эти функции не добавлены, достаточно статического анализатора в статическом анализаторе. Конечно, было бы полезно форсировать эти проверки при каждом выполнении. Конечно, я бы сделал это с помощью прагмы.

После того, как вы добавили прагмы к миксу, вы пошли по скользкому пути, и сложность вашего анализатора должна возрасти пропорционально мощности и гибкости, которые вы предоставляете в своих прагмах. Если вы не будете осторожны, вы можете закончить как Perl, и тогда «только Python может анализировать Python», будущее, которое я бы не хотел видеть.

Возможно, ключ командной строки был бы лучшим способом добавить принудительный статический анализ;)

(Ни в коем случае не собираюсь ставить под сомнение возможности Python, когда я говорю, что он не может работать с поведением во время компиляции, как это может делать Perl. У меня есть догадка, что это тщательно продуманное проектное решение, и я вижу мудрость это. Предельная гибкость Perl во время компиляции, IMHO, большая сила и ужасная слабость языка; я вижу мудрость и в этом подходе.)

12 голосов
/ 05 марта 2009

"философия связывания во время выполнения, которую использует Python ... делает" использование строгого "поведения ненужным [и] особенно нежелательным"

Довольно хорошее резюме. Спасибо.

Это по сути дела. Инструменты статического анализа недостаточно помогают Python


Редактировать

«Я прошу нас разобраться в , почему нам это не нужно и, соответственно, почему программисты на Perl думают, что им это нужно».

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

Однако, поскольку вы нашли время, чтобы задать вопрос снова, я предоставлю больше доказательств того ответа, который вы уже дали.

Я пишу на Java почти так же, как пишу на Python. Статическая проверка типов в Java не предотвращает никаких логических проблем; это не способствует выполнению требований к производительности; это не помогает удовлетворить случаи использования. Это даже не уменьшает объем модульного тестирования.

В то время как статическая проверка типов обнаруживает случайное неправильное использование метода, вы обнаруживаете это так же быстро в Python. В Python вы найдете его во время модульного тестирования, потому что он не будет работать. Примечание: я не говорю, что неправильные типы обнаруживаются с помощью множества хитрых модульных тестов, я говорю, что большинство проблем с неправильным типом обнаруживаются в необработанных исключениях, когда вещь просто не может пройти достаточно далеко, чтобы проверить утверждения.

Причина, по которой Pythonistas не тратит время на статическую проверку, проста. Нам это не нужно. Это не предлагает никакой ценности. Это уровень анализа, который не имеет экономической выгоды. Это больше не дает мне возможности решать реальные проблемы, которые возникают у реальных людей с их реальными данными.

Посмотрите на самые популярные вопросы SO Python, связанные с языком (не проблемным доменом или библиотекой).

Есть ли разница между "foo is None" и "foo == None"? - == против is. Никакая статическая проверка не может помочь с этим. Также см. Есть ли разница между `==` и `is` в Python?

Что ** (двойная звезда) и * (звезда) делают для параметров? - *x дает список, **x дает словарь. Если вы этого не знаете, ваша программа немедленно умирает, когда вы пытаетесь сделать что-то неподходящее для этих типов. «Что если ваша программа никогда не делает ничего« ​​неуместного »». Тогда ваша программа работает. 'ничего не сказал.

Как я могу представить 'Enum' в Python? - это призыв к некоторому типу ограниченного домена. Класс со значениями на уровне класса в значительной степени выполняет эту работу. «Что если кто-то изменит назначение». Легко построить. Переопределите __set__, чтобы вызвать исключение. Да, статическая проверка может обнаружить это. Нет, на практике не бывает, чтобы кто-то запутался в константе enum и переменной; и когда они делают, это легко определить во время выполнения. «Что если логика никогда не будет выполнена». Ну, это плохой дизайн и плохое юнит-тестирование. Выдача ошибки компилятора и неверная логика, которая никогда не тестировалась, ничем не лучше, чем то, что происходит в динамическом языке, когда он никогда не тестируется.

Выражения генератора и понимание списка - статическая проверка не помогает решить этот вопрос.

Почему 1 +++ 2 = 3? - статическая проверка не обнаружит этого. 1 +++ 2 в C совершенно законно, несмотря на все проверки компилятора. Это не то же самое в Python, как в C, но так же законно. И так же запутанно.

Список изменений списков, неожиданно отраженных в подсписках - Это полностью концептуально. Статическая проверка также не может помочь решить эту проблему. Эквивалент Java также будет компилироваться и вести себя плохо.

11 голосов
/ 05 марта 2009

В Python есть что-то, что может изменить синтаксис скрипта:

from __future__ import print_function

и различные другие будущие функции, имеющие синтаксическое значение. Просто синтаксис Python был более строгим, стабильным и более четким, чем исторический Perl; такого рода вещи, которые «строгие ссылки» и «строгие подписчики» запрещают в Python, никогда не существовали.

«строгие переменные» в первую очередь предназначены для того, чтобы не допускать опечаток и пропущенных «моих» от создания случайных глобальных переменных (ну, переменных пакета в терминах Perl). Это не может произойти в Python, поскольку пустые назначения по умолчанию соответствуют локальному объявлению, а открытые неназначенные символы приводят к исключению.

(Все еще существует случай, когда пользователи случайно пытаются выполнить сквозную запись в глобальную переменную, не объявляя ее оператором 'global', вызывая либо случайную локальную, либо, чаще, UnboundLocalError. Это имеет тенденцию быть изученным довольно быстро , но это спорный случай, когда необходимость объявить ваших местных жителей может помочь. Хотя немногие опытные программисты на Python возьмут на себя бремя читаемости.)

Другие изменения языка и библиотеки, которые не включают синтаксис, обрабатываются с помощью системы warning .

7 голосов
/ 05 марта 2009

Я думаю, что есть некоторая путаница с тем, что делает «использование строгого», из комментариев, которые я вижу. Он не включает проверки типов времени компиляции (чтобы быть похожим на Java). В этом смысле программисты Perl согласны с программистами на Python. Как говорит С.Лотт выше, эти типы проверок не защищают от логических ошибок, не уменьшают количество модульных тестов, которые вам нужно написать, и мы также не большие поклонники программирования бондажа.

Вот список того, что делает «use strict»:

  1. Использование символьных ссылок является ошибкой во время выполнения. Это мешает вам сходить с ума (но иногда полезные вещи вроде)

    $var = 'foo';

    $foo = 'bar';

    print $$var; # this would contain the contents of $foo unless run under strict

  2. Использование необъявленных переменных является ошибкой во время выполнения (это означает, что вам нужно использовать «my», «our» или «local», чтобы объявить область видимости вашей переменной перед ее использованием.

  3. Все голые слова считаются синтаксическими ошибками во время компиляции. Голые слова - это слова, которые не были объявлены как символы или подпрограммы. В основном это запрещает то, что было исторически сделано, но считается ошибкой.

5 голосов
/ 05 марта 2009

Python не имеет истинной лексической области видимости, поэтому строгие переменные не будут очень разумными Он не имеет символических ссылок AFAIK, поэтому он не нуждается в строгих ссылках. У него нет голых слов, поэтому ему не нужны строгие переменные.

Если честно, я скучаю только по лексической области видимости. Два других я бы посчитал бородавками в Perl.

4 голосов
/ 10 ноября 2010

Этот оригинальный ответ правильный, но, возможно, не объясняет ситуацию в практическом смысле.

Существуют инструменты статического анализа для Python, но проверки во время компиляции, как правило, диаметрально противоположны философии связывания во время выполнения, которую придерживается Python.

То, что «использует строгое» в Perl, - это способность гарантировать, что неправильно написано или имя переменной (обычно) перехватывается во время компиляции. Это улучшает код надежность и ускоряет разработку. Но для того, чтобы сделать такую ​​вещь стоящей, вам нужно объявить переменные. И стиль Python, кажется, препятствует этому.

Так что в Python вы никогда не узнаете о неправильно написанной переменной, пока не заметите в во время выполнения, что задание, которое, как вы думали, вы сделали, не выполняется, или что Кажется, выражение выражает неожиданное значение. Поймать такие ошибки можно отнимает много времени, особенно когда программы становятся большими и люди вынуждены поддерживать код, разработанный другими.

Java и C / C ++ делают еще один шаг, проверяя тип. Мотивация практична, а не философский. Как вы можете поймать как можно больше ошибок как можно скорее, и быть уверенным, что все ошибки устранены перед выпуском кода в производство? Кажется, что каждый язык берет определенную стратегию и работает с ней, основываясь на том, что они думаю, это важно. В таком языке, как Perl, где привязка во время выполнения не поддерживается, имеет смысл воспользоваться преимуществом «строгого использования», чтобы упростить разработку.

3 голосов
/ 05 марта 2009

Я считаю 'use strict' в Perl скорее прагмой, как вы намекали: она меняет поведение компилятора.

Философия языка Perl отличается от философии Python. Например, вам дано более чем достаточно веревки, чтобы повеситься в Perl.

Ларри Уолл хорошо разбирается в лингвистике, поэтому у Perl есть то, что называется принципом TIMTOWTDI (скажем, tim-toe-dee) против дзен питона:

Должен быть один - и желательно только один - очевидный способ сделать это.

Вы можете очень легко использовать pylint и PyChecker, чтобы придумать свой собственный вкус use strict для python (или что-то аналогичное perl -cw *scriptname*), но из-за различных философий в языковом дизайне, вы не столкнетесь с этим в практикуйте широко.

Исходя из вашего комментария к первому постеру, вы знакомы с import this в Python. Там есть много вещей, которые освещают, почему вы не видите эквивалент use strict в Python. Если вы медитируете на коан , найденный в Дзэн Питона, вы можете найти просветление для себя. :)

1 голос
/ 19 июля 2011

Очень сложно писать большие программы без «строгого использования» на Perl. Если вы не используете «строгий», если вы снова используете переменную и неправильно пишете ее, оставляя букву, программа все равно запускается. И без тестовых случаев, чтобы проверить свои результаты, вы никогда не найдете таких ошибок. По этой причине может быть очень много времени, чтобы выяснить, почему вы получаете неправильные результаты.

Некоторые из моих программ на Perl состоят из 5000 строк на 10 000 строк кода, разбитых на десятки модулей. Никто не может по-настоящему заниматься производственным программированием без «строгого использования». Я бы никогда не допустил, чтобы производственный код устанавливался на фабрике с языками, которые не поддерживают «объявления переменных».

Вот почему Perl 5.12.x теперь использует «строгий режим» в качестве поведения по умолчанию. Вы можете отключить их.

PHP доставил мне немало проблем из-за отсутствия принудительного объявления переменных. Поэтому вам нужно ограничиться небольшими программами на этом языке.

Просто мнение ...

abcParsing

1 голос
/ 05 марта 2009

Я обнаружил, что мне действительно важно обнаруживать ссылки на необъявленные переменные. Eclipse имеет интеграцию с Pylint через PyDev и, хотя Pylint далек от совершенства, он делает разумную работу в этом.

Это идет вразрез с динамической природой Python, и мне иногда приходится добавлять #IGNORE, когда мой код что-то умный. Но я нахожу, что это случается достаточно редко, и я этим доволен.

Но я мог видеть, что некоторые функции, похожие на pylint, становятся доступны в виде флага командной строки. Вроде как в -3 переключатель Python 2.6, который определяет точки несовместимости между кодами Python 2.x и 3.x.

0 голосов
/ 06 августа 2014

Perl - это язык без ограничений, как они сказали :). Таким образом, вы можете использовать переменную до объявления; Например: если вы используете имя переменной «is_array», но вводите «is_arrby», компилятор не сообщит об ошибке без «use strict». Поэтому, когда кодируете длинную программу на Perl, лучше использовать выражение «использовать строгий». Конечно, меньше 50 строк для запуска одноразового скрипта, в этом нет необходимости :)

...