Ссылки в Python и счетчики ссылок

В этом руководстве вы получите представление о ссылках в Python и подсчете ссылок.

Содержание

Введение в ссылки на Python

В Python переменная не является меткой значения, как вы думаете. Вместо этого переменная ссылается на объект, содержащий значение. Другими словами, переменные являются ссылками.

В следующем примере переменной присваивается число со значением 100:

counter = 100

Python создает в памяти новый целочисленный объект(int) и привязывает переменную counter к этому адресу памяти:

Пример ссылки на Python

Когда вы получаете доступ к переменной counter, Python ищет объект, на который ссылается счетчик, и возвращает значение этого объекта:

print(counter) # 100

Таким образом, переменные — это ссылки, указывающие на объекты в памяти.

Чтобы найти адрес памяти объекта, на который ссылается переменная, вы передаете переменную встроенной функции id().

Например, следующая команда возвращает адрес памяти целочисленного объекта, на который ссылается переменная counter:

counter = 100
print(id(counter))

Выход:

140717671523072

Функция id() возвращает адрес памяти объекта, на который ссылается переменная, в виде числа по основанию 10.

Чтобы преобразовать этот адрес памяти в шестнадцатеричную строку, вы используете функцию hex():

counter = 100

print(id(counter)) 
print(hex(id(counter)))

Выход:

140717671523072
0x7ffb62d32300

Подсчет ссылок

Объект по адресу памяти может иметь одну или несколько ссылок. Например:

counter = 100

Целочисленный объект со значением 100 имеет одну ссылку, которая является переменной-счетчиком. Если вы присвоите счетчик другой переменной, например max:

counter = 100
max = counter

Теперь переменные counter и max ссылаются на один и тот же целочисленный объект. Целочисленный объект со значением 100 имеет две ссылки:

Подсчет ссылок в Python

Если вы присвоите другое значение переменной max:

max = 999

…целочисленный объект со значением 100 будет иметь одну ссылку, которая является переменной-счетчиком:

Пример подсчета ссылок

А количество ссылок целочисленного объекта со значением 100 будет равно нулю, если вы присвоите переменной-счетчику другое значение:

counter = 1

Пример присвоения переменной-счетчику другого значения

Если у объекта нет ссылки, диспетчер памяти Python уничтожит этот объект и освободит память.

Как подсчитать количество ссылок

Чтобы получить количество ссылок на объект, вы используете метод from_address() модуля ctypes.

ctypes.c_long.from_address(address).value

Чтобы использовать этот метод, вам необходимо передать адрес памяти объекта, ссылки на который вы хотите подсчитать. Кроме того, адрес должен быть целым числом.

Ниже определяется функция ref_count(), которая использует метод from_address():

import ctypes


def ref_count(address):
    return ctypes.c_long.from_address(address).value

Теперь вы можете использовать более короткую функцию ref_count() вместо длинного синтаксиса, как указано выше.

В этом примере определяется список из трех целых чисел:

numbers = [1, 2, 3]

Чтобы получить адрес памяти списка номеров, вы используете функцию id() следующим образом:

numbers_id = id(numbers)

Ниже показано количество ссылок на список, на который ссылается переменная Numbers:

print(ref_count(numbers_id))  # 1

Она возвращает единицу, поскольку на список ссылается только переменная чисел.

Это присваивает переменную чисел новой переменной:

ranks = numbers

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

print(ref_count(numbers_id)) # 2

Если вы присвоите переменную Ranks None, количество ссылок в списке уменьшится до одного:

ranks = None
print(ref_count(numbers_id))  # 1

А если вы присвоите переменную Numbers None, количество ссылок в списке будет равно нулю:

numbers = None
print(ref_count(numbers_id))  # 0

Все это вместе:

import ctypes


def ref_count(address):
    return ctypes.c_long.from_address(address).value


numbers = [1, 2, 3]
numbers_id = id(numbers)

print(ref_count(numbers_id))  # 1

ranks = numbers
print(ref_count(numbers_id))  # 2

ranks = None
print(ref_count(numbers_id))  # 1

numbers = None
print(ref_count(numbers_id))  # 0
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *