2016-04-24 69 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