locals () и ссылка на объект в python - PullRequest
0 голосов
/ 14 сентября 2018

Я нашел кое-что любопытное в том, как python отслеживает объекты в locals().

С учетом следующего сценария:

import gc


class T(object):
    pass


def func1():

    t = T()

    #locals()
    del t
    #locals()

    for o in gc.get_objects():
        if type(o) is T:
            print("STILL EXISTS")


func1()

Запуск с комментариями к обоим locals() вызовам (как указано выше) даетМне не пришло сообщений о том, что созданный объект T() был подвергнут сборке мусора.

Когда я запускаю его с первой командой locals() (удаляя первый комментарий), создается словарь со ссылкойк моему t объекту.Этот словарь не связан с какими-либо именами, поэтому я не ожидал бы, что этот диктат будет работать, не будучи собранным мусором.

Проблема в том, что при выполнении кода я получаю "STILL EXISTS".Даже если я удаляю t из пространства имен функции, объект не является сборщиком мусора, так как на него все еще ссылается dict, возвращаемый locals().

Достаточно забавно, если я снова вызываю locals() (удалениевторой комментарий в приведенном выше коде), затем словарь каким-то образом обновляется, в нем не содержится t, а объект удаляется мусором (и я не получаю "STILL EXISTS" сообщения).

Я нахожу это поведение немного странным.

Вопросы:

  1. Это нормально, что словарь, возвращаемый locals(), является долгоживущим, даже не связывая его с какими-либо именами?
  2. Это нормально или есть причина, по которой этот словарь не обновляется автоматически при удалении имен из текущей области?

Редактировать: Я использую cpython 3.6

Спасибо!

1 Ответ

0 голосов
/ 14 сентября 2018

locals() странно. Внутри функции каждый вызов locals() копирует текущие значения локальной переменной в dict, связанный с кадром стека, и возвращает dict. DICT не используется для фактического поиска локальной переменной, но присоединяется к объекту фрейма, и каждый раз это не новый диктат; все locals() вызовы в одном и том же кадре стека повторно используют один и тот же запрос.

Когда вы вызываете locals(), локальный dict теперь имеет ссылку на все объекты, на которые в данный момент ссылаются локальные переменные. Это будет поддерживать эти объекты до тех пор, пока либо не исчезнет фрейм стека, либо в этом фрейме стека не будет сделан новый вызов locals() с различными значениями локальной переменной. Несколько других вещей также обновят dict локальных данных, например, получение атрибута f_locals объекта стекового фрейма, но присваивание локальной переменной само по себе не обновляет dict localals.

...