1

我是一名生物工程博士生,试图自学 Python 编程以用于自动化我的部分研究,但我遇到了处理更大列表中的子列表的问题,我似乎无法解决。

基本上,我要做的目标是编写一个小脚本,该脚本将处理一个 CSV 文件,其中包含我正在使用各种 DNA 组装方法构建的质粒序列列表,然后吐出我需要的引物序列订购以构建质粒。

这是我正在处理的场景:

当我想构建一个质粒时,我必须在我的 Excel 电子表格中输入该质粒的完整序列。我必须在称为“Gibson”和“iPCR”的两种 DNA 组装方法之间进行选择。每个“iPCR”组装只需要列表中的一行,所以我已经知道如何处理这些人,因为我只需将我正在尝试构建的质粒的完整序列放入一个单元格中。另一方面,“Gibson”组装要求我必须将完整的 DNA 序列分成更小的块,所以有时我需要 Excel 电子表格中的 2-5 行来完整描述一个质粒。

所以我最终得到了一个看起来像这样的电子表格:

构造......策略......名称

1.....Gibson.....P(OmpC)-cI::P(cI)-LacZ 控制器
1.....Gibson.....P(OmpC)-cI::P(cI )-LacZ 控制器
1......Gibson......P(OmpC)-cI::P(cI)-LacZ 控制器
2......iPCR.......P(cpcG2)-带 K1F 位置的 K1F 控制器。反馈
3 .....Gibson .....P(cpcG2)-K1F 控制器与交换启动子位置
3 .....Gibson .....P(cpcG2)-K1F 控制器与交换启动子位置
4.. ...iPCR.......P(cpcG2)-K1F 控制器,具有更强的 K1F RBS 库

我认为这个长度的列表具有足够的代表性。

所以我遇到的问题是,我希望能够遍历列表并处理吉布森,但我似乎无法让代码以我想要的方式工作。这是我到目前为止编写的代码:

#import BioPython Tools
from Bio.Seq import Seq
from Bio.Alphabet import IUPAC

#import csv tools
import csv
import sys
import os

with open('constructs-to-make.csv', 'rU') as constructs:
    construct_list = csv.reader(constructs, delimiter=',')
    construct_list.next()
    construct_number = 1
    primer_list = []
    temp_list = []
    counter = 2

    for row in construct_list:
        print('Current row is row number ' + str(counter))
        print('Current construct number is ' + str(construct_number))
        print('Current assembly type is ' + row[1])
        if row[1] == "Gibson": #here, we process the Gibson assemblies first
            print('Current construct number is: #' + row[0] + ' on row ' + str(counter) + ', which is a Gibson assembly')
##            print(int(row[0]))
##            print(row[3])
            if int(row[0]) == construct_number:
                print('Adding DNA sequence from row ' + str(counter) + ' for construct number ' + row[0])
                temp_list.append(str(row[3]))
                counter += 1
            if int(row[0]) > construct_number:
                print('Current construct number is ' + str(row[0]) + ', which is greater than the current construct number, ' + str(construct_number))
                print('Therefore, going to work on construct number ' + str(construct_number))
                for part in temp_list: #process the primer design work here
                    print('test')
##                    print(part)
                construct_number += 1
                temp_list = []
                print('Adding DNA from row #' + str(counter) + ' from construct number ' + str(construct_number))
                temp_list.append(row)
                print('Next construct number is number ' + str(construct_number))
                counter += 1
##            counter += 1
        if str(row[1]) == "iPCR":
            print('Current construct number is: ' + row[0] + ' on row ' + str(counter) + ', which is an iPCR assembly.')
            #process the primer design work here
            #get first 60 nucleotides from the sequence
            sequence = row[3]
            fw_primer = sequence[1:61]
            print('Sequence of forward primer:')
            print(fw_primer)
            last_sixty = sequence[-60:]
##            print(last_sixty)
            re_primer = Seq(last_sixty).reverse_complement()
            print('Sequence of reverse primer:')
            print(re_primer)
            #ending code: add 1 to counter and construct number
            counter += 1
            construct_number += 1
##            if int(row[0]) == construct_number:
##        else:
##            counter += 1
##            construct_number += 1
##    print(temp_list)

##        for row in temp_list:
##    print(temp_list)        
##    print(temp_list[-1])
#                fw_primer = temp_list[counter - 1].

(我知道代码可能看起来很菜鸟 - 除了介绍性 Java,我从未做过任何编程课程。)

