Функция bin() в Python

Получаем двоичное число из десятичного

Функция bin() в Python

Почти все программисты сегодня пишут код на человекочитаемых языках, который понятен людям: 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

Бонус для читателей

Если вам интересно погрузиться в мир ИТ и при этом немного сэкономить, держите наш промокод на курсы Практикума. Он даст вам скидку при оплате, поможет с льготной ипотекой и даст безлимит на маркетплейсах. Ладно, окей, это просто скидка, без остального, но хорошая. 

Вам слово

Приходите к нам в соцсети поделиться своим мнением о статье и почитать, что пишут другие. А ещё там выходит дополнительный контент, которого нет на сайте — шпаргалки, опросы и разная дурка. В общем, вот тележка, вот ВК — велком!

Обложка:

Алексей Сухов

Корректор:

Александр Зубов

Вёрстка:

Егор Степанов

Соцсети:

Юлия Зубарева

Вам может быть интересно
easy