枚举.py精简版

本文主要从枚举的相关定义,取值,迭代器,比较四方面讲解

1. 枚举的定义(三条)

首先,定义枚举要导入enum模块

枚举定义用class关键字继承Enum类

用于定义枚举的class和定义类的class是有区别(用class定义的类,实际上就是一种类型)

from enum import Enum

class Color(Enum):
    red = 1
    orange = 2
    yellow = 3
    green = 4
    blue = 5
    indigo = 6
    purple = 7
总结:枚举定义:先导enum模块再class关键字,继承Enum

注意:定义枚举时,成员名称不允许重复

默认情况下,不同的成员允许相同。但是两个相同值的成员,第二个成员的名称被视作第一个成员的别名

如果枚举中存在相同值的成员,在通过值获取枚举成员时,只能获取到第一个成员

如果要限制定义枚举时,不能定义相同值的成员。可以使用装饰器@unique【要导入unique模块】

2. 枚举取值(三条)

通过成员的名称来获取成员

通过成员来获取成员

通过成员,来获取它的名称和值

总结:名称和值获取成员,反之亦然

3. 迭代器(三条)

枚举支持迭代器,可以遍历枚举成员

如果枚举有值重复的成员,循环遍历枚举时只获取值重复成员的第一个成员

如果想把值重复的成员也遍历出来,要用枚举的一个特殊属性__members__

from enum import Enum
class Color(Enum):
    red = 1
    orange = 2
    yellow = 3
    green = 4
    blue = 5
    indigo = 6
    purple = 7
    red_alias = 1
for color in Color.__members__.items():
    print(color)

总结:可以遍历      值重复获取第一个    重复的遍历要用__members__


4. 枚举比较(三条)

枚举成员可进行同一性比较

枚举成员可进等值比较

枚举成员不能进行大小比较

总结:同一性   等值  不能大小比较

