将 DNA 链转换为正则表达式

时间:2021-03-27 23:22:37

标签: python bioinformatics re

这是我目前的代码:

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。我该如何更改这个?

1 个答案:

答案 0 :(得分:1)

您在迭代时修改了 x_split。这从根本上是行不通的。相反,解决方案是在迭代输入时生成一个新序列。

此代码还有多个其他问题。

  1. while True: 有什么作用?这似乎没有必要,而且您在一次迭代后总是中断。您可以完全删除它。

  2. 你的 try 块意味着如果用户使用错误的键调用函数,他们会收到一条消息而不是错误。创建可读的消息很好,但吞下错误不是。改为引发自定义错误。

  3. try 块太大:它应该只包含 e2_dict 子集,而不是整个函数。把它变小可以更清楚哪里可能发生错误,并使代码更具可读性。

  4. x_split=list(x) 是不必要的:字符串是序列,你可以像列表一样迭代它们。

  5. x_split.index(base) 做错了事:它返回 basex_splitfirst 索引。考虑一下当您有输入 GAA 并且您处于最后一个基数时会发生什么:x_split.index('A') 将返回 1,而不是 2(正确的索引)。您不能在此处使用 index。如果在迭代序列时需要索引,请使用 for i, base in enumerate(x_split)。但是,我们在更正后的代码中实际上不需要这个,见下文。

  6. 组合 baseDict.get(base) ... baseDict[base] 执行一次冗余查找。理想情况下,我们希望避免这种不必要的工作。

  7. if len(y)>0: 有点奇怪:如果 False 存在但为空或仅包含无效符号(例如 e2r_dict[strand]),则此条件只会是 ^^ .这是真实发生的案例吗?如果是这样,应该改进错误消息。而且,同样,不要打印错误消息。 提出错误。如果我们反转条件,我们也不需要 else 情况。

  8. strand 这个名字很奇怪:它似乎指代 DNA 以外的东西;我不知道您的确切域,所以这可能是正确的术语,但在序列分析的背景下,我从未听说它指的是 DNA 链以外的任何东西。

  9. 同样,像 pat1re1baseDictxy 这样的名字也不是好名字,它们要么不给任何关于他们目的的信息(xy)或者他们提供了不相关的信息(1 中的 re1 是什么?baseDict for ?)。

    选择好的名字很重要,因为它会大大提高可读性。 make_seq_2_re 更好,但仍然可以改进:make 通常太笼统而无法在名称中使用(尽管也有例外),并且此类名称通常被表述为“make A from B”,而不是“make B to A”,符合英语语法。

  10. 熟悉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)。我通常敦促不要过度使用此运算符。但我认为在这种情况下是合适的。