第九節 函數 函數就是完成特定功能的一個語句組,這組語句可以作為一個單位使用,並且給它取一個名字。 可以通過函數名在程式的不同地方多次執行(這通常叫做函數調用),卻不需要在所有地方都重覆編寫這些語句。 自定義函數 用戶自己編寫的 預定義的Python函數 系統自帶的一些函數,還有一些和第三方編寫的函 ...
第九節 函數
函數就是完成特定功能的一個語句組,這組語句可以作為一個單位使用,並且給它取一個名字。
可以通過函數名在程式的不同地方多次執行(這通常叫做函數調用),卻不需要在所有地方都重覆編寫這些語句。
自定義函數
- 用戶自己編寫的
預定義的Python函數
- 系統自帶的一些函數,還有一些和第三方編寫的函數,如其他程式員編寫的一些函數,對於這些現成的函數用戶可以直接拿來使用。
為什麼使用函數
- 降低編程的難度
- 通常將一個複雜的大問題分解成一系列更簡單的小問題,然後將小問題繼續劃分成更小的問題,當問題細化為足夠簡單時,我們將可以分而治之。這時,我們可以使用函數來處理特定的問題,各個小問題解決了,大問題也就迎刃而解了。
- 代碼重用
- 我們定義的函數可以在一個程式的多個位置使用,也可以用於多個程式。此外,我們還可以把函數放到一個模塊中供其他程式員使用,同時,我們也可以使用其他程式定義的函數。這就避免了重覆勞動,提供了工作效率。
函數定義和調用
當我們自己定義一個函數時,通常使用def語句,其語法形式如下所示:
def 函數名 (參數列表): #可以沒有參數函數體 def add(a, b): print a + b
調用函數的一般形式是:
函數名(參數列表) add(1, 2)
形式參數和實際參數
在定義函數時函數後面圓括弧中的變數名稱叫做“形式參數”,或簡稱為“形參”
在調用函數時,函數名後面圓括弧中的變數名稱叫做“實際參數”,或簡稱為“實參”
預設參數(預設參數)
預設參數只能從右至左給定,如果需要第一個參數給預設值,其他參數不給,那麼把第一個參數移到最後一個即可。
def add(a, b = 2): print a + b add(3) #result : 5
局部變數和全局變數
Python中的任何變數都有其特定的作用域。
在函數中定義的變數一般只能在該函數內部使用,這些只能在程式的特定部分使用的變數我們稱之為局部變數。
在一個文件頂部定義的變數可以供該文件中的任何函數調用,這些可以為整個程式所使用的變數稱為全局變數。
x = 100 #全局變數,可以在文件任何地方調用 def func(): x = 200 #局部變數,只能在函數內部調用 print x func() #輸出200 print x #輸出100
global語句
強制聲明為全局變數
x = 100 def func(): global x #強制聲明x為全局變數,導致值被覆蓋 x = 200 func() print x #輸出200
函數返回值
函數被調用後會返回一個指定的值
函數調用後預設返回None
return返回值
返回值可以是任意類型
return執行後,函數終止
區分返回值和列印
def add(a, b): return a + b ret = add(1, 2) #將函數返回結果賦值給變數ret print ret #輸出3
向函數傳入元組和字典
func (*args)
def func(x, y): print x, y t = (1, 2) func(*t)
func (**kw)
def func(name='jack', age=30): print name,age d = {'age': 22, 'name' : 'mike'}; func(**d)
處理多餘實參
def func(*args, **kw)
def func(x, *args, **kw): print x print args print kw func(1, 2, 3, 4, 5, y=10, z=20) #輸出 1 (2, 3, 4, 5) {'y': 10, 'z': 20}
lambda表達式
- 匿名函數
lambda函數是一種快速定義單行的最小函數,是從Lisp借用來的,可以用在任何需要函數的地方。
lambda x,y:x*y
- 使用Python寫一些執行腳本時,使用lambda可以省去定義函數的過程,讓代碼更加精簡。
- 對於一些抽象的,不會別的地方再復用的函數,有時候給函數起個名字也是個難題,使用lambda不需要考慮命名的問題。
使用lambda在某些時候讓代碼更容易理解。
lambda基礎
lambda語句中,冒號前是參數,可以有多個,用逗號隔開,冒號右邊的返回值。lambda語句構建的其實是一個函數對象
g = lambda x:x**2 print g <function <lambda> at 0x0000000002643A58>
lambda應用實例
reduce為逐次操作list里的每項,接收的參數為2個,最後返回的為一個結果。
sum = reduce(lambda x,y:x*y, range(1,6)) print sum
switch語句
- switch語句用於編寫多分支結構的程式,類似與if...elif...else語句。
- switch語句表達的分支結構比if...elif...else語句表達的更清晰,代碼的可讀性更高。
- 但是python並沒有提供switch語句
switch實現
- python可以通過字典實現switch語句的功能。
- 實現方法分為兩步
- 首先,定義一個字典
- 其次,調用字典的get()獲取相應的表達式
函數調用
通過字典調用函數
def add(a, b): return a + b def sub(a, b): return a - b def mul(a, b): return a * b def div(a, b): return a / b operator = {'+': add, '-': sub, '*': mul, '/': div} #通過字典實現switch語句的功能 def calc(a, o, b): return operator.get(o)(a, b) print calc(4, '+', 2) print calc(4, '-', 2) print calc(4, '*', 2) print calc(4, '/', 2)
第十節 內置函數
help函數可以用來查看函數的用法
help(range)
#輸出結果
Help on built-in function range in module __builtin__:
range(...)
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers
Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
These are exactly the valid indices for a list of 4 elements.
常用函數
abs(number)
: 絕對值max(iterable[, key=func])
: 最大值min(iterable[, key=func])
: 最小值len(collection)
: 取得一個序列或集合的長度divmod(x, y)
: 求兩個數的商和模,返回一個元組(x//y, x%y)pow(x, y[, z])
: 求一個數的冪運算round(number[, ndigits])
: 對一個數進行指定精度的四捨五入callable(object)
: 判斷一個對象是否可調用isinstance(object, class-or-type-or-tuple)
:判斷對象是否為某個類的實例cmp(x, y)
: 比較兩個數或字元串大小range(start [,stop, step])
: 返回一個範圍數組,如range(3), 返回[0,1,2]xrange(start [,stop, step])
: 作用與range相同,但是返回一個xrange生成器,當生成範圍較大的數組時,用它性能較高
類型轉換函數
type()
type(object) -> the object's type type(name, bases, dict) -> a new type
int()
int(x=0) -> int or long int(x, base=10) -> int or long
long()
long(x=0) -> long long(x, base=10) -> long
float()
float(x) -> floating point number
complex()
complex(real[, imag]) -> complex number
str()
str(object='') -> string
list()
list() -> new empty list list(iterable) -> new list initialized from iterable's items
tuple()
tuple() -> empty tuple tuple(iterable) -> tuple initialized from iterable's items
hex()
hex(number) -> string
oct()
oct(number) -> string
chr()
chr(i) -> character
ord()
ord(c) -> integer
string函數
str.capitalize()
>>> s = "hello" >>> s.capitalize() 'Hello'
str.replace()
>>> s = "hello" >>> s.replace('h', 'H') 'Hello'
str.split()
>>> ip = "192.168.1.123" >>> ip.split('.') ['192', '168', '1', '123']
序列處理函數
len()
>>>l = range(10) >>> len(l) 10
max()
>>>l = range(10) >>> max(l) 9
min()
>>>l = range(10) >>> min(l) 0
filter()
>>>l = range(10) >>> filter(lambda x: x>5, l) [6, 7, 8, 9]
zip()
>>> name=['bob','jack','mike'] >>> age=[20,21,22] >>> tel=[131,132] >>> zip(name, age) [('bob', 20), ('jack', 21), ('mike', 22)] >>> zip(name,age,tel) [('bob', 20, 131), ('jack', 21, 132)] #如果個數不匹配會被忽略
map()
>>> map(None, name, age) [('bob', 20), ('jack', 21), ('mike', 22)] >>> map(None, name, age, tel) [('bob', 20, 131), ('jack', 21, 132), ('mike', 22, None)] #個數不匹配時,沒有值的會被None代替 >>> a = [1,3,5] >>> b = [2,4,6] >>> map(lambda x,y:x*y, a, b) [2, 12, 30]
reduce()
>>> reduce(lambda x,y:x+y, range(1,101)) 5050
lambda -> 列表表達式
map的例子,可以寫成
print map(lambda x:x*2+10, range(1,11)) print [x*2+10 for x in range(1,11)]
非常的簡潔,易懂。filter的例子可以寫成:
print filter(lambda x:x%3==0, range(1,11)) print [x for x in range(1,11) if x%3 == 0]
第十一節 模塊
簡介
- 模塊是python組織代碼的基本方式
- python的腳本都是用擴展名為py的文本文件保存的,一個腳本可以單獨運行,也可以導入另一個腳本中運行。當腳本被導入運行時,我們將其稱為模塊(module)
包
- python的模塊可以按目錄組織為包
- 創建一個包的步驟是:
- 建立一個名字為包名字的文件夾
- 在該文件夾下創建一個
__init__.py
文件 - 根據需要在該文件夾下存放腳本文件、已編譯擴展及子包
import pack.m1, pack.m2, pack.m3
模塊
- 模塊名與腳本的文件名相同
- 例如我們編寫了一個名為
items.py
的腳本,則可在另外一個腳本中用import items
語句來導入它
- 例如我們編寫了一個名為
總結
- 模塊是一個可以導入的python腳本文件
- 包是一堆目錄組織的模塊和子包,目錄下的
__init__.py
文件存放了包的信息 可以用
import, import as, from import
等語句導入模塊和包#假設有一個模塊名為calc.py import calc import calc as calculate from calc import add
第十二節 正則表達式
目標
- 掌握正則表達式的規則
案例
- 一個小爬蟲
簡介
- 正則表達式(或re)是一種小型的、高度專業化的編程語言,(在python中)它內嵌在python中,並通過re模塊實現
- 可以為想要匹配的相應字元串集指定規則
- 該字元集可能包含英文語句、e-mail地址、命令或任何你想搞定的東西
- 可以問諸如“這個字元串匹配該模式嗎”
- “在這個字元串中是否有部分匹配該模式呢?”
- 你也可以使用re以各種試來修改或分割字元串
- 正則表達式模式被編譯成一系列的位元組碼,然後由C編寫的匹配引擎執行
- 正則表達式語言相對小型和受限(功能有限)
- 並非所有字元串處理都能用正則表達式完成
字元匹配
- 普通字元
- 大多數字母和數字一般都會和自身匹配
- 如正則表達式test會和字元串"test"完全匹配
元字元
. ^ $ * + ? {} [] \ | ()
[]
- 常用來指定一個字元集:
[abc] [a-z]
- 元字元在字元集中不起作用:
[akm$]
補集匹配不在區間範圍內的字元:
[^5]
import re regExp = r't[0-9]p' print re.findall(regExp, 't1p t2p')
- 常用來指定一個字元集:
^
- 匹配行首。除非設置MULTILINE標誌,它只是匹配字元串的開始。在MULTILINE模式里,它也可以匹配字元串中的每個換行。
$
- 匹配行尾,行尾被定義為要麼是字元串尾,要麼是一個換行字元後面的任何位置。
\
- 反斜杠後面可以加不同的字元以表示不同特殊意義
也可以用於取消所有的元字元:
\[
或\\
\d 匹配任何十進位數,它相當於[0-9] \D 匹配任何非數字字元,它相當於[^0-9] \s 匹配任何空白字元,它相當於[\t\n\r\f\v] \S 匹配任何非空白字元,它相當於[^\t\n\r\f\v] \w 匹配任何字母數字字元,它相當於[a-zA-Z0-9] \W 匹配任何非字母數字字元,它相當於[^a-zA-Z0-9]
- 重覆
- 正則表達式第一功能是能夠匹配不定長的字元集,另一個功能就是可以指定正則表達式的一部分的重覆次數。
*
- 指定前一個字元可能被匹配零次或更多次,而不是只有一次。匹配引擎會試著重覆儘可能多的次數(不超過整數界定範圍,20億)
+
- 表示匹配一次或更多次
- 註意和+之間的不同:匹配零或更多次,所以可以根本不出現,而+則要求至少出現一次
?
- 匹配一次或零次,你可以認為它用於標識某事物是可選的
{m,n}
- 其中
m
和n
是十進位整數。該限定符的意思是至少有m個重覆,至多到n個重覆 - 忽略m會認為下邊界是0,而忽略n的結果將是上邊界為無窮大(實現上是20億)
{0,}
等同於*
,{1,}
等同於+
,而{0,1}
則與?
相同。如果可以的話,最好使用*
,+
或?
- 其中
使用正則表達式
re
模塊提供了一個正則表達式引擎的介面,可以讓你將REstring編譯成對象並用它們來進行匹配編譯正則表達式
>>> import re >>> p = re.compile('ab*') >>> print p <_sre.SRE_Pattern object at 0x00000000004D1CA8>
re.compile()
也可以接受可選擇的標誌參數,常用來實現不同的特殊功能和語法變更p = re.compile('ab*', re.IGNORECASE)
反斜杠的麻煩
字元串前加
"r"
反斜杠就不會被任何特殊方式處理字元 階段 \section 要匹配的字元串 \\section 為re.compile取消反斜杠的特殊意義 "\\\\section" 為"\\section"的字元串實值(string literals)取消反斜杠的特殊意義
執行匹配
'RegexObject'實例有一些方法和屬性,完整的列表可查閱Python Library Reference
方法/屬性 作用 match() 決定RE是否在字元串剛開始的位置匹配 search() 掃描字元串,找到這個RE匹配的位置 findall() 找到RE匹配的所有子串,並把它們作為一個列表返回 finditer() 找到RE匹配的所有子串,並把它們作為一個迭代器返回 如果沒有匹配到的話,match()和search()將返回None。 如果成功的話,就會返回一個'MatchObject'實例。
MatchObject實例方法
方法/屬性 作用 group() 返回被RE匹配的字元串 start() 返回匹配開始的位置 end() 返回匹配結束的位置 span() 返回一個元組包含匹配(開始,結束)的位置
實際程式中,最常見的作法是將'MatchObject'保存在一個變數里,然後檢查它是否為None
p = re.compile('ab*', re.I) m = p.match('aaaabcccccabcc') if m: print 'Match found : ', m.group() else: print 'No match'
模塊級函數
- re模塊也提供了頂級函數調用如
match()、search()、sub()、subn()、split()、findall()
等 - 查看模塊的所有屬性和方法:
dir(re)
編譯標誌-flags
標誌 含義
DOTALL, S 使.匹配包括換行在內的所有字元
IGNORECASE, I 使匹配對大小寫不敏感
LOCALE, L 做本地化識別(local-aware)匹配.法語等
MULTILINE, M 多行匹配,影響^和$
VERBOSE, X 能夠使用REs的verbose狀態,使之被組織得更清晰易懂
charref = re.compile(r"""
(
[0-9]+[^0-9] #Decimal form
| 0[0-7]+[^0-7] #Octal form
| x[0-9a-fA-F]+[^0-9a-fA-F] #Hexadecimal form
)
""", re.VERBOSE)
分組()
email = r"\w+@\w+(\.com|\.cn)"
一個小爬蟲
下載貼吧或空間中所有圖片
import re import urllib def getHtml(url): page = urllib.urlopen(url) html = page.read() return html def getImg(html): reg = r'src="(.*?\.jpg)" width' imgre = re.compile(reg) imglist = re.findall(imgre, html) x = 0 for imgurl in imglist: urllib.urlretrieve(imgurl, '%s.jpg' % x) x++ getImg(getHtml(url))
第十三章 python對記憶體的使用
淺拷貝和深拷貝
- 所謂淺拷貝就是對引用的拷貝(只拷貝父對象)
- 所謂深拷貝就是對對象的資源的拷貝
解釋一個例子:
import copy a = [1,2,3,['a','b','c']] b = a c = copy.copy(a) d = copy.deepcopy(a)
第十四章 文件與目錄
目標
- 文件的打開和創建
- 文件讀取
- 文件寫入
- 內容查找和替換
- 文件刪除、複製、重命名
- 目錄操作
案例
- 目錄分析器
- 殺毒軟體
- 系統垃圾清理工具
python文件讀寫
- python進行文件讀寫的函數是
open
或file
file_handle = open(filename, mode)
模式 | 說明 |
---|---|
r | 只讀 |
r+ | 讀寫 |
w | 寫入,先刪除原文件,在重新寫入,如果文件沒有則創建 |
w+ | 讀寫,先刪除原文件,在重新寫入,如果文件沒有則創建(可以寫入輸出) |
a | 寫入,在文件末尾追加新的內容,文件不存在,創建之 |
a+ | 讀寫,在文件末尾追加新的內容,文件不存在,創建之 |
b | 打開二進位文件。可以與r、w、a、+結合使用 |
U | 支持所有的換行符號。"\r"、"\n"、"\r\n" |
文件對象方法
- close
- 格式
FileObject.close()
- 說明
- 關閉文件,關閉前,會將緩存中的數據先寫入文件。
- 格式
- readline
- 格式
String = FileObject.readline([size])
- 說明
- 每次讀取文件的一行
- size:是指每行每次讀取size個位元組,直到行的末尾
- 格式
- readlines
- 格式
List = FileObject.readlines([size])
- 說明
- 多行讀,返回一個列表
- size: 每次讀入size個字元,然後繼續按size讀,而不是每次讀入行的size個字元
- 格式
- read
- 格式
String = FileObject.read([size])
- 說明
- 讀出文件的所有內容,並複製給一個字元串
- size: 讀出文件的前[size]個字元,並輸出給字元串,此時文件的指針指向size處
- 格式
- next
- 格式
FileObject.next()
- 說明
- 返回當前行,並將文件指針到下一行
- 格式
- write
- 格式
FileObject.write(string)
- 說明
- write和後面的writelines在寫入前會是否清除文件中原來所有的數據,在重新寫入新的內容,取決於打開文件的模式
- 格式
- writelines
- 格式
FileObject.writelines(List)
- 說明
- 多行寫
- 效率比write高,速度更快,少量寫入可以使用write
- 格式
- seek
- 格式
FileObject.seek(偏移量,選項)
- 說明
- 選項=0時,表示將文件指針指向從文件頭部到“偏移量”位元組處。
- 選項=1時,表示將文件指針指向從文件的當前位置,向向移動“偏移量”位元組。
- 選項=2時,表示將文件指針指向從文件的尾部,向前移動“偏移量”位元組。
- 格式
- flush
- 格式
FileObject.flush()
- 說明
- 提交更新
- 格式
文件查找和替換
- 文件查找
cat a.txt
hello world hello hello world
統計文件中hello的個數
import re fp = file("a.txt", "r") count = 0 for s in fp.readlines(): li = re.findall("hello", s) if len(li) > 0: count = count + len(li) print "Search ",count," hello" fp.close()
- 文件內容替換
- 問題:把a.txt中的hello替換為good, 並保存結果到b.txt中
示例代碼一:
fp1 = file("a.txt", "r") fp2 = file("b.txt", "w") for s in fp1.readlines(): fp2.write(s.replace("hello", "good")) fp1.close() fp2.close()
示例代碼二:
fp1 = file("a.txt", "r") fp2 = file("b.txt", "w") s = fp1.read() fp2.write(s.replace("hello", "good")) fp1.close() fp2.close()
目錄操作
- 目錄操作就是通過python來實現目錄的創建,修改,遍歷等功能
import os
- 目錄操作需要調用os模塊
- 比如
os.mkdir('/root/demo')
- 常用函數
函數 | 說明 |
---|---|
mkdir(path[,mode=0777]) | 創建單個目錄 |
makedirs(name,mode=511) | 創建多層級目錄 |
rmdir(path) | 刪除單個目錄 |
removedirs(path) | 刪除多層級目錄 |
listdir(path) | 列出目錄 |
getcwd() | 取得當前目錄 |
chdir(path) | 切換目錄 |
walk(top, topdown=True, onerror=None) |
- 案例
- 系統垃圾清除小工具
- 方式
- 遞歸函數
os.walk()
函數- 函數聲明:
os.walk(path)
該函數返回一個元組,該元組有3個元素,這3個元素分別表示每次遍歷的路徑名,目錄列表和文件列表。
for path, dirlist, filelist in os.walk('.'): for filename in filelist: print os.path.join(path, filename)
- 函數聲明:
第十五章 異常處理
異常以及異常拋出
異常拋出機制,為程式開發人員提供了一種在運行時發現錯誤,進行恢復處理,然後繼續執行的能力。下麵是一個異常處理實例:
try: f = open('unfile.py', 'r') except IOError, e: print False,str(e) False [Errno 2] No such file or directory: 'unfile.py'
拋出機制
- 如果在運行時發生異常的話,解釋器會查找相應的處理語句(稱為handler)。
- 要是在當前函數里沒有找到的話,它會將異常傳遞給上層的調用函數,看看那裡能不能處理。
- 如果在最外層(全局“main”)還是沒有找到的話,解釋器就會退出,同時列印出traceback以便讓用戶找出錯誤產生的原因。
- 註意:雖然大多數錯誤會導致異常,但一個異常不一定代表錯誤。有時候它們只是一個警告,有時候它們可能是一個終止信號,比如退出迴圈等。
finally子句
python提供try-finally子句來表述這樣的情況:我們不關心捕捉到是什麼錯誤,無論錯誤是不是發生,這些代碼“必須”運行,比如文件關閉,釋放鎖,把資料庫連接還給連接池等。比如:
try: f = open('unfile.py', 'r') except Exception, e: print False,str(e) finally: print "exec finally"
raise拋出異常
- 到目前為止,我們只討論瞭如何捕捉異常,那麼如何拋出異常?
使用raise來拋出一個異常:
if 'a' > 5: raise TypeError("Error: 'a' must be integer.")
常見的python異常
異常 | 描述 |
---|---|
AssertionError | assert語句失敗 |
AttributeError | 試圖訪問一個對象沒有的屬性 |
IOError | 輸入輸出異常,基本是無法打開文件 |
ImportError | 無法引入模塊或者包,基本是路徑問題 |
IndentationError | 語法錯誤,代碼沒有正確的對齊 |
IndexError | 下標索引超出序列邊界 |
KeyError | 試圖訪問你字典里不存在的鍵 |
KeyBoardInterrupt | Ctrl+C被按下 |
NameError | 使用一個還未賦予對象的變數 |
SyntaxError | python代碼邏輯語法出錯,不能執行 |
TypeError | 傳入的對象類型與要求不符 |
UnboundLocalError | 試圖訪問一個還未設置的全局變數,基本上是由於另有一個同名的全局變數,導致你以為在訪問 |
ValueError | 傳入一個不被期望的值,即使類型正確 |