这段代码的问题在于,如果我有 n 个试图通过“Gibson”组装构建的“构造”(又名质粒),它将处理前 n-1 个质粒,但不会处理最后一个。然而,我也想不出任何更好的方法来编写这段代码,但我可以看到,对于我试图实现的工作流程,知道如何处理列表中的“n”个事物,但每个“事物“可变数量的行,对我来说真的很方便。

我真的很感谢这里的任何人的帮助!非常感谢!

4

2 回答 2

3

这段代码的问题在于,如果我有 n 个试图通过“Gibson”组装构建的“构造”(又名质粒),它将处理前 n-1 个质粒,但不会处理最后一个。

这实际上是一个普遍的问题,最简单的解决方法是在循环后添加一个检查,如下所示:

for row in construct_list:
    do all your existing code
if we have a current Gibson list:
    repeat the code to process it.

当然,您不想重复自己……所以您将这项工作转移到一个函数中,在这两个地方都调用它。

但是,我可能会用不同的方式写这个,使用groupby. 我知道这乍一看可能看起来“太高级了”,但值得尝试看看你是否能理解它,因为它让事情变得简单多了。

def get_strategy(row):
    return row[0]
for group in itertools.groupby(construct_list, key=get_strategy):

现在,您将获得每个构造作为单独的列表,因此您根本不需要temp_list。例如,第一组将是:

[[1, 'Gibson', 'P(OmpC)-cI::P(cI)-LacZ controller'],
 [1, 'Gibson', 'P(OmpC)-cI::P(cI)-LacZ controller'],
 [1, 'Gibson', 'P(OmpC)-cI::P(cI)-LacZ controller']]

接下来将是:

[[2, 'iPCR', 'P(cpcG2)-K1F controller with K1F pos. feedback']]

最后不会有剩下的群体需要担心。

所以:

for group in itertools.groupby(construct_list, key=get_strategy):
    construct_strategy = get_strategy(group[0])
    if construct_strategy == "Gibson":
        # your existing code, using group instead of temp_list,
        # and no need to maintain temp_list at all
    elif construct_strategy == 'iPCR":
        # your existing code, using group[0] instead of row

一旦克服了抽象障碍,以这种方式思考问题就会简单得多。

事实上,一旦你开始直观地掌握迭代器,你就会开始发现itertools(以及它的文档页面上的食谱、第三方库more_itertools以及你可以自己编写的类似代码)将很多复杂的问题变得非常简单那些。“如何在行列表中跟踪当前匹配行组?”的答案。是“保留一个临时列表,并记住在每次组更改时检查它,然后在最后再次检查是否有剩余”,但是等效问题的答案“如何将行迭代转换为行组迭代?” 是“将迭代器包装在groupby.”中。

您可能还想添加一个assert或其他检查all(row[1] == construct_strategy for row in group[1:])len(group) == 1在这种iPCR情况下,没有意外的第三个策略等,所以当您不可避免地遇到错误时,更容易判断它是否是坏数据或错误的代码。

同时,与其使用 a csv.reader,跳过第一行并用无意义的数字引用列,不如使用 a DictReader

with open('constructs-to-make.csv', 'rU') as constructs:
    primer_list = []
    def get_strategy(row):
        return row["Strategy"]
    for group in itertools.groupby(csv.DictReader(constructs), key=get_strategy):
        # same as before, but with
        # ... row["Construct"] instead of row[0]
        # ... row["Strategy"] instead of row[1]
        # ... row["Name"] instead of row[2]
于 2012-12-28T01:29:52.067 回答
1

只是一些关于 python 的一般编码帮助。如果您还没有阅读 PEP8,请这样做。

为了保持清晰的代码,将变量分配给记录/行中引用的字段会很有帮助。

我会为引用的任何字段添加类似的内容:

construct_idx = 0

另外,我建议使用字符串格式,它更干净。

所以:

print('Current construct number is: #{} on row {}, which is a Gibson assembly'.format(row[construct_idx], counter))

代替:

print('Current construct number is: #' + row[0] + ' on row ' + str(counter) + ', which is a Gibson assembly')

如果您正在创建一个 csv 阅读器对象,则将其设置为变量名“*_list”可能会导致误导。称它为“*_reader”更直观。

construct_reader = csv.reader(constructs, delimiter=',')

代替:

construct_list = csv.reader(constructs, delimiter=',')
于 2012-12-28T01:31:04.327 回答