Почти все программисты сегодня пишут код на человекочитаемых языках, который понятен людям: Python, JavaScript, C. Но машины этот язык не понимают, потому что основаны на транзисторах — в зависимости от того, проходит ток через транзистор или нет, он становится либо 0, либо 1. Поэтому компьютер, по сути, понимает только эти два значения.
Современные транзисторы очень маленькие, и в одном компьютере или телефоне их может быть несколько миллиардов. С таким количеством даже двух значений (0 или 1) на каждый транзистор хватает, чтобы создать сложную программу. Людям привычнее считать в десятичной системе, но если в программе понадобятся именно двоичные значения, инструменты для работы с ними тоже есть. Один из них — функция bin()
, работу с ней на практике разбираем сегодня.
Что такое функция bin() в Python
Эта функция нужна для перевода целого числа из десятичной системы в двоичную.
В двоичной системе числа представлены в виде комбинаций из 0 и 1. Десятичная использует цифры от 0 до 9. Теперь смотрите: в мире есть не только двоичная и десятичная системы. Есть троичная, четверичная и системы с любым другим количеством символов. Например, шестнадцатеричная использует цифры десятичной плюс ещё 6 букв латинского алфавита.
Но в Питоне по умолчанию все целые числа считаются десятичными, а в памяти компьютера они хранятся как двоичные. Когда мы используем bin()
, то просто просим компьютер показать число в исходном виде.
Синтаксис функции bin()
Для использования функции в коде понадобятся три вещи:
- переменная, которая будет хранить результат;
- ключевое слово
bin()
со скобками; - целое число, которое мы передадим в эти скобки в качестве аргумента.
Правильная запись функции
В примере ниже в первой строке мы используем переменную number
и сохраняем в неё результат преобразования десятичного числа 99 в двоичную систему. Второй строкой выводим результат работы функции на экран:
number = bin(99)
print(number)
В консоли получаем:
0b1100011
👉 Первые два символа обозначают двоичную систему счисления.
Какие аргументы принимает
Для работы bin()
нужен только один аргумент — это целое число, которое мы передаём в скобках для преобразования в двоичную систему. Правильно говорить, что это число формата integer
или int
.
С другими типами данных функция не работает и выдаст ошибку, если попытаться передать в неё строку или дробное число.
Возвращаемое значение
Может показаться, что раз функция преобразует десятичные числа в двоичные, то она тоже возвращает число. Но проблема в том, что по умолчанию в Python нет чисел двоичного формата.
👉 Поэтому bin()
возвращает строку с префиксом 0b
.
Примеры использования bin()
Вот несколько простых программ из нескольких строк кода с результатом, чтобы было лучше понятно, как работает эта функция.
Простые примеры с целыми числами
В bin()
можно передать число любого размера — но нужно помнить, что при переводе в двоичную систему это значение сильно будет занимать много места:
# создаём первую переменную с целым числом
a = bin(9)
print('Однозначное число: ', a)
# создаём вторую переменную с целым числом
b = bin(999)
print('Трёхзначное число: ', b)
# создаём третью переменную с целым числом
c = bin(999999999)
print('Девятизначное число: ', c)
При запуске получаем такой результат в консоли:
Однозначное число: 0b1001
Трёхзначное число: 0b1111100111
Девятизначное число: 0b111011100110101100100111111111
Работа с отрицательными числами
В реальной жизни отрицательные двоичные числа получаются в три шага.
Сначала число нужно представить в байтовых блоках, каждый из которых состоит из 8 битов. В таком виде число должно иметь количество знаков, кратное 8, даже если в начале будут стоять нули.
Например, у нас есть число 9 в двоичном обычном виде — оно выглядит как 1001
Но для перевода в отрицательную форму нам понадобится фиксированный вид объёма байтовых блоков: 8-битный, 16-битный, 32-битный.
Число 9 в двоичном 8-битном виде будет выглядеть как 00001001
После этого все биты инвертируются. Если положительное 9 было 00001001
, то в отрицательном будет все нули станут единицами, и наоборот: 11110110
.
В конце к инвертированному числу прибавляется единица:
11110110 + 1 = 11110111
Это и есть двоичное представление десятичного числа -9.
Обратите внимания, что в настоящей двоичной системе нет знака минус, его роль играет старший бит — самый левый символ в байтовых блоках. У положительных чисел там 0, у отрицательных — всегда 1. Поэтому в одном байтовом блоке могут быть такие значения:
- положительные: от
0000 0000
(0) до0111 1111
(+127) - отрицательные: от
1000 0000
(−128) до1111 1111
(−1)
Если использовать не один, а два или больше байтовых блоков, мы можем представлять числа в большем диапазоне, но логика с нулём и единицей в крайнем левом бите остаётся.
Но функция bin()
работает по-другому: вместо выдачи реального числа она выдаёт упрощённую запись, просто добавляя знак - перед положительным представлением:
# переводим отрицательное число −9 в двоичную систему
binary = bin(−9)
# выводим результат
print(binary)
Результатом будет такая строка:
-0b1001
❗️ Это не настоящее двоичное число, а его обозначение для упрощения работы разработчиков.
Особенности работы с разными типами данных
При использовании bin()
в коде нужно помнить, что функция умеет работать только с целыми числовыми значениями.
Поэтому стоит заранее предусмотреть обработку ошибки, если кто-то попытается передать в качестве аргумента строку или число с плавающей точкой. Для этого понадобятся блоки try-except
, когда мы запускаем блок кода, про который заранее известно, что он может вызвать ошибку. В блоке except
мы сразу говорим, какую ошибку ожидаем и что объяснить пользователю:
# создаём переменную, которая хранит строку
learn = 'string'
# пытаемся перевести строку в двоичную систему
try:
# это вызовет ошибку
binary = bin(learn)
# обрабатываем ошибку и пишем объяснение
except TypeError:
print("Ошибка: bin() принимает только целые числа")
Теперь при запуске в терминале мы увидим заготовленное сообщение:
Ошибка: bin() принимает только целые числа
Практическое применение
Иногда может быть полезно работать именно с битовыми значениями и смотреть, как они выглядят при отладке. Вот несколько примеров.
Использование в битовых операциях
Это действия над отдельными битами — работа с данными на самом низком уровне, который понимают машины. Основные битовые операции такие:
Побитовое И (AND). В коде обозначается знаком амперсанда &
. Операция сравнивает два бита и возвращает 1, если оба бита тоже равны 1. Если один из битов равен 0, то результатом будет 0.
Побитовое ИЛИ (OR). В коде обозначается прямой чертой |
. Возвращает 1 при сравнении двух битов, если хотя бы один из них равен 1. Если оба равны 0, вернёт 0.
Побитовое исключающее ИЛИ (XOR). В коде обозначается знаком циркумфлекса ˆ
, который часто используется для возведения в степень. Работает как «побитовое ИЛИ» наоборот — даёт в результате 1, если два сравниваемых бита различны.
Побитовое НЕ (NOT). В коде обозначается тильдой ~
. Инвертирует каждый бит: 0 становится 1, и наоборот.
Примеры из реальных проектов
В одном битовом числе можно хранить сразу несколько значений и встраивать такой показатель для отслеживания происходящего в сервисе.
Пример — в приложении может использоваться несколько состояний-флагов какого-то отдельного модуля программы:
- Флаг абстрактного метода METHOD, битовое значение
0b0001
. - Флаг возможности вернуть значение из функции RETURNS, значение
0b0010
. - Флаг представления значения в другой системе REPRESENTATION, значение
0b0100
. - Флаг того, является ли показатель предустановленным, — PREFIXED, значение
0b1000
.
В коде эти состояния будут обозначаться переменными с заглавными буквами — константами, которые не меняются. Но вместо одного флага может быть другой, например вместо ALIVE может быть DEAD.
Суть в том, что все четыре значения можно хранить в одном. Посмотрите, так значения-флаги будут выглядеть по отдельности:
0b0001
0b0010
0b0100
0b1000
Одно битовое значение, которое показывает, что у персонажа сохраняются все состояния:
0b1111
Такое общее значение называется битовой маской. Чтобы установить начальное состояние игрока, можно использовать битовые операции, например объединить значения ALIVE и VISIBLE.
Для примера напишем программу, которая будет управлять несколькими состояниями главного героя в игре
# состояния игрока в битовых флагах
ALIVE = 0b0001
VISIBLE = 0b0010
MOVING = 0b0100
SHOOTING = 0b1000
# начальное состояние: жив и видим
player_state = ALIVE | VISIBLE
Чтобы не просто хранить битовые значения, а делать их понятными для разработчиков, для них можно написать поясняющую функцию. Такая функция будет выводить и битовую маску со всеми значениями и говорить, какие флаги на этой маске включены.
# функция объяснения всех флагов
def print_state(state):
# выводим состояние игрока в двоичном виде
print("\nТекущее состояние игрока:")
print(f" В двоичном виде: {bin(state)}")
# пишем словами все статусы состояний
print(f" Жив: {'да' if state & ALIVE else 'нет'}")
print(f" Видим: {'да' if state & VISIBLE else 'нет'}")
print(f" Движется: {'да' if state & MOVING else 'нет'}")
print(f" Стреляет: {'да' if state & JUMPING else 'нет'}")
Добавим ещё такую мини-функцию: если одно из состояний меняется, мы меняем этот флаг с 0 на 1.
# объявляем функцию
def converts(state, flag):
# инвертируем флаг
return state ^ flag
Теперь попробуем симулировать события и посмотреть, как это будет отображаться на двоичном состоянии и в наших функциях:
# выводим на экран начальное состояние
print_state(player_state)
# симулируем события
# начал двигаться
player_state |= MOVING
print("\n▶ Игрок начал двигаться")
print_state(player_state)
# стал невидимым
player_state = converts(player_state, VISIBLE)
print("\n▶ Игрок стал невидимым")
print_state(player_state)
Запускаем код и смотрим на результат в консоли:
Начальное состояние
Текущее состояние игрока:
В двоичном виде: 0b11
Жив: да
Видим: да
Движется: нет
Стреляет: нет
▶ Игрок начал двигаться
Текущее состояние игрока:
В двоичном виде: 0b111
Жив: да
Видим: да
Движется: да
Стреляет: нет
▶ Игрок стал невидимым
Текущее состояние игрока:
В двоичном виде: 0b101
Жив: да
Видим: нет
Движется: да
Стреляет: нет
Проблема использования функции bin()
без поясняющих выводов в том, что будет сложно понять, какой именно флаг отключён или включён, потому что при выводе она просто удаляет крайние символы 0. Зато если добавить комментарии, то можно отслеживать показатели напрямую в том виде, как это видит компьютер.
Оптимизация работы с двоичными числами
Один из способов улучшения работы с функцией — убрать начальные символы 0b
. Это проще всего сделать через срез строки, то есть просто выводить строку с 3-го символа:
binary = bin(13)[2:]
Получаем чистое двоичное представление числа:
1101
В настоящих программах этот процесс можно обернуть в функцию:
def sl(n):
return bin(n)[2:]
Здесь мы передаём в функцию число n
, получаем его двоичное представление в виде строки и выводим срез этой строки без первых двух символов.
Альтернативные способы
Кроме работы с bin()
, есть другие методы представления чисел в двоичной системе или перевода в другие системы.
Format()
Это ещё один вариант работы с двоичным представлением чисел. Функция format()
даёт больше контроля и применяется для работы не только с числами и разрядами. Например, так можно представить целое число в бинарном представлении в виде байтового блока из 8 битов:
# форматируем число 5 в двоичном виде с 8 разрядами
binary = format(5, '08b')
print(binary)
При запуске получаем результат в виде целого байта:
00000101
Отличия от hex() и oct()
Если bin()
показывает число в двоичном виде, то функции oct()
и hex()
выводят восьмеричное и шестнадцатеричное представления.
Пример работы:
# объявляем переменную с числом
built = 255
# выводим в разных форматах
print(bin(built))
print(oct(built))
print(hex(built))
Результат — одно и то же число в разных системах:
0b11111111
0o377
0xff
Когда лучше использовать другие методы
Если нужно просто вывести двоичное значение, достаточно использования bin()
. Но если нужно работать с байтовыми блоками, убирать префикс 0b
или настраивать вывод ещё как-то по-другому, лучше использовать format()
.
Сначала посмотрим на пример использования:
print(format(10, '08b'))
А вот как это работает:
- В скобках первым аргументом мы передаём число 10 — с этим аргументом функция будет работать дальше.
После этого мы прописываем комбинацию '08b'
, которая означает:
0
— использовать нули вместо пробелов для заполнения строки, если её длина будет больше того, что получится из первого аргумента после обработки;8
означает минимальную длину строки;b
устанавливает формат как бинарный;
При запуске получаем такой результат:
00001010
Ошибка TypeError и как её избежать
Самая частая ошибка при работе с bin()
— попытка преобразовать в двоичный тип какой-то другой тип данных, кроме целых чисел. При попытке сделать это мы получим ошибку примерно такого вида:
TypeError: object cannot be interpreted as an integer
Один из способов избежать этого — попробовать преобразовать аргументы перед передачей в bin()
:
# создаём строку, которую можно преобразовать в число
integers = "15"
# преобразуем строку в число перед вызовом функции
binary = bin(int(integers))
# проверяем результат
print(binary)
Так функция сработает как надо:
0b1111
Преобразование двоичной строки обратно в число
Чтобы перевести двоичное число обратно в целочисленное десятичное, нужно передать его в функцию int()
в качестве первого аргумента и указать вторым, в какой системе записано первое значение:
# создаём двоичное значение в виде строки
convert = "1010"
# преобразуем строку в число
result = int(convert, 2)
# проверяем результат
print(result)
Получаем обычное число в десятичной системе:
10
Бонус для читателей
Если вам интересно погрузиться в мир ИТ и при этом немного сэкономить, держите наш промокод на курсы Практикума. Он даст вам скидку при оплате, поможет с льготной ипотекой и даст безлимит на маркетплейсах. Ладно, окей, это просто скидка, без остального, но хорошая.
Вам слово
Приходите к нам в соцсети поделиться своим мнением о статье и почитать, что пишут другие. А ещё там выходит дополнительный контент, которого нет на сайте — шпаргалки, опросы и разная дурка. В общем, вот тележка, вот ВК — велком!