我对编程还比较陌生,我很想得到一些关于我的代码的以下部分的反馈。
class Gene:
def __init__(self, gene_symbol, gene_id):
# gene_symbol represents the abbreviated name of the gene (string)
# Example: 'RHO' (short for 'Rhodopsin')
self.gene_symbol = gene_symbol
# gene_id represents an accession ID for the gene (string)
# Example: 'NM_000539.3'
self.gene_id = gene_id
# is_valid_ functions check if the type of the gene_id is valid
# and returns True or False
# Assume that the types of the gene_id are mutually exclusive
if is_valid_refseq(gene_id):
# Example of a valid refseq: 'NM_000539.3'
self.gene_id_type = REFSEQ
elif is_valid_ensembl_gene(gene_id):
# Example of a valid ensembl_gene: 'ENSG00000163914'
self.gene_id_type = ENSEMBL_GENE
elif is_valid_ensembl_transcript(gene_id):
# Example of a valid ensembl_transcript: 'ENST00000296271'
self.gene_id_type = ENSEMBL_TRANSCRIPT
else:
raise InvalidGeneIDError("Invalid gene_id: {}".format(gene_id))
refseqs = []
ensembl_genes = []
ensembl_transcripts = []
with open(csv_gene_list, 'r', newline='') as csv_input:
reader = csv.reader(csv_input, delimiter=',')
next(reader)
for row in reader:
row_gene_symbol = row[0]
row_gene_id = row[1]
row_gene = Gene(row_gene_symbol, row_gene_id)
if row_gene.gene_id_type == REFSEQ:
refseqs.append(row_gene)
elif row_gene.gene_id_type == ENSEMBL_GENE:
ensembl_genes.append(row_gene)
elif row_gene.gene_id_type == ENSEMBL_TRANSCRIPT:
ensembl_transcripts.append(row_gene)
else:
# What do I do here?
raise AssertionError('Unrecognized gene_id_type: {}'.format(
row_gene.gene_id_type))假设gene_symbol和gene_id是字符串,is_valid_函数是在代码的其他地方实现的。
我想问一下,实现这些多个if - the语句是否是正确的方法。我觉得如果在行后添加更多的这些条件表达式,我的代码可能会变得杂乱无章。
另一个问题是关于最后一条else语句。在这种情况下我该怎么办?如果代码按预期工作,那么它不应该到达最后一个else语句,因为在初始化Gene对象时应该引发InvalidGeneIDError。一种解决方案是省略这一部分并将elif row_gene.gene_id_type == ENSEMBL_TRANSCRIPT:更改为else:,但我更愿意明确地说明具体的检查,以帮助传达代码的意图。
在我前进的过程中,我的主要任务是集中精力开发良好的编码风格/习惯,并编写可读的代码。我还想学习/发现Python必须提供的新工具/技巧。如有任何建议和帮助,将不胜感激。
发布于 2015-12-04 23:55:56
是的,问题在于切换:在两个地方都有相同的if-elif- set条件重复。很可能,随着程序的发展,您将添加更多的这些链的副本。这些链的问题是,如果以后需要在中间再添加一种情况,则需要相应地修改所有副本。这很容易出错,因为您可能不记得复制链的所有位置。
我们怎样才能更好地处理这件事?我们是否可以用其他的方法来替换这些链,如果我们在Gene构造函数中添加一个新的情况,我们就可以不用担心程序的其余部分了?
至少在这个例子中,有一个可行的解决方案。考虑这3份清单:
参= [] ensembl_genes = [] ensembl_transcripts = []
这些清单是问题的一个重要部分。它们反映了当前支持的3种类型,当您将项目放入这些列表中时,需要准确地通过这些名称引用这些列表。
您可以使用列表字典来代替这些列表,其中键是基因类型,值是列表。就像这样:
genes = dict()
with open(csv_gene_list, 'r', newline='') as csv_input:
reader = csv.reader(csv_input, delimiter=',')
next(reader)
for row in reader:
row_gene_symbol = row[0]
row_gene_id = row[1]
row_gene = Gene(row_gene_symbol, row_gene_id)
if row_gene.row_gene_id not in genes:
genes[row_gene.row_gene_id] = []
genes[row_gene.row_gene_id].append(row_gene)
# ...在这种形式下,链条消失了,你问题的第二部分自然也消失了。
正如@jaime在评论中指出的,这可以大大简化:
如果基因中没有row_gene.row_gene_id:划_gene.row_基因_id= [] 划_gene.row_基因_id.append(Row_gene)
像这样使用setdefault:
genes.setdefault(row_gene.row_gene_id, []).append(row_gene)发布于 2015-12-05 00:51:02
以下是我的代码在采纳@janos的建议后的一个修订版。
# Make an empty dictionary that will hold the following key-value pairs
# {gene_id_type: list of Gene objects}
all_genes = dict()
with open(csv_gene_list, 'r', newline='') as csv_input:
reader = csv.reader(csv_input, delimiter=',')
next(reader)
for row in reader:
row_gene_symbol = row[0]
row_gene_id = row[1]
row_gene = Gene(row_gene_symbol, row_gene_id)
gene_id_type = row_gene.gene_id_type
# Check if gene_id_type is in the dictionary
if gene_id_type in all_genes:
# Append row_gene to the list in the dictionary
all_genes[gene_id_type].append(row_gene)
else:
# Make a new key named gene_id_type and
# assign its value as a list with row_gene in it
all_genes[gene_id_type] = [row_gene]
# Do stuff with all_genes发布于 2015-12-07 12:20:17
如果文件中的行只包含两个元素,则可以同时设置符号和id。我也不认为你需要有row_前缀。
gene_symbol, gene_id = row这将将每个row解压到gene_symbol和gene_id的两个值中。这是一种同时获得两个值的更干净的方法。如果row有两个以上的值,则会引发错误,但这也意味着您不会忽略格式错误的数据。
https://codereview.stackexchange.com/questions/112942
复制相似问题