如何通过继承实现Click命令代码去重?以lidtk分类器为例
实现Click命令的继承与代码去重
当然可以!你遇到的这种重复Click命令结构的场景,完全可以通过抽象通用逻辑+继承/工厂模式来实现代码复用,彻底消除冗余。下面给你两种适配你场景的实用方案:
方案一:创建带通用CLI命令的基类
既然所有分类器都继承自lidtk.LIDClassifier,我们可以再封装一个带Click命令的中间基类,把重复的命令逻辑全部放在这里,让具体分类器类直接继承它即可。
步骤1:定义通用CLI基类
在lidtk库中新增一个base_cli.py文件,写入以下代码:
import click from lidtk import LIDClassifier class BaseCLIClassifier(LIDClassifier): @classmethod def create_cli(cls, module_name): """生成当前分类器的Click命令组""" @click.group(help=f"Use the {module_name} language classifier.") def cli(): pass # 绑定通用命令到分类器实例 classifier = cls() @cli.command() def get_languages(): """获取当前分类器支持的语言列表""" languages = classifier.get_supported_languages() click.echo("\n".join(languages)) @cli.command() @click.argument("text") def predict(text): """预测输入文本的语言""" result = classifier.predict_language(text) click.echo(result) @cli.command() def print_languages(): """格式化打印支持的语言列表""" languages = classifier.get_supported_languages() click.echo(f"Supported languages ({len(languages)}):") for lang in sorted(languages): click.echo(f"- {lang}") @cli.command() def wili(): """在WILI数据集上运行评估""" classifier.evaluate_wili() click.echo("WILI evaluation completed.") @cli.command() @click.argument("k", type=int) def wili_k(k): """在WILI数据集上运行Top-K评估""" classifier.evaluate_wili_top_k(k) click.echo(f"WILI top-{k} evaluation completed.") @cli.command() def wili_unk(): """在WILI数据集上运行未知语言评估""" classifier.evaluate_wili_unknown() click.echo("WILI unknown language evaluation completed.") return cli
步骤2:改造具体分类器模块
以cld2_mod.py为例,现在只需要实现分类器的核心逻辑,调用基类的方法生成CLI即可:
from lidtk.base_cli import BaseCLIClassifier import cld2 class CLD2Classifier(BaseCLIClassifier): def get_supported_languages(self): # 实现CLD2特有的语言列表逻辑 return ["en", "fr", "de", "es", ...] def predict_language(self, text): # 实现CLD2特有的预测逻辑 return cld2.detect(text)[0] def evaluate_wili(self): # 实现CLD2特有的WILI评估逻辑 pass # 其他评估方法同理实现... # 生成当前模块的CLI命令组 cli = CLD2Classifier.create_cli("cld2_mod")
其他三个模块(langdetect_mod.py、langid_mod.py、text_cat.py)只需要替换类名和核心逻辑,完全复用基类的CLI命令结构。
方案二:使用工厂函数生成CLI
如果不想新增基类,也可以用工厂函数来封装通用的CLI命令生成逻辑,这种方式更轻量化:
步骤1:定义CLI工厂函数
在lidtk/utils.py中添加:
import click def create_lid_cli(classifier_class, module_name): """为LID分类器生成通用Click命令组""" @click.group(help=f"Use the {module_name} language classifier.") def cli(): pass classifier = classifier_class() # 以下命令逻辑和方案一完全一致,省略重复代码 @cli.command() def get_languages(): languages = classifier.get_supported_languages() click.echo("\n".join(languages)) @cli.command() @click.argument("text") def predict(text): result = classifier.predict_language(text) click.echo(result) # 其余命令(print_languages、wili等)同上... return cli
步骤2:改造具体模块
还是以cld2_mod.py为例:
from lidtk import LIDClassifier from lidtk.utils import create_lid_cli import cld2 class CLD2Classifier(LIDClassifier): # 核心逻辑实现同上... # 调用工厂函数生成CLI cli = create_lid_cli(CLD2Classifier, "cld2_mod")
扩展与维护
如果未来某个分类器需要添加特定命令,只需要在生成的cli对象上额外添加即可,不会影响其他模块:
# 在cld2_mod.py中添加CLD2专属命令 @cli.command() def cld2_debug(): """CLD2专属调试命令""" click.echo("Running CLD2 debug mode...")
如果需要修改通用命令的逻辑(比如调整predict命令的参数),只需要修改基类或工厂函数中的代码,所有模块都会自动同步更新,彻底解决冗余问题。
内容的提问来源于stack exchange,提问作者Martin Thoma
相关产品推荐
相关产品推荐

