flag/bit掩码操作是否有Pythonclass/enum?
Is there a Python class/enum for flag/bit mask operations?
我知道基数 类 Enum
和 IntEnum
。两者都非常有帮助,但我想念标志操作的功能。我不希望这两个 类 实现我想要的功能。
让我们构建一个例子:
class NetlistKind(IntEnum):
Unknown = 0
LatticeNetlist = 1
QuartusNetlist = 2
XSTNetlist = 4
CoreGenNetlist = 8
All = 15
如您所见,我已经在使用 IntEnum
来获取此枚举的算术特征。最好有 @unique
之类的东西来确保所有值都是 2 的幂。我可以根据需要分叉 enum.unique 来做到这一点。 (我知道 All
是该规则的一个例外。)
如何使用这样的枚举?
filter = NetlistKind.LatticeNetlist | NetlistKind.QuartusNetlist
由于底层的 int 位操作是可能的,过滤器的内部值为 3。
如果有一个“是否在过滤器 Y 中设置了标志 X”功能或更好的运算符会更好。我为 x in y
添加了一个魔法函数:
@unique
class NetlistKind(IntEnum):
Unknown = 0
LatticeNetlist = 1
QuartusNetlist = 2
XSTNetlist = 4
CoreGenNetlist = 8
All = 15
def __contains__(self, item):
return (self.value & item.value) == item.value
用法示例:
....
def GetNetlists(self, filter=NetlistKind.All):
for entity in self._entities:
for nl in entity.GetNetlists():
if (nl.kind in filter):
yield nl
def GetXilinxNetlists(self):
return self.GetNetlists(NetlistKind.XSTNetlist | NetlistKind.CoreGenNetlist)
所以问题是:
- 是否有更好的方法来实现位域?
- 是否有更好的方法来实现这样的一维滤波器?这么简单的过滤条件我不想用lamdas?
- Python 标准库中是否已经包含这样的解决方案?
- 如何将此枚举扩展添加到下一个 Python 版本? :)
开放功能:
- return
__str__
中所有活动标志的列表
- ...?
我最近发布了一个针对这个问题的开源包 py-flags。该库正是具有此功能,其设计深受 python3 枚举模块的影响。
关于它是否足够 pythonic 来实现这样的标志存在争论 class 因为它的功能与语言提供的其他方法有很大的重叠(bool 变量的集合、集合、具有 bool 属性的对象或带有 bool 项的指令,...)。出于这个原因,我觉得标志 class 太狭窄了,目的 and/or 多余,无法进入标准库,但在某些情况下,它比之前列出的解决方案要好得多,所以有一个 "pip install"-able 库可以派上用场。
使用 py-flags 模块,您的示例如下所示:
from flags import Flags
class NetlistKind(Flags):
Unknown = 0
LatticeNetlist = 1
QuartusNetlist = 2
XSTNetlist = 4
CoreGenNetlist = 8
All = 15
上面的事情可以进一步调整,因为用库声明的标志 class 会自动提供两个 "virtual" 标志:NetlistKind.no_flags
和 NetlistKind.all_flags
。这些使已声明的 NetlistKind.Unknown
和 NetlistKind.All
变得多余,因此我们可以将它们从声明中删除,但问题是 no_flags
和 all_flags
与您的命名约定不匹配。为此,我们在您的项目中声明了一个标志基 class 而不是 flags.Flags
,您将不得不在项目的其余部分中使用它:
from flags import Flags
class BaseFlags(Flags):
__no_flags_name__ = 'Unknown'
__all_flags_name__ = 'All'
基于先前声明的基础 class 可以被您项目中的任何标志子class,我们可以将您的标志声明更改为:
class NetlistKind(BaseFlags):
LatticeNetlist = 1
QuartusNetlist = 2
XSTNetlist = 4
CoreGenNetlist = 8
这样 NetlistKind.Unknown
自动声明为零值。 NetlistKind.All
也在那里,它自动是所有声明标志的组合。可以迭代枚举成员 with/without 这些虚拟标志。您还可以声明别名(与另一个先前声明的标志具有相同值的标志)。
作为使用 "function-call style" 的替代声明(也由标准枚举模块提供):
NetlistKind = BaseFlags('NetlistKind', ['LatticeNetlist', 'QuartusNetlist',
'XSTNetlist', 'CoreGenNetlist'])
如果标志 class 声明了一些成员,那么它被认为是最终的。尝试 subclass 会导致错误。为了添加新成员或更改功能而允许子class 标记 class 在语义上是不受欢迎的。
除此之外,标志 class 以类型安全的方式提供您列出的运算符(布尔运算符、in、迭代等...)。我将在接下来的几天内完成 README.rst 以及包界面上的一些管道,但基本功能已经存在并且经过了很好的覆盖测试。
Python 3.6 添加了 Flag
and IntFlag
支持通常的位操作。作为奖励,按位运算的结果值仍然是原始标志 class 的成员,并且是单例 [1].
aenum
库也有这个添加并且可以使用回到 Python 2.7。
[1] 3.6.0 中存在一个错误:如果伪标志成员是在线程中创建的,那么最终可能会重复;这在 3.6.1 中已修复(在 aenum
中从未存在)。
我知道基数 类 Enum
和 IntEnum
。两者都非常有帮助,但我想念标志操作的功能。我不希望这两个 类 实现我想要的功能。
让我们构建一个例子:
class NetlistKind(IntEnum):
Unknown = 0
LatticeNetlist = 1
QuartusNetlist = 2
XSTNetlist = 4
CoreGenNetlist = 8
All = 15
如您所见,我已经在使用 IntEnum
来获取此枚举的算术特征。最好有 @unique
之类的东西来确保所有值都是 2 的幂。我可以根据需要分叉 enum.unique 来做到这一点。 (我知道 All
是该规则的一个例外。)
如何使用这样的枚举?
filter = NetlistKind.LatticeNetlist | NetlistKind.QuartusNetlist
由于底层的 int 位操作是可能的,过滤器的内部值为 3。
如果有一个“是否在过滤器 Y 中设置了标志 X”功能或更好的运算符会更好。我为 x in y
添加了一个魔法函数:
@unique
class NetlistKind(IntEnum):
Unknown = 0
LatticeNetlist = 1
QuartusNetlist = 2
XSTNetlist = 4
CoreGenNetlist = 8
All = 15
def __contains__(self, item):
return (self.value & item.value) == item.value
用法示例:
....
def GetNetlists(self, filter=NetlistKind.All):
for entity in self._entities:
for nl in entity.GetNetlists():
if (nl.kind in filter):
yield nl
def GetXilinxNetlists(self):
return self.GetNetlists(NetlistKind.XSTNetlist | NetlistKind.CoreGenNetlist)
所以问题是:
- 是否有更好的方法来实现位域?
- 是否有更好的方法来实现这样的一维滤波器?这么简单的过滤条件我不想用lamdas?
- Python 标准库中是否已经包含这样的解决方案?
- 如何将此枚举扩展添加到下一个 Python 版本? :)
开放功能:
- return
__str__
中所有活动标志的列表
- ...?
我最近发布了一个针对这个问题的开源包 py-flags。该库正是具有此功能,其设计深受 python3 枚举模块的影响。
关于它是否足够 pythonic 来实现这样的标志存在争论 class 因为它的功能与语言提供的其他方法有很大的重叠(bool 变量的集合、集合、具有 bool 属性的对象或带有 bool 项的指令,...)。出于这个原因,我觉得标志 class 太狭窄了,目的 and/or 多余,无法进入标准库,但在某些情况下,它比之前列出的解决方案要好得多,所以有一个 "pip install"-able 库可以派上用场。
使用 py-flags 模块,您的示例如下所示:
from flags import Flags
class NetlistKind(Flags):
Unknown = 0
LatticeNetlist = 1
QuartusNetlist = 2
XSTNetlist = 4
CoreGenNetlist = 8
All = 15
上面的事情可以进一步调整,因为用库声明的标志 class 会自动提供两个 "virtual" 标志:NetlistKind.no_flags
和 NetlistKind.all_flags
。这些使已声明的 NetlistKind.Unknown
和 NetlistKind.All
变得多余,因此我们可以将它们从声明中删除,但问题是 no_flags
和 all_flags
与您的命名约定不匹配。为此,我们在您的项目中声明了一个标志基 class 而不是 flags.Flags
,您将不得不在项目的其余部分中使用它:
from flags import Flags
class BaseFlags(Flags):
__no_flags_name__ = 'Unknown'
__all_flags_name__ = 'All'
基于先前声明的基础 class 可以被您项目中的任何标志子class,我们可以将您的标志声明更改为:
class NetlistKind(BaseFlags):
LatticeNetlist = 1
QuartusNetlist = 2
XSTNetlist = 4
CoreGenNetlist = 8
这样 NetlistKind.Unknown
自动声明为零值。 NetlistKind.All
也在那里,它自动是所有声明标志的组合。可以迭代枚举成员 with/without 这些虚拟标志。您还可以声明别名(与另一个先前声明的标志具有相同值的标志)。
作为使用 "function-call style" 的替代声明(也由标准枚举模块提供):
NetlistKind = BaseFlags('NetlistKind', ['LatticeNetlist', 'QuartusNetlist',
'XSTNetlist', 'CoreGenNetlist'])
如果标志 class 声明了一些成员,那么它被认为是最终的。尝试 subclass 会导致错误。为了添加新成员或更改功能而允许子class 标记 class 在语义上是不受欢迎的。
除此之外,标志 class 以类型安全的方式提供您列出的运算符(布尔运算符、in、迭代等...)。我将在接下来的几天内完成 README.rst 以及包界面上的一些管道,但基本功能已经存在并且经过了很好的覆盖测试。
Python 3.6 添加了 Flag
and IntFlag
支持通常的位操作。作为奖励,按位运算的结果值仍然是原始标志 class 的成员,并且是单例 [1].
aenum
库也有这个添加并且可以使用回到 Python 2.7。
[1] 3.6.0 中存在一个错误:如果伪标志成员是在线程中创建的,那么最终可能会重复;这在 3.6.1 中已修复(在 aenum
中从未存在)。