Нужна помощь в понимании того, как работает эта рекурсивная функция - PullRequest
2 голосов
/ 07 декабря 2009

Вот функция (спасибо пользователю Abbot, за предоставление его в другом вопросе)

def traverse(ftp):

    level = {}
    for entry in (path for path in ftp.nlst() if path not in ('.', '..')):
        ftp.cwd(entry)
        level[entry] = traverse(ftp) 
        ftp.cwd('..')
    return level

Вот что я не понимаю: когда python входит в функцию, он создает пустой словарь (level). В цикле for он сохраняет имя каталога в качестве ключа в словаре. Что касается значения этого ключа, python снова входит в функцию и ищет каталог, и он становится значением этого ключа.

Но как словарь уровней запоминает значения внутри? Я имею в виду, не следует ли его сбрасывать / очищать каждый раз, когда питон входит в функцию?

Ответы [ 5 ]

7 голосов
/ 07 декабря 2009

Нет. Каждый «экземпляр» функции имеет свою собственную копию level, и между различными копиями level.

нет никаких побочных эффектов.

Возьмите это дерево папок:

root
 `-home
    |- lyrae
    |   |- ftp.py
    |   `- http.py
    `- badp

Вот (упрощенный) поток выполнения при вызове ftp на root:

  • ftp(root) создает пустой level словарь
  • ftp(root) перечисляет подпапки: (home).
  • ftp(root) выбирает первую подпапку и меняет каталог на нее.
  • ftp(root) устанавливает level[home] на результат ftp в текущей папке.

  • ftp(home) создает пустой level словарь
  • ftp(home) перечисляет подпапки: (lyrae, badp).
  • ftp(home) выбирает первую подпапку и меняет каталог на нее.
  • ftp(home) устанавливает level[lyrae] на результат ftp в текущей папке.

  • ftp(lyrae) создает пустой level словарь
  • ftp(lyrae) перечисляет подпапки: ().
  • ftp(lyrae) вне подпапок для анализа и возвращает level.

  • ftp(home) выполняет задание: levels = {'lyrae': {}}
  • ftp(home) переходит в следующую папку.
  • ftp(home) устанавливает level[badp] на результат ftp в текущей папке.

  • ftp(badp) создает пустой level словарь
  • ftp(badp) перечисляет подпапки: ().
  • ftp(badp) вне подпапок для анализа и возвращает level.

  • ftp(home) выполняет задание: levels = {'lyrae': {}, 'badp': {}}
  • ftp(home) вне подпапок для анализа и возвращает level.

  • ftp(root) выполняет задание: levels = {'home': {'lyrae': {}, 'badp': {}}}
  • ftp(root) вне подпапок для анализа и возвращает level.
2 голосов
/ 07 декабря 2009

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

1 голос
/ 07 декабря 2009

Область действия level ограничена только функцией. Даже если функция вызывает себя, это не значит, что , что внутренние переменные вызова функции ( разные level) такие же, как эта одна.

1 голос
/ 07 декабря 2009

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

1 голос
/ 07 декабря 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...