Python生物信息学包模块结构优化及代码运行原理咨询
一、未实例化直接调用可正常运行的原因
你当前的写法属于Python非规范的偶然可用情况。类内部默认定义的方法为实例方法,要求第一个参数必须是实例本身(约定命名为self)。你直接通过类名Punnet.progeny()调用时,Python不会自动注入self参数,刚好你定义的progeny第一个参数是genotype1,调用时传入的两个基因型参数刚好匹配参数列表,所以不会报错。但如果尝试实例化后调用Punnet().progeny(xxx)就会抛出参数不匹配的错误,因为实例调用时会自动把实例对象作为第一个参数传入,相当于多传了一个参数。
二、更规范的实现与包结构设计
2.1 方法层面的修正
你的progeny方法不需要访问类属性、也不需要操作实例属性,属于纯工具方法,应该加上@staticmethod装饰器声明为静态方法,这样不管是类调用还是实例调用都符合语法规范,同时可以对重复逻辑做抽取优化,参考修正后代码:
import re import itertools import numpy as np class Punnet: @staticmethod def progeny(genotype1: str, genotype2: str, show: str = 'genotype') -> dict: # 前置参数校验 if show not in ('genotype', 'phenotype'): raise ValueError(f"show参数仅支持'genotype'和'phenotype',当前输入为{show}") g1 = [list(i) for i in re.findall('..', genotype1)] g2 = [list(i) for i in re.findall('..', genotype2)] gametes1 = itertools.product(*g1) gametes2 = itertools.product(*g2) mate = itertools.product(gametes1, gametes2) progeny_list = [] for gamete1, gamete2 in mate: offspring = '' for a1, a2 in zip(gamete1, gamete2): allele_pair = sorted([a1, a2]) if show == 'genotype': offspring += ''.join(allele_pair) else: offspring += allele_pair[0] progeny_list.append(offspring) unique, counts = np.unique(progeny_list, return_counts=True) return dict(zip(unique, counts))
2.2 包结构设计
要满足你预期的import Rosa后直接调用Rosa.Punnet.progeny()的用法,推荐分层清晰的目录结构如下:
Rosa/ # 包根目录 ├── __init__.py # 包入口文件 ├── genetics/ # 遗传学相关功能模块目录 │ ├── __init__.py │ └── punnet.py # 存放上述Punnet类的实现代码 └── utils/ # 通用工具目录 ├── __init__.py └── validators.py # 存放基因型格式校验、参数校验等通用工具逻辑
在最上层的Rosa/__init__.py中添加导出逻辑,即可支持预期的调用形式:
from .genetics.punnet import Punnet __version__ = "0.1.0"
这个结构后续新增其他功能(比如序列比对、变异分析模块)时,可以直接在根目录新增对应模块目录,不会出现结构混乱的问题。
2.3 后续优化建议
- 补充输入校验:比如校验输入的基因型字符串是否为偶数长度、是否仅包含合法的等位基因代表字符,避免非法输入导致逻辑错误
- 保留扩展性:后续如果需要支持自定义等位基因显隐性规则、多性状连锁分析等功能,可以添加类属性存储规则,对应方法改为类方法即可
- 补充单元测试:针对不同的基因型组合、参数配置分别写测试用例,保证迭代过程中逻辑正确性
内容的提问来源于stack exchange,提问作者Aditya Prakash
相关产品推荐
相关产品推荐

