Вы когда-нибудь задавались вопросом, что за этими забавными значениями разрешений доступа UNIX, такие как 600
✋, 777
⚠️, или 666
😈? Ну, они Октальные представления , где каждая из трех крайних главных цифр представляет собой разную часть разрешений для владельца, группы и других.
Каждая из этих цифр создана из суммы его компонентных битов. В результате конкретные биты добавляют в сумму, так как она представлена цифрой:
- читать бит добавляет 4 до его общего (в двоичном
100
), - Напишите бит добавляет 2 до его общего (в двоичном
010
), а также - Выполнить Бит добавляет 1 до его общего (в бинарном
001
).
Эти значения никогда не вызывают неоднозначные комбинации и поэтому каждая сумма представляет собой уникальный набор разрешений. Давайте возьмем 600
Например. Первая цифра 6
представляет разрешения для владельца. В бинарном это 110
И единственный способ создать его из суммы компонентных битов выше, добавляя 010
( Написать Доступ) до 100
( Читать Доступ). Другими словами, владелец имеет разрешение на чтение и запись файла, но не выполнять его.
Использование этой системы для разрешений оптимизирована для хранения данных. Но также токарные разрешения на (или выключенные) могут быть сделаны эффективно в том, что известно как бит-маскировка.
Bitmasks
Вы видите, чтобы включить определенные биты, Или
Оператор может быть использован. Этот оператор следует правило, что Х или
и Икс ИЛИ
. Если из примера выше мы сейчас также хотим владельца иметь Исполнительный Разрешение на файл, мы просто используем Или
С 1 ( execute Value) на текущем значении разрешений: 6 или
или в бинарном
110 OR 001 = 111
Мы также можем выключить определенные биты, используя И
Оператор, который следует правило, что Икс И
и Икс И
Отказ Чтобы отключить немного, мы используем его с 0
Отказ Интересно, что мы можем оставить немного, как это было при использовании 1
Отказ
Включение и выключение битов также называют «маскировкой» и «маскировать».
Используя эту очень старую технику для хранения частей разрешения очень круто! Но есть ли другие случаи использования, где имеет смысл? Их все еще есть сегодня, хотя они стали непопулярными из-за гораздо более эффективного оборудования, позволяющего использовать набор или словарь для хранения представлений, которые в противном случае удержали бы.
Фильтрация с использованием битовой маскировки
Для Бит Проект Мне нужен способ сохранить поддерживаемые функции для каждого из многочисленных объектов, представляющих сетевые API. Вместо использования словаря, чтобы сопоставить каждый API к его поддерживаемому набору функций или хранить набор функций на каждом API, я решил использовать систему, аналогичную значениям разрешения доступа UNIX.
Использование битовой маскировки позволяет быстро фильтрацию API в зависимости от определенных особенностей. Это может быть достигнуто с помощью единого И
оператор. Мы просто используем значение фильтра Y
Это представляет функции, которые мы хотим фильтровать, и значение Х
Представление поддерживаемых функций некоторых объектов API. Расчет Икс И у
дает еще одно значение Z
. Но вспомните, что каждый бит в Z
будет либо 0, если бит в Y
было 0, или это будет немного Х
сам.
Можете ли вы увидеть тонкое последствие от этого? Если N-бит нашей фильтрации Y
было 0, то тогдашний бит результата Z
будет 0. Нет потери информации, потому что нам все равно, если битовая ценность в Х
сигнализировала поддержка этой функции или нет. Но если N-бит Y
было 1, тогда мы также хотим N’th But of Z
быть 1. Это возможно, только если соответствующий бит в Х
Был 1, отсюда для поддержки сигнализации этой функции. Таким образом, мы можем сравнить результат Z
к Y
сам. Если Х и у
Тогда и только тогда будет ценность Х
сигнал для (по крайней мере) все функции, которые мы фильтруем со значением Y
.
Давайте возьмем быстрый пример, используя значения разрешений UNIX еще раз. Допустим, у нас есть список файлов с именами разрешений и захотете фильтровать их, чтобы сохранить только те, которые нам разрешено читать , что является значением 4 или в двоичном 100
Отказ Одним из файлов может иметь значение разрешения 5, которое в двоичном является 101
И таким образом соответствует читать и Выполнить разрешение.
Фильтр, чтобы увидеть, если хотя бы читать Разрешение было установлено в этом файле, будет проверено следующим образом:
101 AND 100 = 100
Мы видим, что результат на последней строке точно такое же значение, как наш фильтр. Это так же, как мы ожидали, и поэтому мы будем держать его.
Если файл дает нам разрешение на Напишите и Выполнить , но не к читать он представлен как 3 или в бинарном двоике 011
Отказ Применение нашего фильтра:
011 AND 100 = 000
Результат отличается от нашего фильтра, и поэтому мы немедленно знаем, что фильтр не был удовлетворен.
Настоящая красота происходит от применения сложных фильтров с включенными несколькими битами. Если бы мы хотели фильтровать для E.G. читать и Выполнить Разрешения, фильтр будет 101
И так же, как до того, как мы проверили, если финал И
Результат будет равен этой ценности.
Значение Z
в результате использования И
Оператор в разрешении файла и фильтрации – это пересечение разрешений в файле и фильтре.
Битовая фильтрация в Python
Использование Python 3.6+
С момента Python 3.6 класс Флаг
существует для операций битовой маски.
>>> from enum import IntFlag, auto >>> >>> class Permissions(IntFlag): ... EXECUTE = auto() ... WRITE = auto() ... READ = auto() ... >>> class PermissionSet: ... def __init__(self, *flags): ... self._permission = Permissions(0) # Initiate no permissions ... for flag in flags: ... self._permission |= Permissions[flag.upper()] ... def __contains__(self, item): ... return (self._permission & item._permission) == item._permission
Мы можем использовать это Permissionset
Класс для хранения разрешений файла следующим образом:
>>> class File: ... def __init__(self, name, *, permission): ... self.name = name ... self._permissions = PermissionSet(*permission)
Давайте использовать его в действии!
>>> # A filter: >>> permission_filter = PermissionSet("read", "execute") >>> >>> # The dummy files: >>> files = [] >>> files.append(File("file_rw", permission=("read", "write"))) # Should be excluded from filter >>> files.append(File("file_re", permission=("read", "execute"))) # Should be included from filter >>> files.append(File("file_w", permission=("read", "execute"))) # Should be included from filter >>> files.append(File("file_we", permission=("write", "execute"))) # Should be excluded from filter >>> files.append(File("file_rwe", permission=("read", "write", "execute"))) # Should be included from filter >>> >>> # Filter the files: >>> for f in filter(lambda f: permission_filter in f._permissions, files): ... print(f.name) ... 'file_re' 'file_w' 'file_rwe'
Использование Python 3.5.
Однако перед Python 3.6 это может быть достигнуто с использованием Intenum
Класс, однако с ручной регулировкой базовых значений разрешений.
>>> from enum import IntEnum >>> >>> class Permissions(IntEnum): ... EXECUTE = 1 << 0 ... WRITE = 1 << 1 ... READ = 1 << 2 ... >>> class PermissionSet: ... def __init__(self, *flags): ... self._permission = 0 # Initiate no permissions ... for flag in flags: ... self._permission |= Permissions[flag.upper()] ... def __contains__(self, item): ... return (self._permission & item._permission) == item._permission
Затем мы можем использовать его точно так же, как мы уже сделали выше в примере для Infflag
Отказ
Что вы думаете об этой технике? Это элегантно? Или чрезмерная техника?
Оригинал: “https://dev.to/bjarnemagnussen/enum-vs-flag-for-bitmasks-in-python-2ig8”