Python文件
Python程序保存為文件以.py結(jié)尾爷狈,一個簡單的例子:
#!/usr/bin/python
#Filename: helloworld.py
print('Hello World')
.py文件能不能像.exe文件那樣直接運行呢锌云?在Windows上是不行的坡椒,但是就缆,在Mac和Linux上是可以的帖渠,方法是在.py文件的第一行加上一個特殊的注釋:
#!/usr/bin/env python3
ps:此處指定為python3的可執(zhí)行程序,python 3版本沒有向前兼容竭宰。
然后空郊,通過命令給hello.py以執(zhí)行權(quán)限:
$ chmod a+x hello.py
就可以直接運行hello.py了。
幫助
在 Python 中切揭,如果你想得到任何關(guān)于函數(shù)或語句的快速信息幫助狞甚,就可以使用內(nèi)置的 help 函數(shù):
>>> help(print)
注意是在Python交互模式下輸入,可以通過在命令行模式下敲命令python3就進(jìn)入到Python交互模式廓旬,它的提示符是>>>
哼审。
不想看時,按 q 來退出幫助孕豹。
如果你需要得到關(guān)于類似 return 操作符的幫助涩盾,需要在內(nèi)部加上引號, >>> help('return')
巩步, 這樣 Python 就能理解你到底想干什么旁赊。
輸入輸出
- 輸出
使用print方法,例如:
>>> print('hello, world')
help獲取到的信息:
print(...)
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
- 輸入
使用input方法椅野,例如:
>>> input('請輸入信息:')
help獲取到的信息:
input(prompt=None, /)
Read a string from standard input. The trailing newline is stripped.
The prompt string, if given, is printed to standard output without a
trailing newline before reading input.
If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
On *nix systems, readline is used if available.
基礎(chǔ)語法
以#
開頭的語句是注釋终畅,注釋是給人看的籍胯,可以是任意內(nèi)容,解釋器會忽略掉注釋离福。其他每一行都是一個語句杖狼,當(dāng)語句以冒號:
結(jié)尾時,縮進(jìn)的語句視為代碼塊妖爷。
Python程序是大小寫敏感的蝶涩,如果寫錯了大小寫,程序會報錯絮识。
變量
變量是標(biāo)識符的例子绿聘。標(biāo)識符是用來標(biāo)識某樣?xùn)|西的名字。在命名標(biāo)識符的時候次舌,你要遵循這些規(guī)則:
標(biāo)識符的第一個字符必須是字母表中的字母(大寫或小寫)或者一個下劃線
_
熄攘。標(biāo)識符名稱的其他部分可以由字母(大寫或小寫)、下劃線
_
或數(shù)字0-9
組成彼念。標(biāo)識符名稱是對大小寫敏感的挪圾。例如,
myname
和myName
不是一個標(biāo)識符逐沙。注意前者中的小寫n
和后者中的大寫N
哲思。有效標(biāo)識符名稱的例子有
i
、__my_name
吩案、name_23
和a1b2_c3
棚赔。無效標(biāo)識符名稱的例子:
2things
、this is spaced out
和my-name
徘郭。
邏輯行和物理行
物理行是你在編寫程序時所看見的忆嗜。邏輯行是 Python 看見的單個語句。 Python 假 定每個物理行對應(yīng)一個邏輯行崎岂。
邏輯行的例子如 print ’Hello World’
這樣的語句 —— 如果它本身就是一行(就像 你在編輯器中看到的那樣),那么它也是一個物理行闪湾。
默認(rèn)地冲甘, Python 希望每行都只使用一個語句,這樣使得代碼更加易讀途样。
如果你想要在一個物理行中使用多于一個邏輯行江醇,那么你需要使用分號;
來 特別地標(biāo)明這種用法。分號表示一個邏輯行/語句的結(jié)束何暇。(但是并不建議這樣寫)
僅僅當(dāng)邏輯行太長的時候陶夜, 在多于一個物理行寫一個邏輯行,可以在一行末尾添加\
表示邏輯行并沒有結(jié)束:
print \
i
縮進(jìn)
在 Python 中空白非常重要裆站。實際上条辟,在每行開頭的空白很重要黔夭。稱之為縮進(jìn)。 在行首的主要的空白(空格鍵和制表符)用來決定邏輯行縮進(jìn)的層次羽嫡,從而來決定語 句分組本姥。
這意味著同一層次的語句必須有相同的縮進(jìn)。每一組這樣的語句稱為一個塊杭棵。
你需要記住的一樣?xùn)|西是錯誤的縮進(jìn)會引發(fā)錯誤婚惫。例如:
i=5
print('Value is ', i) # Error! Notice a single space at the start of the line
print('I repeat, the value is ', i)
當(dāng)你運行的時候,會得到下面的出錯信息:
File "whitespace.py", line 4
print('Value is ', i) # Error! Notice a single space at the start
of the line ^
IndentationError: unexpected indent
注意在第二行的開頭有一個空格魂爪。Python 給出的錯誤信息告訴我們程序的語法不正確先舷。
不要混合使用制表符和空格來縮進(jìn),因為這在跨越不同的平臺的時候滓侍,無法正常工作蒋川,推薦使用4個空格的縮進(jìn)。
給靜態(tài)語言程序員的注釋:
Python 總是使用縮進(jìn)來代表代碼塊粗井,不再使用括號尔破。
數(shù)據(jù)類型
在 Python 中數(shù)的類型有三種 —— 整數(shù)、浮點數(shù)和復(fù)數(shù)浇衬。
- 2是一個整數(shù)的例子懒构。
- 3.23 和 52.3E-4 是浮點數(shù)的例子。 E 標(biāo)記表示 10 的冪耘擂。在這里胆剧,2.3E-4 表示 52.3 * 10?4。
- (-5+4j)和(2.3-4.6j)是復(fù)數(shù)的例子醉冤。
給有經(jīng)驗的程序員的注釋:
在 Python 中不用區(qū)分'long int'類型秩霍。默認(rèn)的整數(shù)類型可以任意長。
字符串
Python中默認(rèn)所有的字符串的編碼是 Unicode蚁阳。沒有僅僅使用 ASCII 的字符串铃绒,原因是 Unicode 是 ASCII 的超集。如果要嚴(yán)格使用 ASCII 編碼的 字節(jié)流螺捐,可用 str.encode("ascii") 颠悬。
如果你寫的文本基本上全部是英文的話,用Unicode編碼比ASCII編碼需要多一倍的存儲空間定血,在存儲和傳輸上就十分不劃算赔癌。因此通常會使用UTF-8編碼,可以通過如下方式聲明.py文件的編碼:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
對于不清楚什么UTF-8的同學(xué)可以看下:ASCII澜沟、Unicode和UTF-8的關(guān)系
- 單引號
你可以用單引號指定字符串灾票,如 ’Quote me on this’ 。所有的空白茫虽,即空格和制表符都照原樣保留刊苍。
- 雙引號
在雙引號中的字符串與單引號中的字符串的使用完全相同既们,例如 "What’s yourname?" 。
- 三引號
利用三引號("""or”’)班缰,你可以指示一個多行的字符串贤壁。你可以在三引號中自由 的使用單引號和雙引號。例如:
'''This is a multi-line string. This is the first line.
This is the second line.
"What's your name?," I asked.
He said "Bond, James Bond."
'''
- 轉(zhuǎn)義序列
假如你有一個字符串包含單引號’
埠忘,如何表示這個字符串呢?例如脾拆,字符串是What’s your name?
。你不能用 ’What’s your name?’
來表示莹妒,因為 Python 不知道字符串的起始和結(jié)束位置名船。所以應(yīng)該將字符串中間的這個單引號指定為不表示字符串的結(jié)束。這可在稱之為轉(zhuǎn)義序列的協(xié)助下實現(xiàn)旨怠∏眨可以講單引號指定為 \'
—— 注意反斜杠。現(xiàn)在鉴腻,就能將字符串表示為 ’What\’s your name?’
迷扇。
還有一種方式就是用雙引號"What’s your name?"
。類似地爽哎,在用雙引號的字符串 中用雙引號必須用轉(zhuǎn)義符蜓席。還有,必須用轉(zhuǎn)義符\\
來表示反斜杠课锌。
如果你想指定兩行字符串厨内,該如何做呢?一種方式就是用前面提到的用三引號的 字符串碰逸,或者可以用轉(zhuǎn)義符\n
表示新的一行的開始琅拌。例如 This is the first line\nThis is the second line 。
另外一個有用的轉(zhuǎn)義字符是Tab鍵 ——\t
宪祥。有許多轉(zhuǎn)義序列志鞍,這兒僅僅提到了最有用的幾個瞭亮。
需要說明的是,在一個字符串中固棚,在一行末尾的反斜杠僅僅表示下一行的字符串是上一行的繼續(xù)街州,但并不增加新的行。例如:
"This is the first sentence.\
This is the second sentence."
與"This is the first sentence. This is the second sentence."
等價玻孟。
- 自然字符串
如果你想指定一些不被特殊處理,例如像轉(zhuǎn)義序列鳍征,那么黍翎,就需要通過在字符 串前面附加 r 或 R 來指定自然字符串。
給有經(jīng)驗的程序員的注釋:
在 Python 中沒有單獨的 char 數(shù)據(jù)類型艳丛。
記住單引號和雙引號是一樣的 —— 沒有絲毫差異匣掸。
用正則表達(dá)式的時候請使用自然字符串趟紊。否則,可能會用到許多反斜杠碰酝。例如霎匈,后向引用符可以寫成’\\1’
或r’\1’
。
格式化
- 使用
%
>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'
%
運算符就是用來格式化字符串的送爸。在字符串內(nèi)部铛嘱,%s
表示用字符串替換,%d
表示用整數(shù)替換袭厂,有幾個%?
占位符墨吓,后面就跟幾個變量或者值,順序要對應(yīng)好纹磺。如果只有一個%?
帖烘,括號可以省略。
常見的占位符有:
占位符 | 替換內(nèi)容 |
---|---|
%d | 整數(shù) |
%f | 浮點數(shù) |
%s | 字符串 |
%x | 十六進(jìn)制整數(shù) |
其中橄杨,格式化整數(shù)和浮點數(shù)還可以指定是否補0和整數(shù)與小數(shù)的位數(shù):
>>> print('%2d-%02d' % (3, 1))
3-01
>>> print('%.2f' % 3.1415926)
3.14
>>>
如果你不太確定應(yīng)該用什么秘症,%s
永遠(yuǎn)起作用,它會把任何數(shù)據(jù)類型轉(zhuǎn)換為字符串式矫。
有些時候乡摹,字符串里面的%
是一個普通字符怎么辦?這個時候就需要轉(zhuǎn)義衷佃,用%%
來表示一個%
:
>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'
- 使用format()
>>> print('{0} is {1} years old'.format('makey', 12))
makey is 12 years old
>>> '{0:.3}'.format(1/3) # decimal (.) precision of 3 for float
'0.333'
>>> '{0:_^11}'.format('hello') # fill with underscores (_) with the text centered (^) to 11 width
'___hello___'
>>> '{name} wrote {book}'.format(name='Swaroop', book='A Byte of Python') # keyword-based
'Swaroop wrote A Byte of Python'
操作符
操作符 | 解釋 | 示例 |
---|---|---|
+ | 兩數(shù)相加或者字符串拼接 | 3 + 5 gives 8. ’a’ + ’b’ gives ’ab’. |
- | 表示負(fù)數(shù)或者兩數(shù)相減 | -5.2 gives a negative number. 50 - 24 gives 26. |
* | 乘法或者復(fù)制字符串 | 2 * 3 gives 6. ’la’ * 3 gives ’lalala’. |
** | 次方 | 3 ** 4 gives 81 (i.e. 3 * 3 * 3 * 3 ) |
/ | 除法 | 4 / 3 gives 1.333333333333. |
// | 除法之后的整數(shù)部分 | 4 // 3 gives 1. |
% | 整除后的剩余部分 | 8 % 3 gives 2. -25.5 % 2.25 gives 1.5. |
<< | 位運算 | 2 << 2 gives 8. 2 is represented by 10 in bits. left shifting by 2 bits gives 1000 which represents the decimal 8. |
>> | 位運算 | 11 >> 1 gives 5. 11 is represented in bits by 1011 which when right shifted by 1 bit gives 101 which is the decimal 5. |
& | 按位與 | 5 & 3 gives 1. |
| | 按位或 | 5 | 3 gives 7 |
^ | 異或 | 5 ? 3 gives 6 |
~ | The bit-wise inversion of x is -(x+1) | ~5 gives -6 |
<, <= , == , != ,>, >= | 比較 | |
not | 非 | 相當(dāng)于java中的 !true. x = True; not x returns False. |
and | 邏輯與 | 相當(dāng)于java中的&& |
or | 邏輯或 | 相當(dāng)于java中|| |
控制流
if 語句
if 語句用來檢驗一個條件趟卸,如果條件為真,我們運行一塊語句(稱為 if-塊)氏义,否 則我們處理另外一塊語句(稱為 else-塊)锄列。當(dāng)然,還有elif 用于判斷另一個條件惯悠, elif 和 else 部分是可選的邻邮。
if <條件判斷1>:
<執(zhí)行1>
elif <條件判斷2>:
<執(zhí)行2>
elif <條件判斷3>:
<執(zhí)行3>
else:
<執(zhí)行4>
while 語句
只要在一個條件為真的情況下, while 語句允許你重復(fù)執(zhí)行一塊語句克婶。 while 語 句是所謂循環(huán)語句的一個例子筒严。 while 語句有一個可選的 else 從句。
# !/usr/bin/python3
# Filename while.py
number = 23
running = True
while running:
guess=int(input("Enter an integer:"))
if guess == number:
print("Congratulation, you guessed it.")
running=False #this causes the while loop to stop
elif guess < number:
print("No, it is a little higher.")
else:
print("No, it is a little lower.")
else:
print("the while loop is over.")
# Do anything else you want to do here
print("done")
輸出:
$ python3 while.py
Enter an integer : 50
No, it is a little lower than that.
Enter an integer : 22
No, it is a little higher than that.
Enter an integer : 23
Congratulations, you guessed it.
The while loop is over.
Done
當(dāng) while 循環(huán)的條件為假時 —— 這或許在第一次檢查條件的時候情萤。如果 while 循 環(huán)有 else 從句鸭蛙,當(dāng)不滿足條件時else塊會觸發(fā),除非你的 while 循環(huán)將永遠(yuǎn)循環(huán)下去不會結(jié)束!
for 循環(huán)
for..in 是另外一個循環(huán)語句筋岛,它在一序列的對象上迭代娶视,即逐一使用序列中的每 個項目。
for i in range(1, 5):
print (i)
else :
print ( 'The for loop is over' )
range 返回一個序列的數(shù)。這個序列從第一個數(shù)開 始到第二個數(shù)為止肪获。例如寝凌, range(1,5) 給出序列 [1, 2, 3, 4]。默認(rèn)地孝赫, range 的步長 為 1较木。如果我們?yōu)?range 提供第三個數(shù),那么它將成為步長青柄。例如伐债,range(1,5,2) 給出 [1,3]。記住刹前,range 向上延伸到第二個數(shù)泳赋,即它不包含第二個數(shù)。
for 循環(huán)在這個范圍內(nèi)遞歸 ——for i in range(1,5) 等價于 for i in [1, 2, 3, 4]喇喉,這就 如同把序列中的每個數(shù)(或?qū)ο?賦值給 i 祖今,一次一個,然后以每個 i 的值執(zhí)行這個 程序塊拣技。在這個例子中千诬,我們只是打印 i 的值。
給有經(jīng)驗的程序員的注釋:
記得 Python中的循環(huán)可以有 else 語句膏斤,但是如果循環(huán)中觸發(fā)break則else不會執(zhí)行徐绑。
break
break 語句是用來終止循環(huán)語句的,即哪怕循環(huán)條件沒有變?yōu)?False 或序列還沒有 被完全迭代結(jié)束莫辨,也停止執(zhí)行循環(huán)語句傲茄。
一個重要的注釋是,如果你從 for 或 while 循環(huán)中終止沮榜,任何對應(yīng)的循環(huán) else 塊 將不執(zhí)行盘榨。
continue
continue 語句被用來告訴 Python 跳過當(dāng)前循環(huán)塊中的剩余語句,然后繼續(xù)進(jìn)行下 一輪循環(huán)蟆融。
數(shù)據(jù)結(jié)構(gòu)
list
Python內(nèi)置的一種數(shù)據(jù)類型是列表:list草巡。list是一種有序的集合,可以隨時添加和刪除其中的元素型酥。
比如山憨,列出班里所有同學(xué)的名字,就可以用一個list表示:
>>> classmates = ['Michael', 'Bob', 'Tracy']
>>> classmates
['Michael', 'Bob', 'Tracy']
變量classmates就是一個list弥喉。用len()函數(shù)可以獲得list元素的個數(shù):
>>> len(classmates)
3
用索引來訪問list中每一個位置的元素郁竟,記得索引是從0開始的:
>>> classmates[0]
'Michael'
>>> classmates[1]
'Bob'
>>> classmates[2]
'Tracy'
>>> classmates[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
當(dāng)索引超出了范圍時,Python會報一個IndexError錯誤由境,所以枪孩,要確保索引不要越界,記得最后一個元素的索引是len(classmates) - 1。
如果要取最后一個元素蔑舞,除了計算索引位置外,還可以用-1做索引嘹屯,直接獲取最后一個元素:
>>> classmates[-1]
'Tracy'
以此類推攻询,可以獲取倒數(shù)第2個、倒數(shù)第3個:
>>> classmates[-2]
'Bob'
>>> classmates[-3]
'Michael'
>>> classmates[-4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
當(dāng)然州弟,倒數(shù)第4個就越界了钧栖。
list是一個可變的有序表,所以婆翔,可以往list中追加元素到末尾:
>>> classmates.append('Adam')
>>> classmates
['Michael', 'Bob', 'Tracy', 'Adam']
也可以把元素插入到指定的位置拯杠,比如索引號為1的位置:
>>> classmates.insert(1, 'Jack')
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
要刪除list末尾的元素,用pop()方法:
>>> classmates.pop()
'Adam'
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy']
要刪除指定位置的元素啃奴,用pop(i)方法潭陪,其中i是索引位置:
>>> classmates.pop(1)
'Jack'
>>> classmates
['Michael', 'Bob', 'Tracy']
要把某個元素替換成別的元素,可以直接賦值給對應(yīng)的索引位置:
>>> classmates[1] = 'Sarah'
>>> classmates
['Michael', 'Sarah', 'Tracy']
list里面的元素的數(shù)據(jù)類型也可以不同最蕾,比如:
>>> L = ['Apple', 123, True]
list元素也可以是另一個list依溯,比如:
>>> s = ['python', 'java', ['asp', 'php'], 'scheme']
>>> len(s)
4
要注意s只有4個元素,其中s[2]又是一個list瘟则,如果拆開寫就更容易理解了:
>>> p = ['asp', 'php']
>>> s = ['python', 'java', p, 'scheme']
要拿到'php'可以寫p[1]或者s[2][1]黎炉,因此s可以看成是一個二維數(shù)組,類似的還有三維醋拧、四維……數(shù)組慷嗜,不過很少用到。
如果一個list中一個元素也沒有丹壕,就是一個空的list庆械,它的長度為0:
>>> L = []
>>> len(L)
0
tuple(元組)
另一種有序列表叫元組:tuple。tuple和list非常類似雀费,但是tuple一旦初始化就不能修改干奢,比如同樣是列出同學(xué)的名字:
>>> classmates = ('Michael', 'Bob', 'Tracy')
現(xiàn)在,classmates這個tuple不能變了盏袄,它也沒有append()
忿峻,insert()
這樣的方法。其他獲取元素的方法和list是一樣的辕羽,你可以正常地使用classmates[0]
逛尚,classmates[-1]
,但不能賦值成另外的元素刁愿。
不可變的tuple有什么意義绰寞?因為tuple不可變,所以代碼更安全。如果可能滤钱,能用tuple代替list就盡量用tuple觉壶。
tuple的陷阱:當(dāng)你定義一個tuple時,在定義的時候件缸,tuple的元素就必須被確定下來铜靶,比如:
>>> t = (1, 2)
>>> t
(1, 2)
如果要定義一個空的tuple,可以寫成():
>>> t = ()
>>> t
()
但是他炊,要定義一個只有1個元素的tuple争剿,如果你這么定義:
>>> t = (1)
>>> t
1
定義的不是tuple,是1這個數(shù)痊末!這是因為括號()既可以表示tuple蚕苇,又可以表示數(shù)學(xué)公式中的小括號,這就產(chǎn)生了歧義凿叠,因此涩笤,Python規(guī)定,這種情況下幔嫂,按小括號進(jìn)行計算辆它,計算結(jié)果自然是1。
所以履恩,只有1個元素的tuple定義時必須加一個逗號,锰茉,來消除歧義:
>>> t = (1,)
>>> t
(1,)
Python在顯示只有1個元素的tuple時,也會加一個逗號,
切心,以免你誤解成數(shù)學(xué)計算意義上的括號飒筑。
最后來看一個“可變的”tuple:
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])
這個tuple定義的時候有3個元素,分別是a
绽昏,b
和一個list协屡。不是說tuple一旦定義后就不可變了嗎?怎么后來又變了全谤?
表面上看肤晓,tuple的元素確實變了,但其實變的不是tuple的元素认然,而是list的元素补憾。tuple一開始指向的list并沒有改成別的list,所以卷员,tuple所謂的“不變”是說盈匾,tuple的每個元素,指向永遠(yuǎn)不變毕骡。即指向a
削饵,就不能改成指向b
岩瘦,指向一個list,就不能改成指向其他對象窿撬,但指向的這個list本身是可變的启昧!
理解了“指向不變”后,要創(chuàng)建一個內(nèi)容也不變的tuple怎么做劈伴?那就必須保證tuple的每一個元素本身也不能變箫津。
dict
Python內(nèi)置了字典:dict的支持,dict全稱dictionary宰啦,在其他語言中也稱為map,使用鍵-值(key-value)存儲饼拍,具有極快的查找速度赡模。
舉個例子,假設(shè)要根據(jù)同學(xué)的名字查找對應(yīng)的成績,用Python寫一個dict如下:
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
把數(shù)據(jù)放入dict的方法师抄,除了初始化時指定外漓柑,還可以通過key放入:
>>> d['Adam'] = 67
>>> d['Adam']
67
由于一個key只能對應(yīng)一個value,所以叨吮,多次對一個key放入value辆布,后面的值會把前面的值沖掉:
>>> d['Jack'] = 90
>>> d['Jack']
90
>>> d['Jack'] = 88
>>> d['Jack']
88
如果key不存在,dict就會報錯:
>>> d['Thomas']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Thomas'
要避免key不存在的錯誤茶鉴,有兩種辦法锋玲,一是通過in判斷key是否存在:
>>> 'Thomas' in d
False
二是通過dict提供的get()
方法,如果key不存在涵叮,可以返回None
惭蹂,或者自己指定的value:
>>> d.get('Thomas')
>>> d.get('Thomas', -1)
-1
注意:返回None
的時候Python的交互環(huán)境不顯示結(jié)果。
要刪除一個key割粮,用pop(key)方法盾碗,對應(yīng)的value也會從dict中刪除:
>>> d.pop('Bob')
75
>>> d
{'Michael': 95, 'Tracy': 85}
請務(wù)必注意,dict內(nèi)部存放的順序和key放入的順序是沒有關(guān)系的舀瓢。
和list比較廷雅,dict有以下幾個特點:
查找和插入的速度極快,不會隨著key的增加而變慢京髓;
需要占用大量的內(nèi)存航缀,內(nèi)存浪費多。
而list相反:
查找和插入的時間隨著元素的增加而增加朵锣;
占用空間小谬盐,浪費內(nèi)存很少。
所以诚些,dict是用空間來換取時間的一種方法飞傀。
dict可以用在需要高速查找的很多地方皇型,在Python代碼中幾乎無處不在,正確使用dict非常重要砸烦,需要牢記的第一條就是dict的key必須是不可變對象弃鸦。
這是因為dict根據(jù)key來計算value的存儲位置,如果每次計算相同的key得出的結(jié)果不同幢痘,那dict內(nèi)部就完全混亂了唬格。這個通過key計算位置的算法稱為哈希算法(Hash)。
要保證hash的正確性颜说,作為key的對象就不能變购岗。在Python中,字符串门粪、整數(shù)等都是不可變的喊积,因此,可以放心地作為key玄妈。而list是可變的乾吻,就不能作為key:
>>> key = [1, 2, 3]
>>> d[key] = 'a list'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
set
set和dict類似,也是一組key的集合拟蜻,但不存儲value绎签。由于key不能重復(fù),所以酝锅,在set中诡必,沒有重復(fù)的key。
要創(chuàng)建一個set屈张,需要提供一個list作為輸入集合:
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}
注意擒权,傳入的參數(shù)[1, 2, 3]
是一個list,而顯示的{1, 2, 3}
只是告訴你這個set內(nèi)部有1阁谆,2碳抄,3這3個元素,顯示的順序也不表示set是有序的场绿。剖效。
重復(fù)元素在set中自動被過濾:
>>> s = set([1, 1, 2, 2, 3, 3])
>>> s
{1, 2, 3}
通過add(key)方法可以添加元素到set中,可以重復(fù)添加焰盗,但不會有效果:
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}
通過remove(key)方法可以刪除元素:
>>> s.remove(4)
>>> s
{1, 2, 3}
set可以看成數(shù)學(xué)意義上的無序和無重復(fù)元素的集合璧尸,因此,兩個set可以做數(shù)學(xué)意義上的交集熬拒、并集等操作:
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
{2, 3}
>>> s1 | s2
{1, 2, 3, 4}
set和dict的唯一區(qū)別僅在于沒有存儲對應(yīng)的value爷光,但是,set的原理和dict一樣澎粟,所以蛀序,同樣不可以放入可變對象欢瞪,因為無法判斷兩個可變對象是否相等,也就無法保證set內(nèi)部“不會有重復(fù)元素”徐裸。
切片 Slice
取一個list或tuple的部分元素是非常常見的操作遣鼓,Python提供了切片(Slice)操作符,能大大簡化這種操作重贺。
>>> L[0:3]
['Michael', 'Sarah', 'Tracy']
L[0:3]
表示骑祟,從索引0開始取,直到索引3為止气笙,但不包括索引3次企。即索引0,1潜圃,2抒巢,正好是3個元素。
如果第一個索引是0秉犹,還可以省略:
>>> L[:3]
['Michael', 'Sarah', 'Tracy']
也可以從索引1開始,取出2個元素出來:
>>> L[1:3]
['Sarah', 'Tracy']
類似的稚晚,既然Python支持L[-1]
取倒數(shù)第一個元素崇堵,那么它同樣支持倒數(shù)切片,試試:
>>> L[-2:]
['Bob', 'Jack']
>>> L[-2:-1]
['Bob']
記住倒數(shù)第一個元素的索引是-1客燕。
中括號中什么都不寫鸳劳,只寫[:]
就可以原樣復(fù)制一個list。
你也可以給切片規(guī)定第三個參數(shù)也搓,就是切片的步長(默認(rèn)步長是 1)赏廓。
>>> shoplist = ['apple', 'mango', 'carrot', 'banana']
>>> shoplist[::1]
['apple', 'mango', 'carrot', 'banana']
>>> shoplist[::2]
['apple', 'carrot']
>>> shoplist[::3]
['apple', 'banana']
>>> shoplist[::-1]
['banana', 'carrot', 'mango', 'apple']
注意當(dāng)步長是 2 時,我們得到在位置 0,2,... 的項傍妒,當(dāng)步長是 3 時幔摸,得到位置 0,3, 等等的項。
切片操作同樣可以作用于tuple(元組)和str(字符串)
列表生成式
列表生成式即List Comprehensions颤练,是Python內(nèi)置的非常簡單卻強大的可以用來創(chuàng)建list的生成式既忆。
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
還可以使用兩層循環(huán),可以生成全排列:
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
列表生成式也可以使用兩個變量來生成list:
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']
最后把一個list中所有的字符串變成小寫:
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
生成器
函數(shù)
函數(shù)是重用的程序段嗦玖。它們允許你給一個語句塊一個名稱患雇,然后你用這個名字可 以在你的程序的任何地方,任意多次地運行這個語句塊宇挫。這被稱為調(diào)用函數(shù)苛吱。
實際上之前我們一直在調(diào)用函數(shù),例如:
>>> print('abc')
函數(shù)名其實就是指向一個函數(shù)對象的引用器瘪,完全可以把函數(shù)名賦給一個變量翠储,相當(dāng)于給這個函數(shù)起了一個“別名”:
>>> a = abs # 變量a指向abs函數(shù)
>>> a(-1) # 所以也可以通過a調(diào)用abs函數(shù)
1
定義
函數(shù)用關(guān)鍵字 def 來定義绘雁。def
關(guān)鍵字后跟一個函數(shù)的標(biāo)識符名稱,然后跟一對圓括號()
彰亥。圓括號之中可以包括一些變量名咧七,該行以冒號:
結(jié)尾。接下來是一塊語句任斋,它們是函數(shù)體继阻。下面這個例子將說明這事實上是十分簡單的:
#!/usr/bin/python3
# Filename: function1.py
def sayHello():
print('Hello World!') # block belonging to the function # End of function
sayHello() # call the function
sayHello() # call the function again
參數(shù)
函數(shù)取得的參數(shù)是你提供給函數(shù)的值,這樣函數(shù)就可以利用這些值做一些事情废酷。 這些參數(shù)就像變量一樣瘟檩,只不過它們的值是在我們調(diào)用函數(shù)的時候定義的,而非在函 數(shù)本身內(nèi)賦值澈蟆。
參數(shù)在函數(shù)定義的圓括號對內(nèi)指定墨辛,用逗號分割。當(dāng)我們調(diào)用函數(shù)的時候趴俘,我們 以同樣的方式提供值睹簇。注意我們使用過的術(shù)語 —— 函數(shù)中的參數(shù)名稱為形參而你提 供給函數(shù)調(diào)用的值稱為實參。
局部變量
當(dāng)你在函數(shù)定義內(nèi)聲明變量的時候寥闪,它們與函數(shù)外具有相同名稱的其他變量沒有任何關(guān)系太惠,即變量名稱對于函數(shù)來說是局部的。這稱為變量的作用域疲憋。所有變量的作用域是它們被定義的塊凿渊,從它們的名稱被定義的那點開始。
#!/usr/bin/python3
# Filename: func_local.py
x = 50
def func(x):
print('x is', x)
x=2
print('Changed local x to', x)
func(x)
print('x is still', x)
輸出:
$ python3 func_local.py
x is 50
Changed local x to 2
x is still 50
在函數(shù)中缚柳,我們第一次使用x
的值的時候埃脏, Python 使用函數(shù)聲明的形參的值。 接下來秋忙,我們把值 2
賦給x
彩掐。 x
是函數(shù)的局部變量。所以灰追,當(dāng)我們在函數(shù)內(nèi)改
變 x
的值的時候佩谷,在主塊中定義的 x
不受影響。在最后一個 print
語句中监嗜,我們證明 了主塊中的x
的值確實沒有受到影響谐檀。
使用全局語句
如果你想要為一個定義在函數(shù)外的變量賦值,那么你就得告訴 Python 這個變量 名不是局部的裁奇,而是全局的桐猬。我們使用 global
語句完成這一功能。沒有 global
語句刽肠, 是不可能為定義在函數(shù)外的變量賦值的溃肪。
你可以使用定義在函數(shù)外的變量的值(假設(shè)在函數(shù)內(nèi)沒有同名的變量)免胃。然而, 我并不鼓勵你這樣做惫撰,并且你應(yīng)該盡量避免這樣做羔沙,因為這使得程序的讀者會不清楚 這個變量是在哪里定義的。使用global
語句可以清楚地表明變量是在外面的塊定義的厨钻。
#!/usr/bin/python
#Filename: func_global.py
x = 50
def func():
global x
print('x is',x)
x=2
print('Changed global x to',x)
func()
print('Value of x is',x)
輸出:
$ python func_global.py
x is 50
Changed global x to 2
Value of x is 2
global
語句被用來聲明x
是全局的 —— 因此扼雏,當(dāng)我們在函數(shù)內(nèi)把值賦給 x
的時 候,這個變化也反映在我們在主塊中使用x
的值的時候夯膀。
你可以使用同一個 global
語句指定多個全局變量诗充。例如global x, y, z
。
使用非局部語句
上面給出了如何在局部和全局作用域內(nèi)使用變量诱建。還有一種作用域叫做“非局 部”域蝴蜓,處于這兩種作用域之間。
非局部作用域在你定義函數(shù)內(nèi)的函數(shù)時會看到俺猿。
由于在 Python 中茎匠,任何事物是可執(zhí)行的代碼,你可以在任何地方定義函數(shù)押袍。
#!/usr/bin/python3
# Filename: func_nonlocal.py
def func_outer():
x=2
print('x is',x)
def func_inner():
nonlocal x
x=5
func_inner()
print('Changed local x to',x)
func_outer()
輸出:
$ python3 func_nonlocal.py
x is 2
Changed local x to 5
當(dāng)在函數(shù) func_inner
的內(nèi)部時汽抚,在函數(shù) func_outer
的第一行定義的 x
相對來講 既不是在局部范圍也不是在全局的作用域中,使用這樣的 x
稱之為非局部 x
伯病,因此可以使用這個變量。
默認(rèn)參數(shù)值
對于一些函數(shù)否过,你可能希望它的一些參數(shù)是可選的午笛,如果用戶不想要為這些參數(shù) 提供值的話,這些參數(shù)就使用默認(rèn)值苗桂。這個功能借助于默認(rèn)參數(shù)值完成药磺。你可以在函 數(shù)定義的形參名后加上賦值運算符=
和默認(rèn)值,從而給形參指定默認(rèn)參數(shù)值煤伟。
#!/usr/bin/python3
# Filename: func_default.py
def say(message, times = 1):
print(message * times)
say('Hello')
say('World', 5)
輸出:
$ python3 func_default.py
Hello
WorldWorldWorldWorldWorld
名為say
的函數(shù)用來打印一個字符串任意所需的次數(shù)癌佩。如果我們不提供一個值, 那么默認(rèn)地便锨,字符串將只被打印一遍围辙。我們通過給形參 times
指定默認(rèn)參數(shù)值 1 來實 現(xiàn)這一功能。
只有在形參表末尾的那些參數(shù)可以有默認(rèn)參數(shù)值放案,即你不能在聲明函數(shù)形參的時候姚建,先聲明有默 認(rèn)值的形參而后聲明沒有默認(rèn)值的形參。這是因為賦給形參的值是根據(jù)位置而賦值的吱殉。例如掸冤,def func(a, b=5) 是有效的厘托,但是 def func (a=5, b) 是無效的。
默認(rèn)參數(shù)很有用稿湿,但使用不當(dāng)铅匹,也會掉坑里。默認(rèn)參數(shù)有個最大的坑饺藤,演示如下:
先定義一個函數(shù)包斑,傳入一個list,添加一個END再返回:
def add_end(L=[]):
L.append('END')
return L
當(dāng)你正常調(diào)用時策精,結(jié)果似乎不錯:
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']
當(dāng)你使用默認(rèn)參數(shù)調(diào)用時裆装,一開始結(jié)果也是對的:
>>> add_end()
['END']
但是,再次調(diào)用add_end()時上枕,結(jié)果就不對了:
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
默認(rèn)參數(shù)是[]盅视,但是函數(shù)似乎每次都“記住了”上次添加了'END'后的list。
原因解釋如下:
Python函數(shù)在定義的時候询刹,默認(rèn)參數(shù)L
的值就被計算出來了谜嫉,即[]
,因為默認(rèn)參數(shù)L
也是一個變量凹联,它指向?qū)ο?code>[]沐兰,每次調(diào)用該函數(shù),如果改變了L的內(nèi)容蔽挠,則下次調(diào)用時住闯,默認(rèn)參數(shù)的內(nèi)容就變了,不再是函數(shù)定義時的[]
了澳淑。
定義默認(rèn)參數(shù)要牢記一點:默認(rèn)參數(shù)必須指向不變對象比原!
要修改上面的例子,我們可以用None這個不變對象來實現(xiàn):
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
現(xiàn)在杠巡,無論調(diào)用多少次量窘,都不會有問題:
>>> add_end()
['END']
>>> add_end()
['END']
為什么要設(shè)計str
、None
這樣的不變對象呢氢拥?因為不變對象一旦創(chuàng)建蚌铜,對象內(nèi)部的數(shù)據(jù)就不能修改,這樣就減少了由于修改數(shù)據(jù)導(dǎo)致的錯誤嫩海。此外冬殃,由于對象不變,多任務(wù)環(huán)境下同時讀取對象不需要加鎖叁怪,同時讀一點問題都沒有造壮。我們在編寫程序時,如果可以設(shè)計一個不變對象,那就盡量設(shè)計成不變對象耳璧。
關(guān)鍵參數(shù)
如果你的某個函數(shù)有許多參數(shù)成箫,而你只想指定其中的一部分,那么你可以通過命 名來為這些參數(shù)賦值 —— 這被稱作關(guān)鍵參數(shù) —— 我們使用名字(關(guān)鍵字)而不是位 置(我們前面所一直使用的方法)來給函數(shù)指定實參旨枯。
這樣做有兩個優(yōu)勢 ——
一蹬昌、由于我們不必?fù)?dān)心參數(shù)的順序,使用函數(shù)變得更加 簡單了攀隔。
二皂贩、假設(shè)其他參數(shù)都有默認(rèn)值,我們可以只給我們想要的那些參數(shù)賦值昆汹。
#!/usr/bin/python3
# Filename: func_key.py
def func(a, b=5, c=10):
print('a is', a, 'and b is', b, 'and c is', c)
func(3, 7)
func(25, c=24)
func(c=50, a=100)
輸出:
$ python3 func_key.py
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50
VarArgs 參數(shù)
有時明刷,你或許想定義一個能獲取任意個數(shù)參數(shù)的函數(shù),這可通過使用*
號來實現(xiàn)满粗。
#!/usr/bin/python3
# Filename: total.py
def total(initial=5, *numbers, **keywords):
count = initial
for number in numbers:
count += number
for key in keywords:
count += keywords[key]
return count
print(total(10, 1, 2, 3, vegetables=50, fruits=100))
輸出:
$ python3 total.py
166
當(dāng)我們定義一個帶星的參數(shù)辈末,像*param
時,從那一點后所有的參數(shù)被收集為一 個叫做 ’param’ 的元組(tuple)映皆。在該例中挤聘,首先會給initial
的值由 5 變成 10 , 然后numbers
將 1,2,3捅彻,收集作為一個元組numbers=(1,2,3)
组去。
類似地,當(dāng)我們定義一個帶兩個星的參數(shù)步淹,像**param
時从隆,從那一點開始的 所有的關(guān)鍵字參數(shù)會被收集為一個叫做 ’param’ 的字典(dict)。在該例子中缭裆, 從 vegetables=50
后的所有參數(shù)收集為一個字典 keywords=’vegetables’: 50, ’fruits’: 100
键闺。
如果已經(jīng)有一個list或者tuple,要調(diào)用一個可變參數(shù)怎么辦幼驶?可以這樣做:
>>> nums = [1, 2, 3]
>>> calc(nums[0], nums[1], nums[2])
14
這種寫法當(dāng)然是可行的,問題是太繁瑣韧衣,所以Python允許你在list或tuple前面加一個*
號盅藻,把list或tuple的元素變成可變參數(shù)傳進(jìn)去:
>>> nums = [1, 2, 3]
>>> calc(*nums)
14
*nums
表示把nums
這個list的所有元素作為可變參數(shù)傳進(jìn)去。這種寫法相當(dāng)有用畅铭,而且很常見氏淑。
Keyword-only 參數(shù)
如果想指定特定的關(guān)鍵參數(shù)為 keyword-only 而不是位置參數(shù)(只能通過關(guān)鍵字進(jìn)行賦值),可以在帶星的參數(shù)后申明:
#!/usr/bin/python3
# Filename: keyword_only.py
def total(initial=5, *numbers, vegetables):
count = initial
for number in numbers:
count += number
count += vegetables
return count
print(total(10, 1, 2, 3, vegetables=50))
print(total(10, 1, 2, 3,))# Raises error because we have not supplied a default argument value for 'vegetables'
輸出:
$ python3 keyword_only.py
66
Traceback (most recent call last):
File "test.py", line 12, in <module>
print(total(10, 1, 2, 3))
TypeError: total() needs keyword-only argument vegetables
在帶星號的參數(shù)后面申明參數(shù)會導(dǎo)致 keyword-only 參數(shù)硕噩。如果這些參數(shù)沒有默認(rèn)值假残,且像上面那樣不給關(guān)鍵參數(shù)賦值,調(diào)用函數(shù)的時候會引發(fā)錯誤。
如果你想使用 keyword-only 參數(shù)辉懒,但又不需要帶星的參數(shù)阳惹,可以簡單地使用不適 用名字的空星,如 def total(initial=5, *, vegetables):
眶俩。
參數(shù)組合
在Python中定義函數(shù)莹汤,可以用必選參數(shù)、默認(rèn)參數(shù)颠印、可變參數(shù)纲岭、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù),這5種參數(shù)都可以組合使用线罕。但是請注意止潮,參數(shù)定義的順序必須是:必選參數(shù)、默認(rèn)參數(shù)钞楼、可變參數(shù)喇闸、命名關(guān)鍵字參數(shù)和關(guān)鍵字參數(shù)。
return 語句
return
語句用來從一個函數(shù)返回即跳出函數(shù)窿凤。我們也可選是否從函數(shù)返回一個值仅偎。
沒有返回值的 return
語句等 價于 return None
。 None
是 Python 中表示沒有任何東西的特殊類型雳殊。例如橘沥,如果一 個變量的值為 None
,可以表示它沒有值夯秃。除非你提供你自己的 return
語句座咆,每個函 數(shù)都在結(jié)尾暗含有 return None
語句。通過運行 print(someFunction())
仓洼,你可以明白這 一點介陶,函數(shù) someFunction
沒有使用 return
語句,如同:
def someFunction():
pass
pass
語句在 Python 中表示一個空的語句塊色建。
pass
語句什么都不做哺呜,那有什么用?實際上pass
可以用來作為占位符箕戳,比如現(xiàn)在還沒想好怎么寫函數(shù)的代碼某残,就可以先放一個pass
,讓代碼能運行起來陵吸。
返回多個值
函數(shù)可以返回多個值嗎玻墅?答案是肯定的。
比如在游戲中經(jīng)常需要從一個點移動到另一個點壮虫,給出坐標(biāo)澳厢、位移和角度,就可以計算出新的新的坐標(biāo):
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
import math
語句表示導(dǎo)入math
包,并允許后續(xù)代碼引用math
包里的sin
剩拢、cos
等函數(shù)线得。
然后,我們就可以同時獲得返回值:
>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print(x, y)
151.96152422706632 70.0
實際上返回值是一個tuple裸扶!但是框都,在語法上,返回一個tuple可以省略括號呵晨,而多個變量可以同時接收一個tuple魏保,按位置賦給對應(yīng)的值,所以摸屠,Python的函數(shù)返回多值其實就是返回一個tuple谓罗,但寫起來更方便。
DocStrings
Python 有一個很奇妙的特性季二,稱為文檔字符串檩咱,它通常被簡稱為 docstrings 。 DocStrings 是一個重要的工具胯舷,由于它幫助你的程序文檔更加簡單易懂刻蚯,你應(yīng)該盡量 使用它。你甚至可以在程序運行的時候桑嘶,從函數(shù)恢復(fù)文檔字符串!
#!/usr/bin/python3
# Filename: func_doc.py
def printMax(x, y):
'''Prints the maximum of two numbers.
The two values must be integers.'''
x = int(x) # convert to integers, if possible
y = int(y)
if x > y:
print(x, 'is maximum')
else:
print(y, 'is maximum')
printMax(3, 5)
print(printMax.__doc__)
輸出:
$ python3 func_doc.py
5 is maximum
Prints the maximum of two numbers.
The two values must be integers.
在函數(shù)的第一個邏輯行的字符串是這個函數(shù)的文檔字符串炊汹。注意, DocStrings 也 適用于模塊和類逃顶。
文檔字符串的慣例是一個多行字符串讨便,它的首行以大寫字母開始,句號結(jié)尾以政。第二行是空行霸褒,從第三行開始是詳細(xì)的描述。強烈建議你在你的函數(shù)中使用文檔字符串時遵循這個慣例盈蛮。
你可以使用__doc__
(注意雙下劃線)調(diào)用printMax
函數(shù)的文檔字符串屬性(屬于函數(shù)的名稱)废菱。請記住 Python 把每一樣?xùn)|西都作為對象,包括這個函數(shù)抖誉。
如果你已經(jīng)在 Python 中使用過 help()
殊轴,那么你已經(jīng)看到過 DocStings 的使用了! 它所做的只是抓取函數(shù)的__doc__
屬性,然后整潔地展示給你寸五。你可以對上面這個函 數(shù)嘗試一下 —— 只是在你的程序中包括help(printMax)
梳凛。記住按 q
退出 help
耿币。
自動化工具也可以以同樣的方式從你的程序中提取文檔梳杏。因此,我強烈建議你 對你所寫的任何正式函數(shù)編寫文檔字符串。隨你的 Python 發(fā)行版附帶的 pydoc 命令十性, 與 help()
類似地使用 DocStrings 叛溢。