Почему число ссылок на Python для маленьких целых чисел удивительно велико?

Вэтот Ответ Я нашел способ получить количество ссылок на объекты в Python.

Они упомянули использованиеsys.getrefcount(), Я попробовал, но получаю неожиданный результат. Когда есть 1 ссылка, кажется, что количество равно 20. Почему это?

Я посмотрел надокументация но это не объясняет причину.

 cdarke07 июл. 2016 г., 21:43
@Valerie: в том же духе, посмотрите наid, В реализации C он возвращает виртуальный адрес. Значение не полезно, но сравните адрес объектов. Например:a=42, b=42сравнитьid(a) а такжеid(b), Теперь измените один из них и сделайте это снова. Теперь попробуйте то же самое с двумя списками, и сделайтеlist1 = list2 и посмотрите наid каждого.
 user619504307 июл. 2016 г., 21:37
@BhargavRao ха-ха, угадайте, что, это было 3 снова :)
 cdarke07 июл. 2016 г., 21:38
Просто идет, чтобы показать, что есть только одинNone объект, который много (4533) вещей использовать. Демонстрирует, что имена переменных являются просто ссылками. Вы получили 3 за 257, потому что 2 другие вещи в Python используют его (sys.getrefcount сам добавляет один к счетчику ссылок).
 user619504307 июл. 2016 г., 21:36
@cdarke 4534 !? это почему :)
 cdarke07 июл. 2016 г., 21:35
Пытатьсяsys.getrefcount(None) за интересный номер.
 Padraic Cunningham07 июл. 2016 г., 21:34
Пытатьсяsys.getrefcount(257) и это, вероятно, заметно упадет.
 user619504307 июл. 2016 г., 21:39
Спасибо всем, только что многое узнал о питоне. Я думаю, что такие вещи они пропускают в уроках Hello World :)
 Bhargav Rao07 июл. 2016 г., 21:36
Пытатьсяsys.getrefcount("Valerie") также. (Чтобы быть в синхронизации с другими комментаторами здесь)
 Padraic Cunningham07 июл. 2016 г., 21:36
Снова детали реализации, но небольшие целые числа от -5 до 257 являются интернированными, поэтому количество ссылок для этого диапазона будет намного выше.
 user619504307 июл. 2016 г., 21:35
Это действительно странно, я никогда не создавал переменную с 257. Почему он возвращает 3?
 smci30 июл. 2016 г., 23:27
Ваш заголовок вводил в заблуждение: это был не просто объект, это было маленькое целое число.

Ответы на вопрос(3)

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

Python пытается сохранить только одно фактическое значение для каждой ссылки. Таким образом, 100, которое вы имеете в своем примере, будет тем же самым 100, которое является некоторым внутренним пределом для рекурсивных вызовов, или теми же 100, что и индекс текущего цикла.Python хранит дополнительные ссылки на некоторые распространенные объекты, включая младшие целые числа. Счетчик ссылок до 1,234,567 отличается от счетчика до 20.Многие функции запоминают и сохраняют ссылки на последние аргументы.Некоторые интерпретаторы сохраняют ссылки на последние значения и значения, на которые ссылаются последние строки. Например, предыдущее возвращаемое значение хранится в «_». Это означает, что запуск в интерпретаторе и запуск из командной строки даст разные ответы.Как и во всех схемах подсчета ссылок, здесь есть ошибки. Например, PyTuple_GetItem () имеет несколько сомнительных вариантов.

Точные ссылочные значения и значения этих значений будут отличаться в PyPi по сравнению с C-Python и IPython. Подсчет ссылок редко является хорошим инструментом для нахождения странного поведения в Python.

который очень хорошо написан и понятен для чтения. (Я имею в виду версию 2.7.12, если вы хотите поиграть дома.) Хорошим местом для начала понимания кода является отличная серия лекций:C Python Internals который начинается с точки зрения начинающего.

Критический код (написанный на C), относящийся к нам, появляется в файле 'Objects / intobject.c' (я удалил некоторый код #ifdef и немного изменил создание нового объекта Integer для ясности):

    #define NSMALLPOSINTS           257
    #define NSMALLNEGINTS           5
    static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

    PyObject *
    PyInt_FromLong(long ival)
    {
        register PyIntObject *v;
        if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
            v = small_ints[ival + NSMALLNEGINTS];
            Py_INCREF(v);
            return (PyObject *) v;
        }
        /* Inline PyObject_New */
        v = (PyIntObject *)Py_TYPE(v);
        PyObject_INIT(v, &PyInt_Type);
        v->ob_ival = ival;
        return (PyObject *) v;
    }

По сути, он создает предустановленный массив, содержащий все числа от -5 до 256 включительно, и использует эти объекты (увеличивая их число ссылок с помощью макроса Py_INCREF), если это возможно. Если нет, он создаст новый объект PyInt_Type, который инициализируется с количеством ссылок 1.

Тайна того, почему каждое число имеет счетчик ссылок 3 (фактически, практически любой новый объект), раскрывается только тогда, когда вы смотрите на байт-код, который генерирует Python. Виртуальная машина работает со стеком значений (немного как в Forth), и каждый раз, когда объект помещается в стек значений, он увеличивает счетчик ссылок.

Так что я подозреваю, что ваш код сам предоставляет все 3 ссылки, которые вы видите, поскольку для чисел, отсутствующих в списке небольших значений, вы должны получить уникальный объект. Первая ссылка, вероятно, находится в стеке значений для вызывающей стороны getrefcount, когда она делает вызов; вторая находится в списке локальных переменных для фрейма getrefcount; третья, скорее всего, находится в стеке значений во фрейме getrefcount, пока просматривает счетчик ссылок.

Полезным инструментом, если вы хотите углубиться в проблему, являются команда 'compile' и команда 'dis' (disassemble), находящиеся в модуле 'dis', которые вместе позволят вам прочитать фактический байт-код, сгенерированный любой фрагмент кода Python, и он должен помочь вам точно определить, когда и где создается третья ссылка.

Что касается большего количества ссылок для небольших значений, то при запуске Python он автоматически загружает всю Стандартную библиотеку и выполняет довольно много кода инициализации модуля Python, прежде чем приступить к интерпретации собственного кода. Эти модули содержат свои собственные копии многих маленьких целых чисел (и объект None, который также является уникальным).

Решение Вопроса

sys.getrefcount вызов. Это не просто ссылки, которые вы создали; есть все виды других ссылок на него в других модулях и во внутренних компонентах Python, поскольку (это детали реализации) стандартная реализация Python создает только один100 объект и использует его для всех случаев100 в программе Python.

 user619504307 июл. 2016 г., 21:33
Интересно, приятно знать, спасибо!
 alexis07 июл. 2016 г., 21:38
Более уместно, если вы создадите свои собственные объекты (списки, кортежи, экземпляры классов), вы получите ожидаемое поведение.

Ваш ответ на вопрос