如何合理归类仅服务主函数的无副作用辅助函数?
把辅助函数归到主函数专属上下文的最佳实践
我懂你这种困扰——主函数带着一堆辅助函数,放模块层级太乱,又想给它们一个清晰的归属,还不想搞复杂。先梳理下你列出的几个方案,再聊聊最适合你的选择:
方案0:独立模块
把相关代码单独放到一个模块里:
# template_fillers.py def create_in_temp(path, values_mapping): template_text = path.read_text() filled_template = _fill_template(template_text, values_mapping) result_path = _save_in_temp(filled_template) return result_path def _fill_template(template_text, values_mapping): ... def _save_in_temp(filled_template): _, pathname = tempfile.mkstemp(suffix='.ini', text=True) path = pathlib.Path(pathname) path.write_text(filled_template) return path
调用方式:
import template_fillers template_fillers.create_in_temp(path, values_mapping)
存在问题
- 代码量太少,单独新增文件反而会加剧项目结构混乱
- 明明是一个操作,却被迫用名词性模块名(要么违反命名规则,要么名称过于宽泛),增加理解成本
方案1:普通类
创建一个无__init__方法、仅含一个公开方法的类:
class TemplateFillerIntoTemp: def run(self, path, values_mapping): template_text = path.read_text() filled_template = self._fill_template(template_text, values_mapping) result_path = self._save_in_temp(filled_template) return result_path def _fill_template(self, template_text, values_mapping): ... def _save_in_temp(self, filled_template): _, pathname = tempfile.mkstemp(suffix='.ini', text=True) path = pathlib.Path(pathname) path.write_text(filled_template) return path
调用方式:
TemplateFillerIntoTemp().run(path, values_mapping)
存在问题
- 无状态无副作用,完全没必要创建类实例,属于过度设计
- 为了套类的壳,硬用名词性类名,容易催生一堆“管理器”“创建器”类,把简单操作复杂化
- 这是对类概念的误用:类是用来描述事物的,不是用来打包几个函数的,反而会降低代码可读性
方案2:静态类
在方案1基础上,给所有方法添加@staticmethod装饰器,可配合ABC元类:
from abc import ABC class TemplateFillerIntoTemp(ABC): @staticmethod def run(path, values_mapping): template_text = path.read_text() filled_template = TemplateFillerIntoTemp._fill_template(template_text, values_mapping) result_path = TemplateFillerIntoTemp._save_in_temp(filled_template) return result_path @staticmethod def _fill_template(template_text, values_mapping): ... @staticmethod def _save_in_temp(filled_template): _, pathname = tempfile.mkstemp(suffix='.ini', text=True) path = pathlib.Path(pathname) path.write_text(filled_template) return path
调用方式:
TemplateFillerIntoTemp.run(path, values_mapping)
优缺点
- 优点:明确表明操作与实例无关,无需多余实例化
- 缺点:平白增加了
@staticmethod和类的冗余代码,把简单问题复杂化
方案3:含__call__方法的类
在方案1基础上,将主方法改为__call__,并在模块层级创建单实例:
class TemplateFillerIntoTemp: def __call__(self, path, values_mapping): template_text = path.read_text() filled_template = self._fill_template(template_text, values_mapping) result_path = self._save_in_temp(filled_template) return result_path def _fill_template(self, template_text, values_mapping): ... def _save_in_temp(self, filled_template): _, pathname = tempfile.mkstemp(suffix='.ini', text=True) path = pathlib.Path(pathname) path.write_text(filled_template) return path # 模块层级单实例 create_filled_template_in_temp = TemplateFillerIntoTemp()
调用方式:
create_filled_template_in_temp(path, values_mapping)
优缺点
- 优点:调用方式和普通函数完全一致,外部感知不到类的存在
- 缺点:实现过于绕弯,为小需求搞复杂设计,完全不符合你的场景
方案4:辅助函数内嵌主函数
把辅助函数直接放到主函数内部:
def create_filled_template_in_temp(path, values_mapping): def _fill_template(template_text, values_mapping): ... def _save_in_temp(filled_template): _, pathname = tempfile.mkstemp(suffix='.ini', text=True) path = pathlib.Path(pathname) path.write_text(filled_template) return path template_text = path.read_text() filled_template = _fill_template(template_text, values_mapping) result_path = _save_in_temp(filled_template) return result_path
调用方式:
create_filled_template_in_temp(path, values_mapping)
优缺点
- 优点:代码量最少,辅助函数完全归属主函数,不会污染模块层级,结构清晰
- 缺点:若辅助函数过多(比如几十行)会导致主函数臃肿,但你的辅助函数仅15行左右,完全不存在这个问题
最终推荐
对你的场景来说,方案4绝对是最优解——既满足了辅助函数仅属于主函数的需求,又不会污染模块层级,代码简单直接,完全匹配你的所有条件:辅助函数代码量少、仅主函数调用、近期无复用计划。
如果以后真的需要复用这些辅助函数,再考虑拆成模块或类都来得及,现在完全没必要过度设计。
内容的提问来源于stack exchange,提问作者Ctrl-C
相关产品推荐
相关产品推荐

