- Побитовые операторы Python: руководство
- Побитовый вывод натуральных чисел
- Типы основных битовых операторов Python
- & (AND, И)
- | (OR, ИЛИ)
- ^ (XOR, исключающее ИЛИ)
- ~ (NOT, НЕ)
- Побитовые сдвиги влево и вправо
- Практическое применение в программировании
- Побитовые операторы(bitwise) в Python
- 1. Побитовый оператор AND
- 2. Побитовый оператор OR
- 3. Примеры с XOR
- 4. Комплиментарный
- 5. Побитовый сдвиг влево
- 6. Побитовый сдвиг вправо
- Перегрузка побитового оператора Python
- Резюме
Побитовые операторы Python: руководство
Несмотря на то, что Python не считается подходящим языком для низкоуровневого программирования, инструменты для этого у него всё же есть. Один из таких инструментов — побитовые (или битовые) операторы.
Побитовые операторы в Python предназначены для изменения строк с двоичным кодом, что может понадобиться для работы с криптографическими алгоритмами, драйверами различных устройств или, например, с сетевой инфраструктурой. Также они могут пригодиться для изменения графики низкого уровня и для любых других задач, где требуется выполнять различные действия с двоичным кодом.
Результатом действия побитовых операторов в Python является изменение объекта на уровне битов путем нескольких типов логических операций с двоичным кодом. Эти операции мы и рассмотрим в данной статье.
Побитовый вывод натуральных чисел
Поскольку мы будем работать с двоичным кодом, причем преимущественно с целыми числами, давайте сначала научимся выводить эти числа в нужном нам виде. Это делается очень просто:
Вот мы и получили бинарное представление числа 5. Впрочем, совсем ли бинарное? На самом деле 5 здесь — это последние три цифры ( 101 ), а код 0b используется в Python для вывода чисел в бинарном виде (есть и — 0b для отрицательных значений). Теперь мы можем вывести любое число в двоичном коде, а вот так будет выглядеть ноль и первая десятка:
>>> bin(0)
0b0
>>> bin(1)
0b1
>>> bin(2)
0b10
>>> bin(3)
0b11
>>> bin(4)
0b100
>>> bin(5)
0b101
>>> bin(6)
0b110
>>> bin(7)
0b111
>>> bin(8)
0b1000
>>> bin(9)
0b1001
>>> bin(10)
0b1010
Из этого ряда понятен принцип битового представления чисел: единицы последовательно заменяют нули, а когда все значения достигают 1, добавляется новый разряд. Досчитаем до 15:
>>> bin(11)
0b1011
>>> bin(12)
0b1100
>>> bin(13)
0b1101
>>> bin(14)
0b1110
>>> bin(15)
0b1111
Четвертый разряд исчерпан (заполнен единицами), поэтому далее в дело вступает пятый, и числа 16 и 17 будут записаны уже так:
>>> bin(16)
0b10000
>>> bin(17)
0b10001
Таким образом, двоичный код организован строго по законам математики: три разряда битов будет у чисел от 4 до 7, четвертый добавляется для чисел от 8 до 15, пять разрядов будет у чисел с 16 до 31, шесть — с 32 до 63, семь — с 64 до 127 и т. д. То есть новый разряд добавляется при очередном умножении на два. Это полезно знать при сравнении операндов с разной разрядностью: в этом случае у операнда с меньшим числом разрядов можно добавить соответствующее число нулей сразу после 0b .
Типы основных битовых операторов Python
Теперь мы готовы оперировать битами, используя логику следующих инструментов:
& (AND, И)
Логика работы: при сравнении двух бит (в одном и том же разряде) & выдает 1 (то есть бит будет скопирован), если бит есть в обоих сравниваемых операндах, и 0, если это условие не выполняется (то есть бит отсутствует хотя бы в одном из операндов). Схематически работу & можно представить так:
Это самое жесткое условие, когда бит возвращается (выдается 1) только в случае, если он был в обоих операндах. Теперь примеры:
Добавляем тройке третий разряд для удобства представления и видим, что только средние биты присутствуют у обоих значений (по 1 в каждом числе), поэтому возвращается такое число: 0b010, а это 2.
24 = 0b011000
62 = 0b111110
24 = 0b011000
Интересный результат, который получился потому, что совпадающие биты оказались ровно на тех же позициях, что и в представлении первого числа.
>>> 555 & 878
554
555 = 0b1000101011
878 = 0b1101101110
554 = 0b1000101010
А теперь примеры посложнее, попрактикуемся с числами с разным количеством разрядов:
>>> 80 & 755
80
80 = 0b0001010000
755 = 0b1011110011
80 = 0b0001010000
>>> 446 & 19
18
446 = 0b110111110
19 = 0b000010011
18 = 0b000010010
>>> 101 & 883
97
101 = 0b0001100101
883 = 0b1101110011
97 = 0b0001100001
| (OR, ИЛИ)
Логика работы: при сравнении двух бит | выдает 1 (бит будет скопирован), если бит есть хотя бы в одном из сравниваемых операндах, и 0, если он отсутствует в обоих. Схематически работу | можно представить так:
Таким образом, бит будет возвращен во всех случаях, кроме одного: когда в обоих сравниваемых операндах нули. Примеры:
>>> 9 | 5
13
9 = 0b1001
5 = 0b0101
13 = 0b1101
Бит не копируется только во втором разряде (справа), поскольку там нули у обоих операндов, в результате возвращается 13.
>>> 87 | 59
127
87 = 0b1010111
59 = 0b0111011
127 = 0b1111111
>>> 846 | 657
991
846 = 0b1101001110
657 = 0b1010010001
991 = 0b1111011111
И задачи посложнее, с уже знакомыми цифрами, но совершенно иными результатами:
>>> 80 | 755
755
80 = 0b0001010000
755 = 0b1011110011
755 = 0b1011110011
>>> 446 | 19
447
446 = 0b110111110
19 = 0b000010011
447 = 0b110111111
>>> 101 | 883
887
101 = 0b0001100101
883 = 0b1101110011
887 = 0b1101110111
^ (XOR, исключающее ИЛИ)
Логика работы: при сравнении двух бит ^ выдает 1 (бит будет скопирован), если сравниваемые операнды различаются, и 0, если они одинаковы. Схематически работу ^ можно представить так:
Как видим, оператору XOR неважно, сравниваются две единицы или два нуля: в обоих случаях бит возвращен не будет: бит возвращается только при сравнении разных значений. Примеры:
>>> 5 ^ 2
7
5 = 0b0101
2 = 0b0010
7 = 0b0111
Во всех разрядах, кроме крайнего левого, операнды не совпали, поэтому в этих случаях были возвращены биты, то есть интерпретатор выдал единицы.
>>> 90 ^ 92
6
90 = 0b1011010
92 = 0b1011100
6 = 0b0000110
>>> 352 ^ 686
974
352 = 0b0101100000
686 = 0b1010101110
974 = 0b1111001110
Несколько примеров с операндами с разным количеством разрядов:
>>> 80 | 755
675
80 = 0b0001010000
755 = 0b1011110011
675 = 0b1010100011
>>> 446 | 19
429
446 = 0b110111110
19 = 0b000010011
429 = 0b110101101
>>> 101 | 883
790
101 = 0b0001100101
883 = 0b1101110011
790 = 0b1100010110
~ (NOT, НЕ)
~ не сравнивает значения, а переворачивает биты в целочисленных значениях. При этом учтите, что положительные числа будут преобразованы в отрицательные со сдвигом на единицу, и наоборот. Работает это так:
>>> ~0
-1
>>> ~30
-31
>>> ~-30
29
>>> ~80
-81
>>> ~-80
79
>>> ~255
-256
>>> ~-255
254
Побитовые сдвиги влево и вправо
Сдвинули 1 на 1 бит и получили 2, потому что:
то есть, единица переместилась на одну позицию влево. А если переместить на две?
Нетрудно догадаться, что даст сдвиг единицы на 3 позиции:
Вот еще пара примеров с раскладкой по битам:
>>> 10 20
10 = 0b01010
20 = 0b10100
>>> 10 40
10 = 0b001010
40 = 0b101000
Правый сдвиг обозначается символами >> , и точно так же слева пишется изменяемое число, а справа от оператора указывается количество бит, на которое выполняется сдвиг. Это обратная операция, поэтому:
>>> 2 >> 1
1
>>> 4 >> 2
1
>>> 8 >> 3
1
>>> 40 >> 1
20
>>> 40 >> 2
10
Практическое применение в программировании
- Одна из областей IT, где активно используются битовые операции (в особенности сдвиги) — криптография. Сдвиговые операции позволяют изменять значения данных так, что без наличия ключей, хранящих первоначальные значения, дешифрование становится невозможным.
- Следующая область применения битовых операций: сетевые технологии, где действия над битами необходимы для проверки соответствия адресов и подсетей.
- А практика побитовых операций & и | поможет вам лучше понять принцип работы операторов and и or в Python и то, как работают любые другие программы, где используется Булева логика, основанная на значениях True (1) и False (0).
Побитовые операторы(bitwise) в Python
Операторы bitwise в Python используются для выполнения поразрядных вычислений целых чисел. Целые числа преобразуются в двоичный формат, а затем операции выполняются побитно, отсюда и название побитовые операторы.
Они работают только с целыми числами, а окончательный результат возвращается в десятичном формате и также называются бинарными операторами.
В Python существует 6 побитовых операторов. В таблице ниже приведены краткие сведения о них.
Побитовый оператор | Побитовый оператор AND | 10 7 = 2 |
| | Побитовый оператор OR | 10 | 7 = 15 |
^ | Побитовый оператор XOR | 10 ^ 7 = 13 |
~ | Побитовый оператор Ones’ Compliment | ~ 10 = -11 |
Побитовый оператор Left Shift | 10 | |
>> | Побитовый оператор Right Shift | 10 >> 1 = 5 |
Давайте рассмотрим этих операторов один за другим и разберемся, как они работают.
1. Побитовый оператор AND
Оператор AND в Python возвращает 1, если оба бита равны 1, в противном случае – 0.
2. Побитовый оператор OR
Побитовый оператор OR в Python возвращает 1, если какой-либо из битов равен 1. Если оба бита равны 0, он возвращает 0.
3. Примеры с XOR
Побитовый оператор XOR в Python возвращает 1, если один из битов равен 0, а другой бит равен 1. Если оба бита равны 0 или 1, он возвращает 0.
4. Комплиментарный
Дополнение числа «A» в Python Ones равно – (A + 1).
5. Побитовый сдвиг влево
Оператор Left Shift в Python сдвигает биты левого операнда в левую сторону заданное количество раз в правом операнде. Проще говоря, к двоичному числу в конце добавляются нули.
6. Побитовый сдвиг вправо
Оператор Right Shift в Python — это полная противоположность оператору сдвига влево. Затем биты левого операнда перемещаются вправо заданное количество раз.
Оператор побитового сдвига вправо в Python.
Перегрузка побитового оператора Python
Python поддерживает перегрузку операторов. Существуют различные методы, которые мы можем реализовать для поддержки побитовых операторов для наших настраиваемых объектов.
__and __ (я, другое) | |
| | __или __ (я, другое) |
^ | __xor __ (я, другой) |
~ | __invert __ (сам) |
__lshift __ (я, другой) | |
>> | __rshift __ (я, другой) |
Вот пример перегрузки побитового оператора для нашего настраиваемого объекта.
class Data: def __init__(self, i): self.id = i def __and__(self, other): print('Bitwise AND operator overloaded') if isinstance(other, Data): return Data(self.id other.id) else: raise ValueError('Argument must be object of Data') def __or__(self, other): print('Bitwise OR operator overloaded') if isinstance(other, Data): return Data(self.id | other.id) else: raise ValueError('Argument must be object of Data') def __xor__(self, other): print('Bitwise XOR operator overloaded') if isinstance(other, Data): return Data(self.id ^ other.id) else: raise ValueError('Argument must be object of Data') def __lshift__(self, other): print('Bitwise Left Shift operator overloaded') if isinstance(other, int): return Data(self.id > other) else: raise ValueError('Argument must be integer') def __invert__(self): print('Bitwise Ones Complement operator overloaded') return Data(~self.id) def __str__(self): return f'Data[]' d1 = Data(10) d2 = Data(7) print(f'd1d2 = ') print(f'd1|d2 =') print(f'd1^d2 = ') print(f'd1') print(f'd1>>2 = >2>') print(f'~d1 = ')
Bitwise AND operator overloaded d1d2 = Data[2] Bitwise OR operator overloaded d1|d2 = Data[15] Bitwise XOR operator overloaded d1^d2 = Data[13] Bitwise Left Shift operator overloaded d1>2 = Data[2] Bitwise Ones Complement operator overloaded ~d1 = Data[-11]
Резюме
Поразрядные операторы Python в основном используются в математических вычислениях. Мы можем реализовать определенные методы для поддержки побитовых операторов и для наших реализаций настраиваемых классов.