


Detailed analysis of the source code of the enum module in Python (code example)
This article brings you a detailed analysis (code example) of the enum module source code in Python. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
Previous article "Detailed explanation of enumeration types in Python (code examples)" At the end of the article, it is said that if you have the opportunity, you can take a look at its source code. Then read it and see how several important features of enumeration are implemented.
To read this part, you need to have some understanding of metaclass programming.
Repeated member names are not allowed
My first idea for this part is to control the key in __dict__. But this way is not good, __dict__ has a large scope, it contains all attributes and methods of the class. Not just the enumeration namespace. I found in the source code that enum uses another method. A dictionary-like instance can be returned through the __prepare__ magic method. In this instance, the __prepare__ magic method is used to customize the namespace, and repeated member names are not allowed in this space.
# 自己实现 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 d class Enum(metaclass=MyMeta): pass class Color(Enum): red = 1 red = 1 # TypeError: Attempted to reuse key: 'red'
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_dict class Enum(metaclass=EnumMeta): ...
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)
Each member has a name attribute and a value attribute
In the above code, the value obtained by Color.red is 1. In the eumu module, each member of the defined enumeration class has a name and attribute value; and if you are careful, you will find that Color.red is an example of Color. How is this situation achieved? It is still done with metaclasses and implemented in __new__ of metaclasses. The specific idea is to first create the target class, then create the same class for each member, and then use setattr to add subsequent The class is added to the target class as an attribute. The pseudo code is as follows:def __new__(metacls, cls, bases, classdict): __new__ = cls.__new__ # 创建枚举类 enum_class = super().__new__() # 每个成员都是cls的示例,通过setattr注入到目标类中 for name, value in cls.members.items(): member = super().__new__() member.name = name member.value = value setattr(enum_class, name, member) return enum_class
class _Dict(dict): def __init__(self): super().__init__() self._member_names = [] def __setitem__(self, key, value): if key in self: raise TypeError('Attempted to reuse key: %r' % key) if not key.startswith("_"): self._member_names.append(key) super().__setitem__(key, value) class MyMeta(type): @classmethod def __prepare__(metacls, name, bases): d = _Dict() return d def __new__(metacls, cls, bases, classdict): __new__ = bases[0].__new__ if bases else object.__new__ # 创建枚举类 enum_class = super().__new__(metacls, cls, bases, classdict) # 创建成员 for member_name in classdict._member_names: value = classdict[member_name] enum_member = __new__(enum_class) enum_member.name = member_name enum_member.value = value setattr(enum_class, member_name, enum_member) return enum_class class MyEnum(metaclass=MyMeta): pass class Color(MyEnum): red = 1 blue = 2 def __str__(self): return "%s.%s" % (self.__class__.__name__, self.name) print(Color.red) # Color.red print(Color.red.name) # red print(Color.red.value) # 1
When the member values are the same, the second member is an alias of the first member
From this section onwards, the description of the class implemented by yourself will no longer be used. , but illustrates its implementation by disassembling the code of the enum module. From the usage characteristics of the module, we can know that if the member values are the same, the latter will be an alias of the former:from enum import Enum class Color(Enum): red = 1 _red = 1 print(Color.red is Color._red) # True
class EnumMeta(type): def __new__(metacls, cls, bases, classdict): ... # create our new Enum type enum_class = super().__new__(metacls, cls, bases, classdict) enum_class._member_names_ = [] # names in definition order enum_class._member_map_ = OrderedDict() # name->value map for member_name in classdict._member_names: enum_member = __new__(enum_class) # If another member with the same value was already defined, the # new member becomes an alias to the existing one. for name, canonical_member in enum_class._member_map_.items(): if canonical_member._value_ == enum_member._value_: enum_member = canonical_member # 取代 break else: # Aliases don't appear in member names (only in __members__). enum_class._member_names_.append(member_name) # 新成员,添加到_member_names_中 enum_class._member_map_[member_name] = enum_member ...
Members can be obtained through member values
print(Color['red']) # Color.red 通过成员名来获取成员 print(Color(1)) # Color.red 通过成员值来获取成员
class EnumMeta(type): def __new__(metacls, cls, bases, classdict): ... # create our new Enum type enum_class = super().__new__(metacls, cls, bases, classdict) enum_class._value2member_map_ = {} for member_name in classdict._member_names: value = enum_members[member_name] enum_member = __new__(enum_class) enum_class._value2member_map_[value] = enum_member ...
class Enum(metaclass=EnumMeta): def __new__(cls, value): if type(value) is cls: return value # 尝试从 _value2member_map_ 获取 try: if value in cls._value2member_map_: return cls._value2member_map_[value] except TypeError: # 从 _member_map_ 映射获取 for member in cls._member_map_.values(): if member._value_ == value: return member raise ValueError("%r is not a valid %s" % (value, cls.__name__))
Iteratively traverse the members
The enumeration class supports iterative traversal of members in the defined order. If there are members with duplicate values, only the first duplicate member is obtained. For duplicate member values, only the first member is obtained, and the attribute _member_names_ will only record the first one:class Enum(metaclass=EnumMeta): def __iter__(cls): return (cls._member_map_[name] for name in cls._member_names_)
Summary
Implementation of the core features of the enum module This is the idea, almost all achieved through meta-class black magic. The members cannot be compared in size but can be compared in equal value. There is no need to talk about this. This is actually inherited from object. It has "features" without doing anything extra.The above is the detailed content of Detailed analysis of the source code of the enum module in Python (code example). For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



