Всё — объект: id, type, ссылки, is и ==
Всё — объект
В Python всё — объекты: числа, строки, функции, классы, модули, даже None и сами типы.
import math
for obj in [42, "hi", [1, 2], None, len, math, int, type]:
print(f"{obj!r:40.40} тип: {type(obj).__name__}")
У каждого объекта есть:
| Характеристика | Как узнать | Может меняться? |
|---|---|---|
| идентичность | id(obj) (в CPython — адрес в памяти) |
нет |
| тип | type(obj) |
нет |
| значение | само содержимое | только у изменяемых объектов |
Переменная — ссылка
Переменная хранит не объект, а ссылку на него. Присваивание = привязывает имя к объекту и никогда не копирует:
a = [1, 2, 3]
b = a # теперь у одного списка два имени (псевдонимы)
print(id(a), id(b), a is b)
b.append(4)
print(a)
c = [1, 2, 3, 4] # другой объект с таким же значением
print(a == c, a is c)
Нажмите 👣 Пошагово и посмотрите на номера объектов: a и b указывают на #1, а c — на #2.
is и ==
a == b— равенство значений: вызываетa.__eq__(b).a is b— идентичность: это один и тот же объект? (id(a) == id(b)). Переопределить нельзя.
class AlwaysEqual:
def __eq__(self, other):
return True
x = AlwaysEqual()
print(x == None, x is None) # == можно «обмануть», is — нет
Когда использовать is
Только для синглтонов: x is None, x is not None, иногда x is True/x is False или собственный объект-маркер _MISSING = object(). Во всех остальных случаях — ==.
Кеширование малых объектов
CPython заранее создаёт целые числа от −5 до 256 и переиспользует их. Поэтому is для маленьких чисел «работает», а для больших — нет:
a = 256
b = 256
print(a is b) # True — один закешированный объект
x = int("1000")
y = int("1000")
print(x == y, x is y) # True False — два разных объекта
Это деталь реализации, на которую нельзя полагаться — один из любимых вопросов «что выведет код». Подробнее — в уроке «Истинность, сравнение и кеширование объектов».
Ссылки и сборка мусора
У каждого объекта есть счётчик ссылок. Когда он становится нулём, объект удаляется:
import sys
data = [1, 2, 3]
print(sys.getrefcount(data)) # на 1 больше: сам вызов getrefcount временно держит ссылку
alias = data
print(sys.getrefcount(data))
container = [data, data]
print(sys.getrefcount(data))
del alias # удаляем ИМЯ, а не объект
print(sys.getrefcount(data), data)
del x удаляет имя x. Объект живёт, пока на него ссылается хоть что-то: другие имена, элементы списков, атрибуты объектов, замыкания.
class Noisy:
def __init__(self, name):
self.name = name
def __del__(self):
print(f"объект {self.name} удалён")
a = Noisy("A")
b = a
del a
print("после del a объект ещё жив, его держит b")
del b
print("конец")
Аргументы функций — тоже ссылки
При вызове функции параметр становится ещё одним именем того же объекта. Поэтому функция может изменить переданный изменяемый объект:
def add_item(items, x):
items.append(x) # меняет тот самый список
shopping = ["хлеб"]
add_item(shopping, "молоко")
print(shopping)
Подробно — в следующем уроке.
Функции и классы — тоже объекты
def greet():
return "привет"
print(id(greet), type(greet), greet.__name__)
f = greet # ещё одна ссылка на функцию
print(f is greet, f())
print(type(int), type(type), isinstance(int, object), isinstance(greet, object))
Итог
- Каждый объект имеет идентичность (
id), тип (type) и значение. - Переменные — ссылки;
=связывает имя с объектом и не копирует; несколько имён одного объекта — псевдонимы. ==сравнивает значения,is— идентичность;is— только дляNoneи других синглтонов.- Малые int кешируются (−5…256) — деталь реализации.
- Объект удаляется, когда на него не остаётся ссылок;
delудаляет имя.
Практика решено 0 из 6
Какие три характеристики есть у каждого объекта в Python?
Что выведет код?
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b, a is b, a is c)
Напишите функцию same_object(x, y), которая возвращает строку:
"один объект", если x и y — один и тот же объект; "равны", если разные, но равные по значению;
иначе "разные".
Какие тесты проверяют код (3)
a = [1]; assert same_object(a, a) == "один объект" assert same_object([1], [1]) == "равны" assert same_object([1], [2]) == "разные"
def same_object(x, y):
if x is y:
return "один объект"
if x == y:
return "равны"
return "разные"
Почему с None сравнивают через is, а не через ==?
Что делает del x?
Что выведет print(x is y)?
| True | False | |
|---|---|---|
x = None; y = None |
||
x = [1]; y = x |
||
x = [1]; y = x[:] |
||
x = (1, 2); y = tuple(x) |
||
x = {}; y = {} |
Войдите, чтобы отмечать пройденные уроки.