Python документы имеют вводящее в заблуждение объяснение возврата в конце концов - PullRequest
2 голосов
/ 08 января 2020

Я просматривал python документы, чтобы улучшить свое ядро ​​python, и я читал о ошибках и исключениях

В do c написано

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

Этот пример также приводится ниже:

def bool_return():
    try:
        return True
    finally:
        return False

bool_return()

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

def bool_return():
    try:
        return print("foo")
    finally:
        return False

bool_return()

Теперь, если вы запустите это, вы увидите, что foo будет напечатано и False будет возвращено. Теперь do c говорит, что return оператора finally будет выполняться перед и вместо оператора try предложения return. Если так, то почему я вижу распечатку foo?

Я отладил этот фрагмент с помощью pycharm, и он показывает, что сначала выполняется оператор return предложения try, и выводится строка, а затем выводится None возвращается из-за оператора return, а оператор return в предложении finally будет выполнен позже, что является последним возвратом программы, поэтому функция отменяет предыдущее возвращение и возвращается False.

Мой вопрос:

1) Почему c говорит, что, наконец, оператор возврата условия выполняется до ?

2) Почему c говорит, что предложение наконец оператор возврата выполняется вместо оператор возврата предложения try?

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

РЕДАКТИРОВАТЬ:

После прочтения ответа @ iBug теперь ясно, как оценивается print("foo"), но None не возвращается. По сути, сначала вычисляется выражение, а затем return. Позже return False в наконец выполняется. Что объясняет, почему мы получаем вывод, который мы сделали.

Тем не менее, я вижу, что return False в окончании выполняется после return print("foo") попытки.

Или согласно комментарию @ iBug, 10 RETURN_VALUE полностью обойден?

enter image description here

EDIT

This теперь разрешено в документации, и теперь верно то, что будет возвращено. Однако, если вы sh знаете «как», прочитайте все комментарии и внимательно ответьте.

1 Ответ

2 голосов
/ 08 января 2020
$ python3
Python 3.7.5 (default, Nov 20 2019, 09:21:52)
[GCC 9.2.1 20191008] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def bool_return():
...     try:
...         return print("foo")
...     finally:
...         return False
...
>>> import dis
>>> dis.dis(bool_return)
  2           0 SETUP_FINALLY            8 (to 10)

  3           2 LOAD_GLOBAL              0 (print)
              4 LOAD_CONST               1 ('foo')
              6 CALL_FUNCTION            1
              8 RETURN_VALUE

  5     >>   10 LOAD_CONST               2 (False)
             12 RETURN_VALUE
>>>

Как вы можете видеть выше, return False происходит до оператора return в блоке try, но после вычисления значения, которое будет возвращено.

Я думаю, что документы, вероятно, означали «само действие возврата» с помощью оператора возврата , или, другими словами, в нем не учитывалось вычисление возвращаемого значения, что, конечно, происходит до того, как он возвращается.


Чтобы посмотреть, выполняется ли 8 RETURN_VALUE или нет, вы можете скомпилировать интерпретатор CPython в режиме отладки и запустить его в GDB. Пошаговое руководство было бы слишком раздутым для этого ответа, поэтому я дам здесь набросок (Linux).

  • Получите исходный код CPython из официальный источник (python .org сайт или GitHub)
  • Сконфигурируйте отладочную сборку ./configure --with-pydebug (вы также можете указать --prefix=/opt/python3-debug), make и make install
  • Запустите отладку Python в GDB: gdb /opt/python3-debug/bin/python3 и (gdb) r
  • Определите функцию bool_return как обычно.
  • Найдите строку RETURN_VALUE в Python/ceval.c, снимите номер строки ( для 3.8.1, это 1911 ).
  • Повесьте интерпретатор Python, отправив SIGTRAP, и установите точку останова в позиции из предыдущий шаг (b Python/ceval.c:1911), а затем c.
  • Просмотр точки останова, достигнутой дважды, с выводом, подобным этому:
(gdb breakpoint info)
False
(gdb breakpoint info)
  • Наблюдайте, как точка останова достигается один раз для каждого оператора, который вы вводите в REPL. Это означает, что вторая точка останова на предыдущем шаге вызвана Python REPL, поэтому только первая точка останова получается из оператора return в функции.

Теперь ясно, что в функции был выполнен только один return, это должно быть 12 RETURN_VALUE, поэтому инструкция Python 8 RETURN_VALUE вообще не выполняется.

...