Почему явные продолжения строк с отступом не допускают комментариев в Python?

#python

#python

Вопрос:

Я пишу синтаксический анализатор Python для изучения Flex и Bison, и я пытаюсь выяснить, почему только первая из этих программ является допустимой для Python.

a.py :

 
# This is valid Python
  

ошибка не возникает.

b.py :

     
# This is not valid Python
  

выдает эту ошибку:

   File "b.py", line 1
    
    ^
IndentationError: unexpected indent
  

и c.py :

 if True:
    pass
    
    # This is not valid Python
  

выдает эту ошибку:

   File "c.py", line 4
    # This is not valid Python
                             ^
SyntaxError: invalid syntax
  

Я использую Python 2.6.5 (r265: 79063, апрель 16 2010, 13:09:56) [ GCC 4.4.3] на linux2 (Ubuntu 10.04); Однако тестирование на ideone.com предполагает, что поведение такое же и на Python 3.

Комментарии:

1. Почему вы хотите это сделать?

2. спросите себя, почему я выполняю продолжение строки в пустой строке перед комментарием?

3. @Will я не столько хочу писать код таким образом, но я пишу синтаксический анализатор Python для изучения flex bison, и я хотел бы знать, почему это недопустимо.

Ответ №1:

Это деталь реализации.

Вот как несколько разных реализаций реагируют на ваш код:

                  a.py  b.py  c.py    
                 ----  ----  ----
CPython 2.6.5     ok    bad   bad
CPython 3.?       ok    bad   bad
Jython 2.2.1      ok    ok    bad
Jython 2.5.2      bad   bad   bad
IronPython 2.7.1  ok    bad   ok
  

Мое чтение раздела Exlplicit Line Joining в справочнике по языку Python заключается в том, что все три примера можно рассматривать как допустимые:

Две или более физических строк могут быть объединены в логические строки с использованием символов обратной косой черты ( ) следующим образом: когда физическая строка заканчивается обратной косой чертой, которая не является частью строкового литерала или комментария, она соединяется со следующей, образуя единую логическую строку, удаляя обратную косую черту и следующий конец-символ строки.

Если бы CPython был изменен, чтобы принять все три примера как действительные, я сомневаюсь, что это было бы замечено его пользователями, изменило характер языка или нарушило какой-либо код.

Комментарии:

1. @agf: Возможно, мне следовало сделать более короткую цитату, но я хотел предоставить контекст для моего чтения этого ключевого предложения: «когда физическая строка заканчивается обратной косой чертой, которая не является частью строкового литерала или комментария, она соединяется со следующей, образуя единую логическую строку, удаляяобратная косая черта и следующий символ конца строки. » Если мы применим это правило к коду примера, все эти конструкции должны быть приемлемыми. Но это не так, поэтому я полагаю, что это деталь реализации.

2. Я думаю, идея заключается в том, что символ продолжения строки делает строку больше не просто пробелом — в строке что-то есть, поэтому слабость, применяемая к строкам пробелов / комментариев, не возникает. Смотрите мой ответ.

3. Интересно. Jython 2.2.1 принимает a и b, но не c . Однако Jython 2.5.2 не принимает ни одного из них (хотя он примет a, если я добавлю последующее утверждение, но не b или c).

4. @agf Это не совсем так. Поведение 2.5.2, по-видимому, заключается в том, чтобы полностью игнорировать строку, содержащую комментарий, поэтому он по-прежнему ожидает утверждения, следующего за символом продолжения строки. Помещение дополнительного оператора в начало не помогает; это должно быть в конце.

5. Я только что проверил IronPython 2.7. Он принимает a.py и c.py . Он захлебывается b.py , выдавая SyntaxError: invalid syntax , а не IndentationError заданный CPython.

Ответ №2:

Цитата Стивена уместна, но она по-прежнему не объясняет эту ситуацию напрямую.

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

  • a.py : Похоже, что он обрабатывает первую строку как пробел. Это не так; как только достигнут символ продолжения строки, он и новая строка удаляются, и, поскольку в этой строке больше ничего нет, она не существует для целей синтаксического анализа — у вас есть только одна строка с комментарием. Примечание: Jython 2.5.2 обрабатывает это в основном так, как ожидалось; допустимый код Python ожидается в более поздней строке.

  • b.py : Никогда не переходит к комментарию, как только достигается символ продолжения строки, и строка больше не является просто пробелом, отступ становится ошибкой.

  • c.py : Комментарий снова не имеет значения, вы получите ту же ошибку с любым количеством пробелов и / или комментарием к следующей строке. Вам нужно иметь фактический код Python в строке, следующей за символом продолжения строки.

Ответ №3:

can join, EOL, EOF

Итак, это работает

 
# This is valid Python
  

но здесь

 if True:
    
    # This is not valid Python
  

после того, как анализатор ищет строку с отступом, которой не существует.

Комментарии:

1. За исключением того, что первое работает даже без EOF после него (после других строк), а второе не работает даже с другой строкой с отступом после строки пробела / комментария. Также обратите внимание, что ошибки во втором SyntaxError нет IndentationError .

Ответ №4:

Гвидо регулярно напоминает в своем блоге и сообщениях по почте, что он хочет максимально упростить реализацию синтаксического анализатора Python.

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

Комментарии:

1. Это может быть или не быть предполагаемым поведением, но это объяснимое поведение. Также я не уверен, что есть какие-либо доказательства того, что решение сохранить его в качестве синтаксического анализатора LL (1) имеет значение.