VS Code extensions pose malicious risks, such as hiding malicious code, exploiting vulnerabilities, and masturbating as legitimate extensions. Methods to identify malicious extensions include: checking publishers, reading comments, checking code, and installing with caution. Security measures also include: security awareness, good habits, regular updates and antivirus software.

VS Code can run on Windows 8, but the experience may not be great. First make sure the system has been updated to the latest patch, then download the VS Code installation package that matches the system architecture and install it as prompted. After installation, be aware that some extensions may be incompatible with Windows 8 and need to look for alternative extensions or use newer Windows systems in a virtual machine. Install the necessary extensions to check whether they work properly. Although VS Code is feasible on Windows 8, it is recommended to upgrade to a newer Windows system for a better development experience and security.

In VS Code, you can run the program in the terminal through the following steps: Prepare the code and open the integrated terminal to ensure that the code directory is consistent with the terminal working directory. Select the run command according to the programming language (such as Python's python your_file_name.py) to check whether it runs successfully and resolve errors. Use the debugger to improve debugging efficiency.

VS Code can be used to write Python and provides many features that make it an ideal tool for developing Python applications. It allows users to: install Python extensions to get functions such as code completion, syntax highlighting, and debugging. Use the debugger to track code step by step, find and fix errors. Integrate Git for version control. Use code formatting tools to maintain code consistency. Use the Linting tool to spot potential problems ahead of time.

PHP is suitable for web development and rapid prototyping, and Python is suitable for data science and machine learning. 1.PHP is used for dynamic web development, with simple syntax and suitable for rapid development. 2. Python has concise syntax, is suitable for multiple fields, and has a strong library ecosystem.

VS Code is available on Mac. It has powerful extensions, Git integration, terminal and debugger, and also offers a wealth of setup options. However, for particularly large projects or highly professional development, VS Code may have performance or functional limitations.

VS Code not only can run Python, but also provides powerful functions, including: automatically identifying Python files after installing Python extensions, providing functions such as code completion, syntax highlighting, and debugging. Relying on the installed Python environment, extensions act as bridge connection editing and Python environment. The debugging functions include setting breakpoints, step-by-step debugging, viewing variable values, and improving debugging efficiency. The integrated terminal supports running complex commands such as unit testing and package management. Supports extended configuration and enhances features such as code formatting, analysis and version control.

Golang is more suitable for high concurrency tasks, while Python has more advantages in flexibility. 1.Golang efficiently handles concurrency through goroutine and channel. 2. Python relies on threading and asyncio, which is affected by GIL, but provides multiple concurrency methods. The choice should be based on specific needs.
