Почему эта синтаксическая ошибка Python не является ошибкой? - PullRequest
0 голосов
/ 28 февраля 2020

Сегодня я столкнулся со следующей ошибкой - это минимальный пример.

class Foo:

    def __init__( self, filename ):
    #    set-up LOG_FILE

    def log( self, msg ):
        print( msg, file=self.LOG_FILE )

#------

##  A) Problem here:
#
foo = Foo
(
    "/dev/stderr"
)

#------

def  bar( log_line ):
    foo.log( "bar:  "+ log_line )

##  elsewhere ...

bar("this is a test")   #  B) example line

Вы, несомненно, понимаете, что утверждение A необходимо исправить, , а именно .:

##  C) Corrected syntax:   
#
foo = Foo            \  
(                    \
    "/dev/stderr"    \   
)      

Это просто исправление. Однако, когда вы запускаете первую версию (с проблемой), вывод вводит в заблуждение. Начнем с того, что Python во время выполнения выполняет оператор в (B).

Traceback (most recent call last):
   :
   foo.log( "bar:  "+ log_line )
TypeError: log() missing 1 required positional argument: 'log_line'

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

Я также проверил с помощью pylint. У него также есть интересное понимание ошибки:

E1120: No value for argument 'self' in unbound method call (no-value-for-parameter)

Что смутило всех. Только после помещения конструктора в одну строку мы ясно увидели проблему.

Таким образом, вопрос:

  • Учитывая, что требуются обратные слеши
  • Почему этот синтаксис не является синтаксической ошибкой?

Следует ли сообщать об этом как об ошибке? Для этого упражнения я использовал Python v3.7.5 и pylint

pylint 2.2.2
astroid 2.1.0
Python 3.7.5 (default, Nov 20 2019, 09:21:52) 
[GCC 9.2.1 20191008]

1 Ответ

4 голосов
/ 28 февраля 2020

Это просто два оператора:

foo = Foo

Определяет новую переменную с именем foo, которая ссылается на класс Foo . После этого вы можете делать такие вещи, как

foo("/dev/stderr")

, и это создаст новый экземпляр Foo.

Второй оператор -

(
    "/dev/stderr"
)

, который является просто выражением в скобках, которое содержит строку; он ничего не делает (сродни написанию только (1) на отдельной строке).

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

...