CoolPython
4.64K subscribers
20 photos
44 links
Канал об основах Python и хороших практиках разработки. Создаём системность в обрывочных знаниях.

Тем, кто хочет понимать, что пишет!
Download Telegram
Чем == отличается от is?

== проверяет, одинаковые ли значения у переменных.
is проверяет, указывают ли переменные на один и тот же объект.

Рассмотрим на примере. Создадим словарь и скопируем ссылку на него:

a = [1, 2, 3] 
b = a
b is a # True
b == a # True

Теперь создадим новый словарь с помощью копирования:

b = a[:]
b is a # False

Но из-за того, что мы скопировали в новый объект все значения старого, то содержимое двух словарей все равно совпадает:

>>> b == a    # True    

То есть, a is b по сути то же, что id(a) == id(b). Поэтому если a is b вернет True, это будет значить, что и содержимое у них одинаковое. Просто потому что это один и тот же объект.

Кстати, чтобы проверить, есть ли вообще у переменной значение, обычно пользуются оператором is, а не ==:

a = 42
a is None # False

Дело в том, что класс None реализован как синглтон. Это значит, что экземпляр этого класса существует в интерпретаторе в единственном числе и все неопределенные значения указывают на него.

a = None 
b = None
a is b # True

Для некоторых классов оператор == тоже сработает, но так лучше не делать, потому что в пользовательских классах этот оператор можно переопределить и выстрелить себе в ногу получить интересные результаты. Поэтому в PEP8 и рекомендуют проверять на значение None именно с помощью is. 🐍

#основы #identity_vs_equality #перед_собесом #типы_данных
👍4🔥1
Кеширование небольших чисел в CPython

Поговорим о небольших числах в CPython. Возьмем, например, два числа, 10 и 300:
 
>>> a = 10
>>> b = 300
>>> a is 10
True
>>> b is 300
False

Что?! Почему a указыввет на свое значение, а b y нет?

Все дело в том, что интерпретатор хранит числа в диапазоне от - 5 до 256 в специальном массиве. Поэтому когда мы пишем x = 10, то вообще-то получаем ссылку на объект, который уже существует в памяти:
 
>>> c = 1
>>> id(1)
94492411548416
>>> id(c)
94492411548416

Причем это касается любых значений, которые приводятся к целым числам этого диапазона. Можно завести число хоть в двоичном виде, хоть в hex, кеширование все равно будет работать:
 
>>> id(19)
94579033949504
>>> id(0b10011)
94579033949504
>>> id(0o23)
94579033949504
>>> id(0x13)
94579033949504

Числа вне диапазона - 5, 256 интерпретатор тоже будет пытаться оптимизировать, но только если они находятся в одной строке (или одном файле). В командной строке интерпретатора так не работает:
 
>>> d = 400
>>> d is 400
False

а так будет:
 
>>> e = 500; f = 500
>>> e is f
True

В общем и целом то, что нужно запомнить -- это что небольшие числа в интерпретаторе хранятся не так, как большие и что с ними следует пользоваться оператором ==, а не is.

И это снова не фича, а деталь реализации для экономии ресурсов. А пишу я об этом, потому что на задачу с кешем наткнулась на собеседовании, и собеседующий удивился, что я в курсе. Сказал, что узнал об этой особенности, когда начал сам проводить собеседования. Теперь это знаете и вы 🐍

#кеш #детали_реализации #low_level #identity_vs_equality
🔥2👍1