Как имена переменных хранятся и отображаются внутри?

Я читаю qaru.site/info/694183/... и кажется, что в CPython переменные - это просто имена, связанные со ссылками.

Происходит несколько вещей с утверждением x = 5:

  • создается объект int со значением 5 (или найден, если он уже существует)
  • имя x создается (или отключается с последним объектом 'x' помечено)
  • счетчик ссылок на новый (или найденный) объект int увеличено на 1
  • имя x связано с объектом с значение '5' создано (или найдено).

Тем не менее, я до сих пор не понимаю, как именно внутренние переменные реализованы.

А именно:

  1. имя x создается (или не связано с последним объектом "x" );

Тогда не будет ли это имя занимать память? sys.sizeof(x) equals sys.sizeof(5), и я получаю, что sys.sizeof(x) может только возвращать размер связанной ссылки, но тогда какой размер имени x?

  1. имя x связано с объектом со значением '5', созданным (или найденным)

Как это реализовано внутри страны? Я думаю, что на высоком уровне это можно сделать с помощью dict, где ключ - это имя переменной (str?), А значение - это ссылка, с которой она связана.

Ответ 1

Я думаю, что на высоком уровне это можно сделать с помощью dict, где ключ - это имя переменной (str?), А значение - ссылка, с которой она связана.

Вот как это работает и внутри. В CPython имена переменных и объекты, на которые они указывают, обычно хранятся в словаре Python; та же самая структура данных, которую вы можете использовать при написании кода Python.

Когда вы пишете x = 5, имя x задается в качестве ключа в словаре глобальных имен с 5 в качестве соответствующего значения. Вы можете вернуть и проверить этот словарь с помощью функции globals(), которая выдает содержимое текущего пространства имен области.

Таким образом, вы также правы, что имя x занимает место. Он существует в виде строки где-то в памяти, и Python хранит ссылку на него для ключа словаря.

Если вы хотите заглянуть глубже в источник CPython, чтобы увидеть, где x получает значение 5, вы можете взглянуть на ceval.c. Запись x = 5 запускает код операции LOAD_CONST (чтобы поместить целое число 5 в стек), а также код операции STORE_GLOBAL * (чтобы задать имя x в качестве ключа в словаре со значением 5 в качестве значения).

Вот код для STORE_GLOBAL операции STORE_GLOBAL:

TARGET(STORE_GLOBAL) {
    PyObject *name = GETITEM(names, oparg);
    PyObject *v = POP();
    int err;
    err = PyDict_SetItem(f->f_globals, name, v);
    Py_DECREF(v);
    if (err != 0)
        goto error;
    DISPATCH();
}

Вы можете увидеть вызов PyDict_SetItem для обновления словаря глобальных переменных.


* Если вы проверяете байт-код, сгенерированный x = 5 (например, используя dis), вы можете увидеть STORE_NAME код операции STORE_NAME. Этот опкод функционирует таким же образом (см здесь для краткого описания).