国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python中的 enum 模塊源碼詳析

2020-02-16 00:33:08
字體:
來源:轉載
供稿:網友

起步

上一篇 《Python 的枚舉類型》 文末說有機會的話可以看看它的源碼。那就來讀一讀,看看枚舉的幾個重要的特性是如何實現的。

要想閱讀這部分,需要對元類編程有所了解。

成員名不允許重復

這部分我的第一個想法是去控制 __dict__ 中的 key 。但這樣的方式并不好,__dict__ 范圍大,它包含該類的所有屬性和方法。而不單單是枚舉的命名空間。我在源碼中發現 enum 使用另一個方法。通過 __prepare__ 魔術方法可以返回一個類字典實例,在該實例 使用 __prepare__ 魔術方法自定義命名空間,在該空間內限定成員名不允許重復。

# 自己實現class _Dict(dict): def __setitem__(self, key, value): if key in self:  raise TypeError('Attempted to reuse key: %r' % key) super().__setitem__(key, value)class MyMeta(type): @classmethod def __prepare__(metacls, name, bases): d = _Dict() return dclass Enum(metaclass=MyMeta): passclass Color(Enum): red = 1 red = 1  # TypeError: Attempted to reuse key: 'red'

再看看 Enum 模塊的具體實現:

class _EnumDict(dict): def __init__(self): super().__init__() self._member_names = [] ... def __setitem__(self, key, value): ... elif key in self._member_names:  # descriptor overwriting an enum?  raise TypeError('Attempted to reuse key: %r' % key) ... self._member_names.append(key) super().__setitem__(key, value)class EnumMeta(type): @classmethod def __prepare__(metacls, cls, bases): enum_dict = _EnumDict() ... return enum_dictclass Enum(metaclass=EnumMeta): ...

模塊中的 _EnumDict 創建了 _member_names 列表來存儲成員名,這是因為不是所有的命名空間內的成員都是枚舉的成員。比如 __str__, __new__ 等魔術方法就不是了,所以這邊的 __setitem__ 需要做一些過濾:

def __setitem__(self, key, value): if _is_sunder(key): # 下劃線開頭和結尾的,如 _order__ raise ValueError('_names_ are reserved for future Enum use') elif _is_dunder(key): # 雙下劃線結尾的, 如 __new__ if key == '__order__':  key = '_order_' elif key in self._member_names: # 重復定義的 key raise TypeError('Attempted to reuse key: %r' % key) elif not _is_descriptor(value): # value得不是描述符 self._member_names.append(key) self._last_values.append(value) super().__setitem__(key, value)

模塊考慮的會更全面。

每個成員都有名稱屬性和值屬性

上述的代碼中,Color.red 取得的值是 1。而 eumu 模塊中,定義的枚舉類中,每個成員都是有名稱和屬性值的;并且細心的話還會發現 Color.red 是 Color 的實例。這樣的情況是如何來實現的呢。

還是用元類來完成,在元類的 __new__ 中實現,具體的思路是,先創建目標類,然后為每個成員都創建一樣的類,再通過 setattr 的方式將后續的類作為屬性添加到目標類中,偽代碼如下:

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 商城县| 仁寿县| 黄山市| 梧州市| 平原县| 余姚市| 嘉禾县| 绍兴县| 中阳县| 新乡县| 隆化县| 当阳市| 鹿泉市| 正镶白旗| 定结县| 商河县| 香河县| 嘉定区| 溧阳市| 古蔺县| 抚松县| 清水河县| 信阳市| 白城市| 永定县| 车险| 鹤壁市| 温宿县| 香港| 华安县| 县级市| 分宜县| 潞西市| 永清县| 合作市| 蓬安县| 淮安市| 庆元县| 靖西县| 福建省| 铅山县|