2016-04-24 66 views
7

我知道基类EnumIntEnum。两者都非常有帮助,但我错过了旗帜操作的特点。我不希望这两个班级实现我希望的功能。有标志/位掩码操作的Python类/枚举吗?

让我们构造一个例子:

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

的内在价值。如果是有一个好的“是在过滤器Ÿ标志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版本? :)

开路特征:

  • 回报所有有效标志的__str__
  • 列表...?
+1

我最近为单元测试装备了一个标志库,并在pypi上发布了它。我将完成它的README.rst并在接下来的几天添加一些额外的功能。它的接口深受python3的标准枚举模块的影响。看看你是否感兴趣:https://pypi.python.org/pypi/py-flags我已经看到关于标志是否是pythonic方法的讨论。我将来对README.rst的更新将有一节讨论使用几个bools作为函数参数或将bools存储在对象中的优点和缺点,或者使用集合VS使用标志来代替词典。 – pasztorpisti

+1

请发表您的评论作为答案,让我可以upvote它!它看起来非常好,成熟。只有一个问题:为什么我需要给枚举赋予一个FQN?例如:'TextStyle('TextStyle.bold')'。我认为'bold'就足够了,因为名称空间已经限制为'TextStyle',因为你将它传递给它的构造函数。 – Paebbels

+1

链接只有答案是不欢迎所以我害怕...枚举的'str()'可以在其他上下文中使用,不仅在序列化的情况下,这就是为什么'__str__'返回fqdn。我认为'str()'应该是可解释的,即使没有上下文中的flags类。实际上,为了自定义序列化的目的,我提供了一个'to_simple_str()',除了标准的'__str__'。在这种情况下'to_simple_str()'会发出简单的''bold''和'TextStyle('bold')'也可以。事实上,pickle serializer对flags的支持只保存flags类名和'to_simple_str()'的输出。 – pasztorpisti

回答

5

我最近发布了一个针对此问题的开源包py-flags。该库完全具备此功能,其设计深受python3枚举模块的影响。

有关于是否pythonic足够实现这样一个标志类的争论,因为它的功能与语言提供的其他方法有巨大的重叠(bool变量,集合,具有bool属性的对象或具有bool项的字典, ...)。出于这个原因,我认为标志类过于狭义和/或冗余,无法通向标准库,但在某些情况下,它比以前列出的解决方案好得多,因此可以使用“pip install”库派上用场。

你的例子看起来像使用PY-标志模块如下:

from flags import Flags 

class NetlistKind(Flags): 
    Unknown = 0 
    LatticeNetlist = 1 
    QuartusNetlist = 2 
    XSTNetlist = 4 
    CoreGenNetlist = 8 
    All = 15 

上面的东西可能有点进一步调整了,因为与库中声明的标志类自动提供了两个“虚拟”的标志: NetlistKind.no_flagsNetlistKind.all_flags。这些使已声明的NetlistKind.UnknownNetlistKind.All是多余的,所以我们可以将它们从声明中排除,但问题是no_flagsall_flags与您的命名约定不匹配。为了帮助这一点,我们在您的项目,而不是flags.Flags声明一个标志基类,你将不得不使用在你的项目的其余部分:

from flags import Flags 

class BaseFlags(Flags): 
    __no_flags_name__ = 'Unknown' 
    __all_flags_name__ = 'All' 

基础上,可以通过任何被继承先前声明的基类你在你的项目的标志,我们可以在你的旗帜声明更改为:

class NetlistKind(BaseFlags): 
    LatticeNetlist = 1 
    QuartusNetlist = 2 
    XSTNetlist = 4 
    CoreGenNetlist = 8 

这样NetlistKind.Unknown自动与零值声明。 NetlistKind.All也在那里,它会自动组合你所有的声明标志。有可能在有/没有这些虚拟标记的情况下迭代枚举成员。您也可以声明别名(与先前声明的标志具有相同值的标志)。

作为使用“函数调用风格”(也由标准枚举模块提供的)的替代声明:

NetlistKind = BaseFlags('NetlistKind', ['LatticeNetlist', 'QuartusNetlist', 
             'XSTNetlist', 'CoreGenNetlist']) 

如果一个标志类声明一些成员则它被认为是最后。尝试子类化会导致错误。为了添加新成员或更改功能,允许子类化一个标志类在语义上是不受欢迎的。

除此之外,flags类以类型安全的方式为您提供的操作符(bool操作符,in,迭代等)提供操作符。我将在接下来的几天内完成README.rst以及封装界面上的一些小工具,但基本功能已经存在并且测试的覆盖范围很广。

+0

啊,我应该已经开始赏金,然后我接受你的答案。现在这个链接已经消失了:(因此,对于整体工作和用户定义的基类中的提示实际上+100,以覆盖'* _flags'的名字,它就像一个魅力 – Paebbels

+0

@Paebbels感谢您的慷慨,当我累得无法做其他事情时,我访问了stackoverflow:-D我正在研究这个lib,它是README.rst文件,一个更详细的doc,它有更好的接口描述和一点的设计理念将在未来几天即将推出,目前的文档是超级基础,正如你所见,但即使在大文档的情况下,我通常以类似的TL开始; DR部分...轮询pypi或github页面如果你对即将到来的更长的版本感兴趣, – pasztorpisti

+0

有时候我会添加一个赏金来纪念优秀的作品,特别是当它让我有时间自己写作的时候:)。所以你的lib现在用在“The PoC-Library”中。我想我应该找到一个很好的方式来描述PoC的依赖关系。我们没有setup.py,因为没有安装PoC。 Python脚本只是一个后台基础架构...我应该为它写一个新问题... – Paebbels

12

Python 3.6增加了FlagIntFlag,它们支持通常的按位操作。作为奖励,来自按位操作的结果值仍然是原始标志类的成员,并且是单身[1]。

aenum库也有这个补充,可用于Python 2.7。

3.6.0中存在一个错误:如果psuedo-flag成员正在线程中创建,那么最终可能是重复的;这固定在3.6.1(并且从未存在于aenum)。

+0

谢谢伊桑。 @pasztorpisti提供的py-flags模块非常强大。也许Python 3.6应该查看他的模块(基于元类)并纳入一些功能。 => https://github.com/pasztorpisti/py-flags – Paebbels

+1

@Paebbels:看起来很像stdlib版本。 –

+2

@Paebbels当涉及到基本功能时,它们几乎相当,所以python3.6 +用户应该考虑std lib版本。 'py-flags'包含一些额外的功能,可以被认为是好的或坏的事情,如果需要使用继承,开发人员实际上可以将这些功能添加到std lib版本。 'py-flags'刻意避免从'Enum'中导出'Flags'作为设计决定。我认为枚举和标志(如果需要)之间的正确关系应该看起来像枚举和“一组枚举”类型的pascal之间的关系:http://wiki.freepascal.org/Set – pasztorpisti