條件、循環、其它語句
print和import
隨着更加深入地學習python,可能會出現這種感覺:有些自以爲已經掌握的知識點,還隱藏着一些讓人驚訝的特性。
使用逗號輸出
打印多個表達式,只要將這些表達式用逗號隔開即可:
>>> print "age:",28
age: 28
參數之間都插入了一個空格符。
如果在結尾加上逗號,那麼接下來的語句會與前一條語句在同一行打印:
print "Hello,",
print "World!"
結果:
Hello, World!
把某件事作爲另一件事導入
從模塊導入函數的時候,可以使用:
import somemodule
或
from somemodule import somefunction
或
from sommodule import somefunction,anotherfunction,yetanotherfunction
或
from somemodule import *
其中,只有確定自己想要從給定的模塊導入所有功能時,才應該使用最後一個版本。
如果兩個模塊都有open函數,應該怎麼做呢?
只需使用第一種方式導入,然後像下面這樣使用函數:
module1.open(...)
module2.open(...)
但還有另外的選擇:可以在語句末尾增加一個as語句,在該子句後給出名字,或爲整個模塊提供別名:
>>> import math as foobar
>>> foobar.sqrt(4)
2.0
也可以爲函數提供別名:
>>> from math import sqrt as foobar
>>> foobar(4)
2.0
對於open函數,可以像下面這樣使用:
from module1 import open as open1
from module2 import open as open2
賦值魔法
序列解包
多個賦值操作可以同時進行:
>>> x,y,z=1,23,456
>>> print x,y,z
1 23 456
用它交換兩個(或多個)變量:
>>> x,y=y,x
>>> print x,y
23 1
>>> x,y,z=y,z,x
>>> print x,y,z
1 456 23
事實上,這裏所做的事情叫做序列解包或可迭代解包——將多個值的序列解開,然後放到變量的序列中。
>>> values=1,2,3
>>> values
(1, 2, 3)
>>> x,y,z=values
>>> print x,y,z
1 2 3
當函數或者方法返回元組(或者其他序列或可迭代對象)時,這個特性尤其有用。假設需要獲取(和刪除)字典中的任意的鍵-值對,可以使用popitem方法,這個方法將鍵值對作爲元組返回,那麼這個元組可以直接賦值到兩個變量中:
>>> people={'name':'signjing','age':'28','weight':'72'}
>>> x,y=people.popitem()
>>> print x,y
age 28
>>> x,y=people.popitem()
>>> print x,y
name signjing
>>> x,y=people.popitem()
>>> print x,y
weight 72
它允許函數返回一個以上的值並且打包成元組,然後通過一個賦值語句很容易進行訪問。所解包的序列中的元素數量必須和放置在賦值符號=左邊的變量數量完全一致,否則python會在賦值時引發異常:
>>> x,y=1,3,4
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
x,y=1,3,4
ValueError: too many values to unpack
>>> x,y,z=2,9
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
x,y,z=2,9
ValueError: need more than 2 values to unpack
鏈式賦值
鏈式賦值是將同一個值賦給多個變量的捷徑。
x=y=somefunction()
和下面語句的效果是一樣的:
y=somefunction()
x=y
注意:上面的語句和下面的語句不一定等價:
x=somefunction()
y=somefunction()
增量賦值
將表達式運算符放置在賦值運算符=的左邊,這種寫法叫做增量賦值,對於*、/、%等標準運算符都適用:
>>> x=5
>>> x+=3
>>> x*=2
>>> x/=4
>>> x
4
對於其他數據類型也適用(只要二元運算符本身適用於這些數據類型即可):
>>> s='too'
>>> s+='many'
>>> s*=2
>>> s
'toomanytoomany'
語句塊
語句塊是在條件爲真(條件語句)時執行或執行多次的一組語句。在代碼前放置空行來縮進語句即可創建語句塊。
塊中的每行都需要縮進相同的量。
很多語言使用特殊單詞或者字符(比如begin或{)來表示一個語句塊的開始,用另外的單詞或字符(如end或})表示語句塊的結束。
在python中,冒號(:)用來標識語句塊的開始,塊中的每一個語句都是縮進的(縮進量相同)。當回退到和已經閉合的塊一樣的縮進量時,就表示當前塊已經結束了。
條件和條件語句
布爾變量
下面的值在作爲布爾表達式時候,會被解釋看做假(False):
False None 0 “” () [] {}
換句話說,也就是標準值False和None、所有類型的數字0(包括浮點數、長整型和其它類型)、空序列(比如空字符串、元組和列表)以及空的字典都爲假。其它的一切都解釋爲真,包括特殊值True。
標準的真值爲True和False。事實上,True和False只不過是1和0的“華麗”說法而已。
>>> True
True
>>> False
False
>>> True==0
False
>>> True==1
True
>>> False==0
True
>>> False==1
False
>>> False+True+23
24
布爾值True和False屬於布爾類型,bool函數可以用來(和list、str以及tuple一樣)轉換其它值。
>>> bool('I think ,therefore I am')
True
>>> bool(42)
True
>>> bool(0)
False
>>> bool('')
False
>>> bool(False)
False
>>> bool(())
False
>>> bool({})
False
>>> bool([])
False
因爲所有值都可以用作布爾值,所以幾乎不需要對它們進行顯式轉換(可以說python會自動轉換這些值)。
注意:儘管[]和””都是假植(也就是說bool([])==bool(“”)==False),它們本身並不相等。對於其他不同類型的假值對象也是如此(例如,()!=False)。
條件執行和if語句
if語句可以實現條件執行,如果條件判定爲真,則後面的語句塊執行,如果條件爲假,語句塊就不會被執行。
name=raw_input("Please input a name: ")
if name.endswith("Bob"):
print "Hello,Bob!"
如果用戶輸入了以Bob結尾的名字,則打印出問候語。
else語句
else子句(之所以叫子句,是因爲它不是獨立的語句,而只能作爲if語句的一部分)可以增加一種選擇。
name=raw_input("Please input a name: ")
if name.endswith("signjing"):
print "Hello,signjing!"
else:
print "Hello,someone!"
如果第1個語句塊沒有被執行,則轉入第2個語句塊。
elif語句
如果需要檢查多個條件,就可以使用elif,它是“else if”的簡寫,也是if和else子句的聯合使用——也就是具有條件的else子句。
num=input("Please input a num: ")
if num>0:
print "num > 0"
elif num<0:
print "num < 0"
else:
print "num = 0"
嵌套代碼塊
if語句裏可以嵌套使用if語句:
num = input("Please input a num: ")
if num > 0:
if num >5:
print "num > 5"
elif num > 3:
print "num >3 and num <= 5"
else:
print "num <= 3 and num > 0"
elif num < 0:
if num < -10:
print "num < -10"
elif num < -4:
print "num < -4 and num >= -10"
else:
print "num >= -4 and num < 0"
else:
print "num = 0"
更復雜的條件
比較運算符
表達式 描述
x==y x等於y
x<y x小於y
x>y x大於y
x>=y x大於等於y
x<=y x小於等於y
x!=y x不等於y
x is y x和y是同一個對象
x is not y x和y是不同的對象
x in y x是y容器的成員
x not in y x不是y容器的成員
比較不兼容類型
理論上,對於相對大小的任意兩個對象x和y都是可以使用比較運算符比較的,並且都會得到一個布爾值結果。但是只有在x和y是相同或者近似類型的對象時,比較纔有意義。
在python中比較運算和賦值運算一樣是可以連接的——幾個運算符可以連在一起使用:
>>> a=5
>>> 0<a<8
True
>>> 0<a<3
False
>>> 0<a>3
True
相等運算符
想要知道兩個東西是否相等,應該使用相等運算符,即兩個等號==:
>>> "abc"=="abc"
True
>>> "abc"=="Abc"
False
單個相等運算符是賦值運算符,是用來改變值的,不能用來比較。
is:同一性運算符
這個運算符比較有趣,它看起來和==一樣,但事實上卻不同:
>>> x=y=[1,2,3]
>>> z=[1,2,3]
>>> x==y
True
>>> x is y
True
>>> x == z
True
>>> x is z
False
x和z相等卻不等同,因爲is運算符是判定同一性而不是相等性。
x和y被綁定到同一個列表上,而變量z被綁定在另外一個具有相同數值和順序的列表上。它們的值可能相等,但卻不是一個對象。
in:成員資格運算符
之前說明過了,此處略;
字符串和序列比較
字符串可以按照字母順序排列進行比較。
>>> "a" < "b"
True
>>> "abc" < "ab"
False
注意:實際的順序可能會因爲使用不同的locale而和上面的例子有所不同。
其他的序列也可以以相同的方式進行比較,不過比較的不是字符而是元素的其它類型:
>>> [1,2,4]>[1,2,3]
True
>>> [1,2,[2,'a']]<[1,2,[3,4]]
True
布爾運算符
and運算符,連接兩個布爾值,且在兩者都爲真時返回真,否則返回假。
or運算符,連接兩個布爾值,且在兩者都爲假時返回假,否則返回真。
not運算符,連接一個布爾值,當連接的布爾值爲真時返回假,爲假時返回真。
短路邏輯
x and y需要兩個變量都爲真時才爲真,如果x爲假,則x and y立即返回false,而不需計算y的值。同理,x or y只要有一個爲真則爲真,如果x爲真,則x or y直接返回True,而不需計算y的值。這樣,避免了無用地執行代碼,可以作爲一種技巧使用。
斷言
if語句有個非常有用的近親,其工作方式多少有點像下面這樣(僞代碼):
if not condition:
crash program
這樣做是因爲與其讓程序在晚些時候崩潰,不如在錯誤條件出現時直接讓它崩潰。一般來說,你可以要求某些條件必須爲真。語句中使用的關鍵字爲assert。
>>> age=10
>>> assert 0<age<102
>>> age=-2
>>> assert 0<age<102
Traceback (most recent call last):
File "<pyshell#39>", line 1, in <module>
assert 0<age<102
AssertionError
如果需要確保程序中的某個條件一定爲真才能讓程序正常工作的話,assert語句就有用了,可以在程序中置入檢查點:
條件後可以添加字符串(用逗號把條件和字符串隔開),用來解釋斷言:
>>> assert 0<age<102, 'make age right'
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
assert 0<age<102, 'make age right'
AssertionError: make age right
循環
while循環
用來在任何條件爲真的情況下重複執行一個代碼塊。
i=5
while i>0:
print i
i-=1
結果:
5
4
3
2
1
for循環
list1=list('signjing')
for l in list1:
print l
結果:
s
i
g
n
j
i
n
g
numbers=[1,2,3,4]
for n in numbers:
print n
結果:
1
2
3
4
迭代(循環的另一種說法)某個範圍的數字是很常見的,有個內建的函數可供使用:
for n in range(1,5):
print n
結果:
1
2
3
4
range函數的工作方式類似於分片,包含下限,不包含上限,如果希望下限爲0,則可以只提供上限。
提示:
如果能使用for循環,就儘量不使用while循環。
循環遍歷字典元素
一個簡單的for語句就能循環字典的所有鍵,就像處理序列一樣:
d={'x':1,'y':2,'z':3}
for key in d:
print key,d[key]
結果:
y 2
x 1
z 3
for循環的一大好處就是可以在循環中使用序列解包:
d={'x':1,'y':2,'z':3}
for key,value in d.items():
print key,value
結果:
y 2
x 1
z 3
一些迭代工具
在python中迭代序列(或其它可迭代對象)時,一些函數非常有用。有些函數位於itertools模塊,還有些python的內建函數也十分有用。
並行迭代
程序可以同時迭代兩個序列:
names=['anne','beth','damon']
ages=[13,19,21]
for i in range(len(names)):
print names[i],'is',ages[i],'years old.'
結果:
anne is 13 years old.
beth is 19 years old.
damon is 21 years old.
內建的zip函數可以用來進行並行迭代,把兩個序列“壓縮”在一起,然後返回一個元組的列表:
names=['anne','beth','damon']
ages=[13,19,21]
for name,age in zip(names,ages):
print name,"is",age,"years old."
結果:
anne is 13 years old.
beth is 19 years old.
damon is 21 years old.
zip函數可以作用於任意多的序列。關於它很重要的一點是zip可以應付不等長的序列:當最短的序列“用完”的時候就會停止:
>>> zip(range(5),xrange(100))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
>>> zip(range(5),xrange(2))
[(0, 0), (1, 1)]
編號迭代
有些時候想要迭代序列中的對象,同時還要獲取當前對象的索引。
暫略;
翻轉和排序迭代
reversed和sorted,同列表的reverse和sort方法類似,但作用於任何序列或可迭代對象上,不是原地修改對象,而是返回翻轉或排序後的版本:
>>> sorted([4,3,6,8,3])
[3, 3, 4, 6, 8]
>>> sorted('hello,world!')
['!', ',', 'd', 'e', 'h', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
>>> list(reversed('hello,world!'))
['!', 'd', 'l', 'r', 'o', 'w', ',', 'o', 'l', 'l', 'e', 'h']
>>> ''.join(reversed('hello,world'))
'dlrow,olleh'
跳出循環
break
結束循環可以使用break語句。
for i in range(5):
print i
if i > 2:
break
print "--"
結果:
0
--
1
--
2
--
3
continue
continue語句用的要少很多,它讓當前的迭代結束,“跳”到下一輪循環的開始。基本意思是:跳過剩餘的循環體,但不結束循環。當循環體很大而且很複雜時,會很有用。
for i in range(5):
print i
if i > 2:
continue
print "--"
結果:
0
--
1
--
2
--
3
4
while True/break習語
while True實現了一個永遠不會自己停止的循環,但在循環體內部的if語句中加入條件,在條件滿足時調用break語句。這樣,就可以在循環內部任何地方而不是隻在開頭終止循環。
儘管應該小心在代碼中頻繁使用break語句,但這個特殊的技術用得非常普遍。
循環中的else子句
當在循環體內部使用break語句時,通常是因爲找到了某物或某事發生了,在跳出時做一些事情是簡單的,但有些時候想要在沒有跳出之前做些事情。可以在循環中增加一個else語句——僅在沒有調用break時執行。
for i in range(5):
print i
if i > 6:
break
print "--"
else:
print "I'm here"
結果:
0
--
1
--
2
--
3
--
4
--
I'm here
for和while循環中都可以使用continue、break語句和else子句。
列表推導式——輕量級循環
列表推導式是利用其它列表創建新列表的一種方法。工作方式類似於for循環。
>>> [x*x for x in range(1,6)]
[1, 4, 9, 16, 25]
可以增加判斷條件:
>>> [x*x for x in range(1,6) if x%2==0 ]
[4, 16]
可以增加更多的for語句:
>>> [x*y for x in range(1,3) for y in (2,5)]
[2, 5, 4, 10]
也可以和if語句聯合使用:
>>> [x*y for x in range(1,11) for y in range(1,9) if x%3==0 if y%4==0 ]
[12, 24, 24, 48, 36, 72]
注意:for循環部分和if語句部分之間都沒有標點符號。
三人行
什麼都沒發生
有些時候,程序什麼事情都不用做:
>>> pass
>>>
name=raw_input("Please input a name: ")
if name == 'signjing':
print "I'm signjing"
elif name == 'sj':
pass
else:
print "unknown"
執行:
Please input a name: signjing
結果:
I'm signjing
執行:
Please input a name: sj
如果將pass行註釋:
if name == 'signjing':
print "I'm signjing"
elif name == 'sj':
#pass
else:
print "unknown"
執行報錯:
File "pass.py", line 6
else:
^
IndentationError: expected an indented block
使用del刪除
一般來說,python解釋器(以其無窮的智慧)自動刪除那些不再使用的對象。另一種方法是使用del語句,它不僅會移除一個對象的引用,也會移除那個名字本身。
>>> x=['hello','world']
>>> y=x
>>> y[1]='python'
>>> x
['hello', 'python']
>>> del x
>>> y
['hello', 'python']
事實上,python中是沒有辦法刪除值的,因爲值不再使用時,python解釋器會負責內存的回收。
使用exec和eval執行和求值字符串
有些時候會動態地創造python代碼,然後將其作爲語句執行或作爲表達式計算,這近似於“黑暗魔法”——在此之前,一定要慎之又慎,仔細考慮:
exec
執行一個字符串的語句是exec:
>>> exec "print 'hello'"
hello
但使用簡單形式的exec語句絕不是好事。很多時候可以給它提供命名空間——可以放變量的地方。
>>> from math import sqrt
>>> exec "sqrt = 1"
>>> sqrt(4)
Traceback (most recent call last):
File "<pyshell#70>", line 1, in <module>
sqrt(4)
TypeError: 'int' object is not callable
可以通過in <scope>來實現,其中<scope>就是起到放置代碼字符串命名空間作用的字典。
>>> from math import sqrt
>>> scope={}
>>> exec "sqrt = 1" in scope
>>> sqrt(4)
2.0
>>> scope['sqrt']
1
可見,潛在的破壞性代碼並不會覆蓋sqrt函數,原來的函數能正常工作,而通過exec賦值的變量sqrt只在它的作用域內有效。
注意,如果需要將scope打印出來的話,能看到其中包括很多東西,因爲內建的__builtins__字典自動包含所有的內建函數和值:
>>> len(scope)
2
>>> scope.keys()
['__builtins__', 'sqrt']
eval
eval(用於“求值”)是類似於exec的內建函數。
exec語句會執行一系列的python語句,而eval會計算python表達式,並返回結果值。
exec語句並不返回任何對象,因爲它本身就是語句。
>>> eval(raw_input("Enter an arithmetic expression: "))
Enter an arithmetic expression: 2*6+8
20