这是我目前的代码:
import re
with open("link_allenz.txt") as f:
s = f.read()
baseDict={'A':'A','C': 'C','T':'T','G':'G','R':'[GA]','Y':'[CT]',
'M':'[AC]','K':'[GT]','S':'[GC]','W':'[AT]',
'B':'[CGT]','D':'[ACT]','V':'[ACG]','N':'[ACGT]',',':'|'}
pat1=r'<1>(.*)\n(?:.*\n){3}<5>(.*)\n'
re1=re.compile(pat1)
e2r_dict=dict(re1.findall(s))
def make_seq_2_re(strand):
while True:
try:
x=e2r_dict[strand]
x_split=list(x)
print(x_split)
for base in x_split:
if baseDict.get(base):
x_split[x_split.index(base)]=baseDict[base]
else:
x_split.remove(base)
y=''.join(x_split)
if len(y)>0:
return(y)
else:
print("No known strand for "+strand+"!")
break
except KeyError:
print("Was there a spelling error?")
pass
对于我的课堂项目,这应该读取一个充满 DNA 链的文件,并将我告诉它的文件转换为正则表达式。出于某种原因,它并不总是转换它需要的每个字母。例如,如果它应该转换 GACNNNN^NNGTC,它将输出 GAC[ACGT][ACGT][ACGT][ACGT][ACGT]NGTC,忽略最后的 N。我该如何更改这个?
答案 0 :(得分:1)
您在迭代时修改了 x_split
。这从根本上是行不通的。相反,解决方案是在迭代输入时生成一个新序列。
此代码还有多个其他问题。
while True:
有什么作用?这似乎没有必要,而且您在一次迭代后总是中断。您可以完全删除它。
你的 try
块意味着如果用户使用错误的键调用函数,他们会收到一条消息而不是错误。创建可读的消息很好,但吞下错误不是。改为引发自定义错误。
try
块太大:它应该只包含 e2_dict
子集,而不是整个函数。把它变小可以更清楚哪里可能发生错误,并使代码更具可读性。
x_split=list(x)
是不必要的:字符串是序列,你可以像列表一样迭代它们。
x_split.index(base)
做错了事:它返回 base
中 x_split
的 first 索引。考虑一下当您有输入 GAA
并且您处于最后一个基数时会发生什么:x_split.index('A')
将返回 1,而不是 2(正确的索引)。您不能在此处使用 index
。如果在迭代序列时需要索引,请使用 for i, base in enumerate(x_split)
。但是,我们在更正后的代码中实际上不需要这个,见下文。
组合 baseDict.get(base)
... baseDict[base]
执行一次冗余查找。理想情况下,我们希望避免这种不必要的工作。
if len(y)>0:
有点奇怪:如果 False
存在但为空或仅包含无效符号(例如 e2r_dict[strand]
),则此条件只会是 ^^
.这是真实发生的案例吗?如果是这样,应该改进错误消息。而且,同样,不要打印错误消息。 提出错误。如果我们反转条件,我们也不需要 else
情况。
strand
这个名字很奇怪:它似乎指代 DNA 以外的东西;我不知道您的确切域,所以这可能是正确的术语,但在序列分析的背景下,我从未听说它指的是 DNA 链以外的任何东西。
同样,像 pat1
、re1
、baseDict
、x
和 y
这样的名字也不是好名字,它们要么不给任何关于他们目的的信息(x
,y
)或者他们提供了不相关的信息(1
中的 re1
是什么?baseDict
for ?)。
选择好的名字很重要,因为它会大大提高可读性。 make_seq_2_re
更好,但仍然可以改进:make
通常太笼统而无法在名称中使用(尽管也有例外),并且此类名称通常被表述为“make A from B”,而不是“make B to A”,符合英语语法。
熟悉the official Python style guide, PEP 8。特别是,比 snake_case
更喜欢 mixedCase
并在操作符周围放置一致的空格。
考虑到所有这些,我会像这样编写函数,例如:
def seq_re(name):
try:
seq = e2r_dict[name]
except KeyError:
raise KeyError(f'No sequence found for {name}')
re = ''
for base in seq:
pattern = base_pattern_table.get(base)
if pattern:
re += pattern
if not re:
raise RuntimeError(f'sequence for {name} was invalid')
return re
然而,Pythonists 喜欢列表理解,并且从一个空列表迭代地构建一个序列被视为一种反模式。所以我很想重写那部分:
def seq_re(name):
try:
seq = e2r_dict[name]
except KeyError:
raise KeyError(f'No sequence found for {name}')
re = ''.join([pattern for base in seq
if (pattern := base_pattern_table.get(base))])
if not re:
raise RuntimeError(f'sequence for {name} was invalid')
return re
请注意,由于它使用了 walrus operator,因此它需要最新版本的 Python(≥ 3.8)。我通常敦促不要过度使用此运算符。但我认为在这种情况下是合适的。