# power/power_sync.py import re import shutil from pathlib import Path import logging from typing import Dict, List from datetime import datetime import json def setup_logger(log_dir: Path) -> logging.Logger: """保持原有日志函数不变""" log_dir.mkdir(parents=True, exist_ok=True) log_file = log_dir / f"sync_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" logger = logging.getLogger("clm_sync") if logger.handlers: logger.handlers.clear() logger.setLevel(logging.DEBUG) fmt = logging.Formatter( '%(asctime)s | %(levelname)-8s | %(funcName)s:%(lineno)d | %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) fh = logging.FileHandler(log_file, encoding='utf-8') fh.setLevel(logging.DEBUG) fh.setFormatter(fmt) logger.addHandler(fh) ch = logging.StreamHandler() ch.setLevel(logging.INFO) ch.setFormatter(fmt) logger.addHandler(ch) logger.info(f"📄 日志已启动,写入文件: {log_file}") return logger class PowerTableSynchronizer: def __init__(self, c_file_path: str, config_path: str = "config/config.json", dry_run: bool = False): # 获取脚本所在目录 → F:\issue\power script_dir = Path(__file__).parent # 推断项目根目录 → F:\issue project_root = script_dir.parent # 解析配置文件路径(支持相对或绝对) if not Path(config_path).is_absolute(): config_path = (project_root / config_path).resolve() self.c_file_path = Path(c_file_path) if not self.c_file_path.is_absolute(): self.c_file_path = (project_root / self.c_file_path).resolve() self.dry_run = dry_run self.output_dir = project_root / "output" self.log_dir = self.output_dir / "log" self.logger = setup_logger(self.log_dir) # 加载配置 self.config = self._load_config(config_path) self.platform = self.config.get("platform_rules", {}) self._validate() def _load_config(self, config_path: Path) -> dict: config_path = Path(config_path) if not config_path.exists(): raise FileNotFoundError(f"❌ 配置文件不存在: {config_path}") with open(config_path, 'r', encoding='utf-8') as f: try: return json.load(f) except json.JSONDecodeError as e: raise ValueError(f"配置文件格式错误: {e}") from e def _validate(self): if not self.c_file_path.exists(): msg = f"❌ 文件不存在: {self.c_file_path.resolve()}" self.logger.error(msg) raise FileNotFoundError(msg) self.logger.info(f"✅ 目标 C 文件已找到: {self.c_file_path.name}") def save_content(self, content: str): if self.dry_run: self.logger.info("🔍 【预览模式】跳过实际写入") return try: # 创建备份 backup_path = self.c_file_path.with_suffix(self.c_file_path.suffix + ".bak") shutil.copy2(self.c_file_path, backup_path) self.logger.info(f"📁 已创建备份: {backup_path.name}") # 写入新内容 with open(self.c_file_path, 'w', encoding='utf-8') as f: f.write(content) self.logger.info(f"✅ 成功更新文件: {self.c_file_path.name}") except Exception as e: self.logger.error(f"写入文件失败: {e}") raise # ==================== 提取区域 ==================== def _extract_section(self, content: str, section: str) -> tuple[str, int, int]: """ 根据配置提取指定区域内容 section: 'enums' | 'power_tables' | 'country_definitions' | 'ranges' """ try: anchors = self.platform["anchors"][section] start_marker = anchors["begin"] end_marker = anchors["end"] except KeyError as e: raise ValueError(f"配置错误:缺少锚点定义 {section}") from e start_pos = content.find(start_marker) end_pos = content.find(end_marker) if start_pos == -1 or end_pos == -1: missing = "起始标记" if start_pos == -1 else "结束标记" msg = f"未找到区域 {section} 的 {missing}: {start_marker[:30]}..." self.logger.warning(msg) raise ValueError(msg) inner_start = start_pos + len(start_marker) inner_end = end_pos extracted = content[inner_start:inner_end].strip() self.logger.debug(f"📦 提取区域 [{section}]: {len(extracted)} 字符") return extracted, inner_start, inner_end def _replace_section(self, content: str, section: str, new_content: str) -> str: """ 替换指定区域内容 """ try: anchors = self.platform["anchors"][section] start_marker = anchors["begin"] end_marker = anchors["end"] except KeyError as e: raise ValueError(f"配置错误:无法替换区域 {section}") from e start_pos = content.find(start_marker) end_pos = content.find(end_marker) if start_pos == -1 or end_pos == -1: raise ValueError(f"无法替换区域 {section},缺失锚点") return content[:start_pos + len(start_marker)] + "\n" + new_content + "\n" + content[end_pos:] # ==================== 1. 同步枚举区 ==================== def sync_locales_enum(self, content: str, new_entries: Dict[str, str]) -> str: """ 同步 enum locale_xxx_idx 区域 new_entries: { "locale_2g_idx": "LOCALE_2G_IDX_MY_REG = 42" } """ self.logger.info("🔄 开始同步 LOCALE ENUMS...") try: block, start, end = self._extract_section(content, "enums") except ValueError: return content lines = [line.rstrip() for line in block.splitlines()] output_lines = [] current_enum = None modified = False i = 0 while i < len(lines): line = lines[i] stripped = line.strip() # 匹配 enum 开始 enum_match = re.match(r"enum\s+([a-zA-Z0-9_]+)", stripped) if enum_match: enum_name = enum_match.group(1) pattern = self.platform.get("locale_enum", {}).get("pattern", r"locale_(\w+)_idx") if re.fullmatch(pattern.replace("\\", ""), enum_name): current_enum = enum_name output_lines.append(line) i += 1 continue # 匹配 enum 结束 → 插入新项 if stripped.endswith("};") and current_enum: key = current_enum.lower() if key in new_entries: entry_code = new_entries[key] last_line = output_lines[-1].rstrip() if not (last_line.endswith(",") or last_line.endswith("{")): output_lines[-1] = last_line + "," output_lines.append(f" {entry_code},") self.logger.info(f"📌 新增枚举: {key} → {entry_code}") modified = True output_lines.append(line) current_enum = None i += 1 continue output_lines.append(line) i += 1 if not modified: self.logger.info("🟨 枚举区无变更") return content new_block = "\n".join(output_lines) updated = self._replace_section(content, "enums", new_block) self.logger.info("✅ 枚举区更新完成") return updated # ==================== 2. 同步功率表区 ==================== def sync_power_tables(self, content: str, tables: Dict[str, str]) -> str: """ 同步功率表数组 tables: { "2g_base_MY_REG": "static const unsigned char locales_2g_base_MY_REG[] = { ... }" } """ self.logger.info("🔄 开始同步 POWER TABLES...") try: block, start, end = self._extract_section(content, "power_tables") except ValueError: return content # 构建动态正则 prefix = self.platform["power_table"]["prefix"] suffix = self.platform["power_table"]["suffix"].replace("[", "\\[").replace("]", "\\]") pattern_template = self.platform["power_table"][ "declaration_regex"] # "static\\s+const\\s+unsigned\\s+char\\s+(%s)\\s*=\\s*\\{[^}]*\\}\\s*;" # 提取已有数组名 array_pattern = r'static\s+const\s+unsigned\s+char\s+(' + prefix + r'[a-zA-Z0-9_]+)' + suffix + r'\s*=\s*\{[^}]*\}\s*;' existing_names = set(re.findall(array_pattern, block, re.IGNORECASE)) all_arrays = [] # 保留原始顺序 + 去重 for match in re.finditer(array_pattern, block, re.DOTALL | re.IGNORECASE): all_arrays.append(match.group(0)) added = [] for key, declaration in tables.items(): if key not in existing_names: all_arrays.append(declaration.strip() + ";") added.append(key) self.logger.info(f"📌 新增功率表: {prefix}{key}{suffix}") if not added: self.logger.info("🟨 功率表区无新增") return content new_block = "\n\n".join(all_arrays) updated = self._replace_section(content, "power_tables", new_block) self.logger.info(f"✅ 功率表更新完成,新增: {', '.join(added)}") return updated # ==================== 3. 同步国家码区 ==================== def sync_country_definitions(self, content: str, country_entries: List[str]) -> str: """ 同步 REGION("CC", ...) 国家码定义 """ self.logger.info("🔄 开始同步 COUNTRY DEFINITIONS...") try: block, start, end = self._extract_section(content, "country_definitions") except ValueError: return content macro_name = self.platform["country_definition"]["macro"] pattern = self.platform["country_definition"]["pattern"] # REGION\("([A-Z]{2})" existing_lines = [line.strip() for line in block.split('\n') if line.strip()] country_map = {} for line in existing_lines: cc_match = re.search(pattern, line) if cc_match: country_map[cc_match.group(1)] = line new_entries = [] for entry in country_entries: cc_match = re.search(pattern, entry) if cc_match: cc = cc_match.group(1) if cc not in country_map: new_entries.append(entry.strip()) self.logger.info(f"📌 新增国家码: {cc}") if not new_entries: self.logger.info("🟨 国家码无新增") return content all_lines = existing_lines + new_entries new_block = "\n".join(all_lines) updated = self._replace_section(content, "country_definitions", new_block) self.logger.info(f"✅ 国家码更新完成,新增 {len(new_entries)} 个") return updated # ==================== 主接口 ==================== def sync_all(self, locale_entries: Dict[str, str], power_tables: Dict[str, str], country_entries: List[str]): """ 一站式同步所有 CLM 内容 """ self.logger.info("🚀 开始执行 CLM 数据同步任务...") self.logger.info(f"目标文件: {self.c_file_path.name}") self.logger.info(f"预览模式: {'是' if self.dry_run else '否'}") try: content = self.load_content() content = self.sync_locales_enum(content, locale_entries) content = self.sync_power_tables(content, power_tables) content = self.sync_country_definitions(content, country_entries) self.save_content(content) self.logger.info("🎉 全部同步任务完成!") except Exception as e: self.logger.error(f"⛔ 同步过程中发生错误: {str(e)}") raise def load_content(self) -> str: """ 读取目标 C 文件内容 """ try: content = self.c_file_path.read_text(encoding='utf-8') self.logger.info(f"📄 已读取文件: {self.c_file_path.name} ({len(content)} 字符)") return content except Exception as e: self.logger.error(f"❌ 读取文件失败: {e}") raise def _extract_locale_block(content: str, locale_name: str) -> str | None: """ 从 tx_limit_table.c 中提取 /* Locale NAME */ 对应的数据块 返回去注释后的干净数据字符串 :param content: 原始文件内容 :param locale_name: 要提取的区域名,如 "DEFAULT" :return: 提取出的数据块(已清理),若未找到则返回 None """ import re pattern = rf'/\*\s*Locale\s+{locale_name}\s*\*/\s*([^/]*)' match = re.search(pattern, content, re.DOTALL) if not match: return None block = match.group(1).strip() # 去掉行内注释 /* ... */ block = re.sub(r'/\*.*?\*/', '', block) # 归一化空白字符 block = re.sub(r'\s+', ' ', block).strip() return block # ==================== 主函数:注入 DEFAULT 功率表(规范版)==================== def main(): """ 主函数:注入 DEFAULT 功率表 保持原有结构,仅提升路径处理的可靠性 """ import sys from pathlib import Path # --- 🔧 修正:使用项目根为基准解析路径 --- # 假设此脚本位于 power/power_sync.py project_root = Path(__file__).parent.parent # → F:\issue CONFIG_FILE = project_root / "config" / "config.json" GENERATED_FILE = project_root / "output" / "tx_limit_table.c" # 确保路径存在再继续 if not CONFIG_FILE.exists(): print(f"❌ 配置文件不存在: {CONFIG_FILE}", file=sys.stderr) sys.exit(1) if not GENERATED_FILE.exists(): print(f"❌ 生成的数据文件不存在: {GENERATED_FILE}", file=sys.stderr) sys.exit(1) try: # 1. 读取生成文件内容 gen_content = GENERATED_FILE.read_text(encoding='utf-8') # 2. 提取 DEFAULT 和 DEFAULT_HT 数据块 base_block = PowerTableSynchronizer._extract_locale_block(gen_content, "DEFAULT") ht_block = PowerTableSynchronizer._extract_locale_block(gen_content, "DEFAULT_HT") if not base_block and not ht_block: raise ValueError("未提取到任何 DEFAULT 功率表数据") # 3. 构造输入参数 locale_entries = { "locale_2g_idx": "LOCALE_2G_IDX_DEFAULT" } power_tables = {} if base_block: power_tables["2g_base_DEFAULT"] = ( f"static const unsigned char locales_2g_base_DEFAULT[] = {{\n {base_block}\n}}" ) if ht_block: power_tables["2g_ht_DEFAULT"] = ( f"static const unsigned char locales_2g_ht_DEFAULT[] = {{\n {ht_block}\n}}" ) country_entries = [ 'REGION("CN", LOCALE_2G_IDX_DEFAULT)', 'REGION("US", LOCALE_2G_IDX_DEFAULT)', ] # 4. 创建同步器(c_file_path 也建议用 Path 处理) c_file_path = project_root / "input" / "wlc_clm_data_6726b0.c" synchronizer = PowerTableSynchronizer( c_file_path=str(c_file_path), config_path=str(CONFIG_FILE), dry_run=False ) # 5. 执行同步 synchronizer.sync_all( locale_entries=locale_entries, power_tables=power_tables, country_entries=country_entries ) print("✅ 成功注入 DEFAULT 功率表!") except Exception as e: print(f"💥 错误: {e}", file=sys.stderr) sys.exit(1) 很好,现在看看函数布局结构有没有问题
最新发布
10-16
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值