Python for Bioinformatics 4 流程控制.docx
《Python for Bioinformatics 4 流程控制.docx》由会员分享,可在线阅读,更多相关《Python for Bioinformatics 4 流程控制.docx(22页珍藏版)》请在冰豆网上搜索。
PythonforBioinformatics4流程控制
PythonforBioinformatics(4)
第四章编程:
流程控制
为了能够做一些有用的东西,程序必须有某种机制来管理怎样和何时执行指令。
交通灯控制着在街上的车流,以同样的方式,流程控制结构指导代码段在一个给定的时间里执行。
通过大量的简化,Python只有三种流的控制结构:
有一个条件结构和两个迭代结构。
条件结构(if)决定,在表达式求值后,是执行或不执行代码块。
迭代结构允许多次执行相同的代码段。
可以执行多少次迭代结构相关的代码呢?
它取决于是哪种循环。
一个for循环执行一个代码块的次数决定于它指定的迭代量的元素的个数,而在while循环下的代码执行直到给定的条件变成假(注:
这等于说,条件为真时执行)。
——————————————————————————————
4.1If-Else
条件结构最经典的控制结构的之一。
它的行为根据求值的结果,如果你知道任何其他的计算机语言,你就有机会熟悉if-else。
计算一个表达式,如果表达式为真,在if子句后的代码块被执行,否则,在else块中执行。
一个if-else条件的基本模式如下:
if EXPRESSION:
Block1
else:
Block2
EXPRESSION必须是一个表达式返回True或False。
这是所有比较的运算符情形:
xy(大于),x==y(等于),x!
=y(不等于)(注:
还有一个过期的运算符<>,你可以在旧的Python版本中找到),x<=y(小于或等于),x>=y(大于或等于)。
来看一个例子:
————————————————————————————
列表4.1:
基本的if-else例子
1 a = 8
2 if a>5:
3 print("a is greater than 5")
4 else:
5 print("a is smaller than 5")
————————————————————————————
程序输出:
a is greater than 5
另一个例子:
————————————————————————————
列表4.2:
实施if-else
1 trans = {"A":
"Ala","N":
"Asn","D":
"Asp","C":
"Cys"}
2 aa = raw_input("Enter one letter:
")
3 if aa in trans:
4 print("The three letter code for "+aa+" is:
"+trans[aa])
5 else:
6 print("Sorry, I don’t have it in my dictionary")
————————————————————————————
程序输出:
Enter one letter:
A
The three letter code for A is:
Ala
为了计算一个以上的条件的值,可以使用elif:
if EXPRESSION1:
Block1
elif EXPRESSION2:
Block2
elif EXPRESSION3:
Block3
else:
Block4
你用多少的elif作为条件来求值都可以。
要注意到的是,一旦一个条件为真值时,其余的条件将不会被检查。
下面的程序使用elif计算多个条件:
—————————————————————————————
列表4.3:
使用elif
1 dna = raw_input("Enter your DNA sequence:
")
2 seqsize = len(dna)
3 if seqsize < 10:
4 print("The primer must have at least ten nucleotides")
5 elif seqsize < 25:
6 print("This size is OK")
7 else:
8 print("The primer is too long")
—————————————————————————————
该程序要求在运行时键盘输入DNA序列,这个序列被称为dna。
它的大小是在第2行计算的,结果绑定在名称seqsize。
在第3行有一个判断求值:
如果seqsize小于10,显示消息“引物必须有至少10个核苷酸”。
程序流跑到此if语句块的最后,没有任何执行if声明中的其他的条件求值。
如果它是不真的值(例如,如果序列的长度是15),一旦下一个条件计算的值是真,它会执行和该条件关联的块。
如果序列的长度值大于10,程序将跳过第4行(第一个条件的代码块),并会计算第5行中的表达,如果这一条件得到满足,它会打印出“这大小是可以的。
”,如果没有表达式计算出真值,执行else块。
——————————————————————————————
小技巧:
什么是真值(True)
记得前面声明,只有计算表达式为真值(True)时,条件语句才能够被执行。
所以现在的问题“什么是真值?
”(“什么是假值,False?
”)是切题的:
什么是真值?
•非空数据结构(列表,字典,元组,字符串,集合)记为True;
•0和None记为False,而其他值记为True;
•关键字True是True,False是False。
如果你对一个表达式是真的还是假的有疑问,使用bool():
>>> a=1
>>> b=’1’
>>> bool(a==b)
False
——————————————————————————————
条件结构可以嵌套:
——————————————————————————————
列表4.4:
嵌套if
1 dna = raw_input("Enter your DNA sequence:
")
2 seqsize = len(dna)
3 if seqsize < 10:
4 print("Your primer must have at least ten nucleotides")
5 if seqsize==0:
6 print("You must enter something!
")
7 elif seqsize < 25:
8 print("This size is OK")
9 else:
10 print("Your primer is too long")
——————————————————————————————
在第5行有一个条件在另一个条件的嵌套。
注意这里是双等号("=="),而不是单等号。
双等号是用来比较值的,而单等号是赋值:
>>> answer=42
>>> answer
42
>>> answer==3
False
>>> answer==42
True
在代码4.4中引入的if嵌套可以避免:
——————————————————————————————————
列表4.5:
嵌套if
1 dna = raw_input("Enter your DNA sequence:
")
2 seqsize = len(dna)
3 if seqsize==0:
4 print("You must enter something!
")
5 elif 06 print("Your primer must have at least ten nucleotides")
7 elif seqsize < 25:
8 print("This size is OK")
9 else:
10 print("Your primer is too long")
——————————————————————————————
注意第5行表达式的计算形式。
这让我们想到如何在一个if中加入多个声明,像代码4.6的例子:
——————————————————————————————
列表4.6:
多部分条件
1 x = ’N/A’
2 if x!
=’N/A’ and 53 print(’OK’)
4 else:
5 print(’Not OK’)
——————————————————————————————
这个表达式是从左至右求值的,如果一个表达式的一部分是假的,以下部分不计算。
由于X=“N/A”,该程序将打印“NotOK”(因为第一个条件是假的)。
看看相同的表达式是按反向顺序书写会发生什么?
这是程序:
——————————————————————————————
列表4.7:
多部分的条件,反向
x=’N/A’
if 5=’N/A’:
print(’OK’)
else:
print(’Not OK’)
——————————————————————————————
返回结果是:
Traceback (most recent call last):
File "", line 1, in
if 5=’N/A’:
ValueError:
invalid literal for float():
N/A
产生ValueError错误是因为字符串“N/A”不能转换为float。
x在代码4.6中也为“N/A”,但没有ValueError错误,是因为这部分的表达在被计算前跳过了。
——————————————————————————————
4.1.1pass语句
有时候在if声明中没有另一种备用选择的需要,在这种情况下,你可以避免使用else:
if EXPRESSION:
Block
Rest of the program...
为了使相同的代码更具可读性,Python提供了pass语句。
该声明就像一个占位符,它除了为声明语句所需的语法提供支撑,不用于任何其他目的。
下面的代码与前面的代码产生相同的输出:
if CONDITION:
BLOCK
else:
pass
Rest of the program...
——————————————————————————————
高级技巧:
条件表达式
有时为了方便,用一种特殊的语法可以把条件结构写在一行上。
自Python2.5中,下面的结构是可用的:
expression1 if condition else expression2
这一行将取expression1的值,如果条件为真,否则将采取expression2的值。
这个语法允许我们写:
>>> print("Average = %s"%(t/n if n!
=0 else "N/A"))
来替代
if n!
=0:
print("Average = %s"%(t/n))
else:
print("Average = N/A")
———————————————————————————————
4.2For循环
这种控制结构使代码被重复执行,并同时保有一个可迭代的对象(注:
最常见的可迭代的对象是:
列表,元组,字符串和字典。
文件和定制的对象,也可迭代的。
)的值的变量。
一个for循环的一般形式是
for VAR in ITERABLE:
BLOCK
在迭代量ITERABLE后有冒号。
这是强制性的,作为缩进的代码块,是for循环的一部分。
这种结构的结果是导致BLOCK和在迭代的对象的元素数目一样多的次数的重复。
在每次迭代中,VAR需要取ITERABLE在当前元素的值。
在下面的代码中,for通过一个列表(bases)遍历四个元素。
在每次迭代中,x的值是列表中的元素之一。
>>> bases = ["C","T","G","A"]
>>> for x in bases:
... print(x)
...
C
T
G
A
在其他语言中,for循环是用来控制一个代码块运行的次数,同时改变一个计数器变量。
这种行为可以在Python通过迭代一个数字的列表被重建:
>>> for x in [0,1,2,3]:
... print(str(x)+"*"+str(x)+" = "+str(x*x))
...
0*0 = 0
1*1 = 1
2*2 = 4
3*3 = 9
生成列表的快捷方式是通过使用内置的功能range(n)。
此函数返回与第一个输入参数一样多的元素列表(注:
所有的内置函数在D.6,页494中介绍),
>>>forxinrange(4):
... printstr(x)+"*"+str(x)+"="+str(x*x)
...
0*0=0
1*1=1
2*2=4
3*3=9
下面的代码是基于单个氨基酸计算蛋白质的分子量。
(注:
氨基酸是蛋白质的组成部分。
每个氨基酸(由字母代表)都有一个分子量。
因为每个氨基酸键脱掉一个水(水分子量是18),脱去水的分子量被总量中减去。
)因为氨基酸是在一个字符串中,该程序将使用for通过每个字母遍历,
———————————————————————————————
列表4.8:
用for计算蛋白质的分子量(py3.us/2)
1protseq=raw_input("Enteryourproteinsequence:
")
2protweight={"A":
89,"V":
117,"L":
131,"I":
131,"P":
115,"F":
165,
3 "W":
204,"M":
149,"G":
75,"S":
105,"C":
121,"T":
119,
4 "Y":
181,"N":
132,"Q":
146,"D":
133,"E":
147,
5 "K":
146,"R":
174,"H":
155}
6totalW=0
7foraainprotseq:
8 totalW=totalW+protweight.get(aa.upper(),0)
9totalW=totalW-(18*(len(protseq)-1))
10print("Thenetweightis:
"+str(totalW))
——————————————————————————————
代码解释:
在第一行要求用户输入蛋白质序列(例如MKTFVLHIFIFALVAF)。
由raw_input返回的字符串被命名为protseq。
从第2行至5行,让氨基酸分子量字典(protweight)初始化。
在第7行使用一个for循环来遍历每个protseq元素。
在每次迭代中,aa从protseq从取一个元素的值,这个值是用来搜索protweight字典的。
一个周期后,totalW最终得到所有氨基酸的重量的总和。
在第9行进行一个修正,是基于这样的事实,每个键涉及一个水分子(分子量18)的损失。
最后一行打印出的净重量。
——————————————————————————————
4.3While循环
这个循环非常类似for循环,因为它也是在以反复的方式执行代码部分。
在这里,没有一个迭代的对象,这个循环不会以迭代遍历对象方式结束,而是通过给定一个条件是不真时结束。
while循环模型如下:
whileEXPRESSION:
BLOCK
考虑到在块内应该有一条指令使条件为假,这是非常重要的,否则,可能会进入一个无限循环:
>>>a=10
>>>whilea<40:
... print(a)
... a=a+10
...
10
20
30
退出while循环的一种方法是使用break。
在这种情况下,没有计算循环条件就使循环中断了。
break经常被用来结合一个总是可以为真的条件:
>>>a=10
>>>whileTrue:
... ifa<40:
... printa
... else:
... break
... a+=10
...
10
20
30
这样做是为了确保至少执行一次循环内的程序块。
在其他语言中有单独为这种情况设计的循环类型(dowhile),但它目前在Python不存在。
(注:
有一个建议是添加这种结构到Python中,见文档PEP-315(http:
//www.python.org/dev/peps/pep-0315),但它没有实施的日期,因此不要依赖于这个结构。
)
——————————————————————————————
4.4Break:
中断循环
Break是用来摆脱一个循环结构的。
我们已经看到的在while中用法的例子,但它也可以应用于for循环。
起初并不容易认识到使用break语句实际上是有意义的。
举个例子,代码4.9
——————————————————————————————
列表4.9:
在一列元组中搜索一个值
1cc=[(’red’,1),(’green’,2),(’blue’,3),(’black’,4)]
2name=’blue’
3forcolorpairincc:
4 ifname==colorpair[0]:
5 code=colorpair[1]
6printcode
——————————————————————————————
在这段代码中有一个for循环遍历cc列表。
对于每个元素,也就是说,每个元组,会检查它的第一个元素。
当它符合我们的查询(name),程序代码存储到相关的值到code,所以这个程序的输出只是“3”。
这个程序的问题是,即使我们不需要,整个序列被遍历了。
在这种情形下,在第4行的条件对cc中的每个元素一次评估时,很显然,一旦匹配是阳性的,就没有必要继续测试。
你可以通过在阳性匹配后中断循环,来节省一些时间和处理能力:
——————————————————————————————
列表4.10:
在一列元组中搜索一个值
1cc=[(’red’,1),(’green’,2),(’blue’,3),(’black’,4)]
2name=’blue’
3forcolorpairincc:
4 ifname==colorpair[0]:
5 code=colorpair[1]
6 break
7printcode
——————————————————————————————
此代码与4.9是相同的,除在第6行的break语句。
输出是像以前一样,但这个时候你不需要浪费CPU周期没有理由地迭代一个序列。
在这个例子中保存的时间是微不足道的,但如果程序有一个大的列表或文件(你也可以遍历文件)需要遍历几次,break可以显著地加快它的运行了。
break的使用是可以被避免的,但生成的代码也不是如程序4.10那么清晰可辨:
——————————————————————————————
列表4.11:
在一列元组中搜索一个值
1cc=[(’red’,1),(’green’,2),(’blue’,3),(’black’,4)]
2name=’blue’
3i=0
4whilename!
=cc[i][0]:
5 i+=1
6code=cc[i][1]
7printcode
____________________________________________________________
在这个例子中,列表可以很容易地被装入内存,更好的主意是创建一个字典来查询它:
——————————————————————————————
列表4.11:
用字典在一列元组中搜索一个值
1cc=[(’red’,1),(’green’,2),(’blue’,3),(’black’,4)]
2name=’blue’
3cc_d=dict(cc)
4printcc_d[name]
——————————————————————————————
4.5总结在一起
把if,for,while和现在看到的数据结构结合在一起,在这里,我展示一些用我们刚刚学到的工具写的小程序:
4.5.1估计一种蛋白质的净电荷
在一个固定的pH值下,可以通过把单个氨基酸的电荷加起来,计算蛋白质的净电荷。
这是一个近似值,因为它没有考虑到暴露或埋藏在蛋白质结构下的氨基酸。
它还没有考虑到半胱氨酸只有当它不是一个二硫键的一部分时才添加电荷这一事实。
因为它是一个近似的值,所以获得的值应被视为一种估计。
这里是第一个版本的protnetcharge.py:
——————————————————————————————
列表4.13:
一种蛋白质的净电荷(py3.us/3)
1 protseq = raw_input("Enter protein sequence:
")
2 charge = -0.002
3 AACharge = {"C":
-.045,"D":
-.999,"E":
-.998,"H":
.091,
4 "K":
1,"R":
1,"Y":
-.001}
5 for aa in protseq:
6 if aa in AACharge:
7