【python】速查手册(基础笔记) - 人生苦短,我用python
生活随笔
收集整理的這篇文章主要介紹了
【python】速查手册(基础笔记) - 人生苦短,我用python
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
python學習筆記:小甲魚python全套視頻 ?+ ?python基礎教程 第2版修訂版(書附10個大型案例)
python學習環境:(python3)win10下python3.5.4的IDLE ?+ ?ubuntu下python3輔助
python分享范圍:適合有C/C++/JAVA任意語言之一為基礎,不適合純新手入門
python語言優勢:至今還沒有一門編程語言,開發速度比Python快,運行速度比C快
python常用工具手冊:
http://bbs.fishc.com/forum.php?mod=collection&action=view&ctid=198
---------------------------------2017.08.27--------------------------------------
00丶python背景與特點
Python語言起源
在1989年末,Guido van Rossum為了打發圣誕節的無聊,創造了python(大蟒蛇)。 1991年,第一個 Python 版本誕生。最新版本是Python3 3.6.2 。Guido van Rossum 是蒙提·派森的飛行馬戲團(Monty Python‘s Flying Circus)的愛好者。logo是由兩只蟒蛇的圖形組成。
官網下載地址:
https://www.python.org/downloads/
Python 3 與 Python 2 不完全兼容
官方表示對 Python2 支持到2020年, Python2 2.7.13。Python 2 的生態庫遠遠大于 Python 3。
簡單:
學習曲線平滑, 45分鐘學會基本使用,使用簡單。
跨平臺:
一次編寫、到處運行。 Windows, Linux, Mac, Android
功能強大:
? ? 動態類型、自動內存管理
? ? 非常實用的內置對象類型
? ? 強大的內置工具和標準庫
? ? 易于擴展,很多成熟易用第三方庫
? ? 大型程序支持
應用廣泛:
? ? 數據庫、網絡、圖形圖像、科學計算、機器學習、web開發、操作系統擴展等
缺點:
運行速度不夠快(硬件的發展可以為此彌補不足)
開發速度與運行速度之間的矛盾:
至今還沒有一門編程語言,開發速度比Python快,運行速度比C快
知名軟件包:Django/Numpy/Pandas/Matplotlib/PIL (Pillow)/PyQt5/Tensorflow/Scipy/Theano/NLTK
知名項目:(網站)豆瓣/知乎/美團/Gmail/Youtube/Instagram/Calibre/……
01丶第一次親密接觸 first love
(1) win下的python IDLE集成開發環境自動縮進,table鍵補齊變量名
(2) linux下使用vi編輯.py的python文件,需要聲明 #!/usr/bin/python3
(3) python使用等量(1個tab)的縮進來嚴格對齊表示作用域
#!/usr/bin/python3
#guess game
print ("---------游戲開始-----------")
temp = input ("輸入一個我現在想的數字:")
guess = int (temp)
if guess == 8:
print ("猜對了!!!")
else:
print ("哈哈,猜錯了。。")
print ("游戲結束嘍~")
#---end---
BIF == Built-in functions(內置函數)
>>> dir(__builtins__)
..., 'input', ...
>>> help(input)
#可以查詢內置函數的說明和用法,類似于C語言的man手冊
02丶變量 variable
(1) python沒有"變量"只有"名字"
(2) 變量使用之前,需要對其先賦值
(3) 變量名命名同C的規則,不能以數字開頭,保證可讀性命名即可
(4) 大小寫敏感,區分
(5) =左右依次為左值和右值
(6) 十六進制,以0x 或 0X 開頭 ,數字由"0"到"9" 或者 "a"到"f" 或者 "A"到"F"組成
八進制,0o或0O 開頭,數字由"0" 到 "7"組成
二進制,0b或0B 開頭表示,數字由"0" 或者"1"組成
十進制由數字"0"到"9"組成,并且不能以0開頭
>>> teacher = 'jiangyuan'
>>> print (teacher)
jiangyuan
>>> teacher = 'somebody'
>>> print (teacher)
somebody
>>> first = 3
>>> second = 8
>>> third = first + second
>>> print (third)
11
>>> myteacher = 'jiangyuan'
>>> yourteacher = 'somebody'
>>> ourteacher = myteacher + yourteacher
>>> print (ourteacher)
jiangyuansomebody
03丶運算符及優先級 precedence of operator
#符合數學運算優先原則,括號最優先,最安全。
lambda lambda表達式
or 布爾或
and 布爾與
not 布爾非
in 和 not in 成員是否屬于測試
is 和 is not 對象是否是同一個
> ?>= ?< ?<= ?== ?!= 比較操作符
| 按位或
^ 按位異或
& 按位與
<< 和 >> 移位
+ 和 - 加法和減法
* 和 / 和 % 乘法、除法、取余
+x 和 -x 正負號
~x 按位翻轉
** 指數(冪運算)
// 地板除法,舍棄小數部分
---python運算符優先級(圖)---
#=連續賦值,自右向左,同C語言
>>> a = b = c = d = 10
>>> print (a, b, c, d)
10 10 10 10
>>> a += 1
>>> b -= 1
>>> c *= 10
>>> d /= 8 #真除法,精確值
>>> print (a, b, c, d)
11 9 100 1.25
>>> d = 10
>>> d // 3 ?#地板除法(Floor)舍棄小數部分
3
>>> 3 < 4 < 5 ?#支持連續判斷,不建議這樣用,可讀性不高
True
>>> 3 < 4 and 4 < 5
True
04丶類型 type
數值類型:整型(int)、浮點型(float)、布爾類型(bool)、e記法(科學計數法,屬于float)
(1) 整型與浮點型的區別就是是否含有小數點'.'
(2) bool類型的值是以大寫開頭的兩個單詞: True / False
(3) 純數字的字符串可以使用int轉為數字,進而參與計算,相當于C的atoi,非純數字的不能使用int轉換為數字
(4) float類型轉換為int類型時,會丟棄小數部分
(5) str類型均可被其他類型轉換,即變成字符串無障礙
(6) type (value) 返回變量類型,isinstance(value, type)類型判斷返回bool值
#float→int,丟棄小數部分
>>> a = 5.99
>>> b = int (a)
>>> print (b)
5
#e記法示例
>>> 0.00000000000000111
1.11e-15
>>> 150000000000
150000000000
>>> 15e10
150000000000.0
#isinstance類型判斷
>>> isinstance ('hello', str)
True
>>> isinstance (520, str)
False
>>> isinstance (520, int)
True
05丶條件分支與循環 condition and loop
條件bool值: True ?False
False 的值: False ?None ?0 ?"" ?() ?[] ?{}
if-else
if condition:
#condition == True, 執行的操作,可多層嵌套
else:
#condition == False, 執行的操作,可多層嵌套
if-elif-else
if condition:
#condition == True, 執行的操作,可多層嵌套
elif condition:
#condition == True, 執行的操作,可多層嵌套
else:
#condition == False, 執行的操作,可多層嵌套
x if condition else y ?#三元操作符
舉例:
>>> x, y = 4, 5
>>> small = x if x < y else y
>>> print (small)
4
assert 斷言
當assert關鍵字后面的條件為假的時候,程序自動崩潰并拋出AssertionError異常。
>>> assert 3 > 4
Traceback (most recent call last):
? File "<pyshell#160>", line 1, in <module>
? ? assert 3 > 4
AssertionError
>>> assert 3 < 4
>>>?
while 循環
while condition:
#condition == true, 執行的循環體操作
#condition == false, 循環體外的操作
for 循環
for target in expression:
#循環體
示例:
>>> favourite = 'string'
>>> for i in favourite:
print (i, end=' ') ?#end以空格隔開
s t r i n g
range()函數
range ([start], [stop], [step]) ?#step默認每次遞增1,且range的取值范圍到stop-1
常與for循環一起使用。
示例:
>>> for i in range (2, 5):
print (i, end=' ')
2 3 4
>>> for i in range (1, 10, 2):
print (i, end=' ')
1 3 5 7 9
break 和 continue
同C語言的break和continue,依次為跳出循環和跳過當前循環。
pass 和 del 和 exec
pass 什么也不敢,暫時預留
del 刪除不再使用的對象
exec 執行python語句
exal 計算python表達式,并返回結果值
06丶列表 list
普通列表:member = ['name', 'id', 'age', 'weight']
混合列表:mix = [1, 'name', 3.14, [1, 2, 3]]
空列表:empty = []
列表常用方法: len()/max()/min()/append()/extend()/insert()/remove()/pop()/count()/index()/reverse()/sort()
len()
功能:列表長度(元素個數)
len(listname)
>>> len(member)
4
append()
功能:向列表添加單個元素
listname.append(element)
>>> member.append('class')
>>> member
['name', 'id', 'age', 'weight', 'class']
extend()
功能:使用子列表擴展列表
listname.extend([element1, element2, ...])
>>> member.extend (['str1', 'str2'])
>>> member
['name', 'id', 'age', 'weight', 'class', 'str1', 'str2']
insert()
功能:向列表指定位置插入元素
listname.insert(position, element)
#list和數組一樣,下標/索引均從0開始
>>> member.insert (1, 'new_elem')
>>> member
['name', 'new_elem', 'id', 'age', 'weight', 'class', 'str1', 'str2']
列表元素訪問
listname[index]
#index從0開始,到index-1位置的索引訪問
列表元素刪除
listname.remove(element) #刪除元素element
del listname[index] #刪除index位置的元素
listname.pop() #刪除最后一個元素,相當于C語言的彈棧
listname.pop(index) #刪除index位置指定的元素
列表元素分片
listname[start_index:stop_index]
(1) 分片不會修改原列表的值,輸出的是一份拷貝
(2) 分片輸出的是從 start_index 到 stop_index-1 位置的值
(3) 分片的start和stop位置均可省略,start省略表示從頭取值,stop省略表示取值到結尾,都省略表示取列表所有的值
示例:
>>> member = ['name', 'id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
? ? ? ? ? ? ? ?0 ? ? ? 1 ? ? 2 ? ? ?3 ? ? ? ? 4 ? ? ? ?5 ? ? ? 6 ? ? ? 7
>>> member[1:3]
['id', 'age']
>>> member[1:]
['id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
>>> member[:3]
['name', 'id', 'age']
>>> member[:]
['name', 'id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
>>> member[5:len(member)] #訪問最后3個元素
['str1', 'str2', 'str3']
>>> member[0:len(member):2] #最后的2代表步長
['name', 'age', 'class', 'str2']
列表常用操作符
(1) list元素的判斷只會判斷第一個元素,然后理解返回bool結果
(2) list支持比較、邏輯、連接(+)、重復(*)、成員關系(in)操作符
(3) list賦值list時需要注意加上[:],左值會表現為一份拷貝
示例:
list2 = list1[:]#list2是list1的一份拷貝
list3 = list1 #list3是list1的一個引用(list1被修改,list3也會跟著被修改)
(4) dir(list) 查看list支持的所有方法:
listname.count(element)#element元素出現的次數
listname.index(element, [range_s], [rang_t])#查找元素在起止范圍里第一次出現的下標位置
listname.reverse()#將list中的元素原地翻轉
listname.sort()#將list中的元素進行排序,默認從小到大(修改原list內容)
listname.sort(reverse=True)#排序元素,實現從大到小(修改原list內容)
07丶元組 tuple
元組和列表使用上相似:
(1) 最大區別:列表可以任意修改和插入等操作,元組是不可改變的
(2) 創建:列表使用[],元組使用()
元組只有1個元素時使用(element,)注意逗號
()可以省略,但是,逗號不能省略
(3) 訪問:都使用name[index]來訪問
(4) 元組在映射中當做鍵使用,而列表不行
示例:
>>> temp = 1,
>>> type (temp)
<class 'tuple'>
>>> 8 * (8)
64
>>> 8 * (8,)
(8, 8, 8, 8, 8, 8, 8, 8) ?#重復元組
#元組元素插入
>>> temp = ('name1','name2','name3','name4')
>>> temp = temp[:2] + ('new_name',) + temp[2:]
>>> temp
('name1', 'name2', 'new_name', 'name3', 'name4')
08丶字符串 ?string
(1) \可以進行符號轉義
(2) 單引號等同于雙引號
(3) 定義字符串時使用r寫在右值前面聲明為原始字符串
(4) 使用三引號('''或""")可以指定多行字符串。并且字符串里可以包含單引號和雙引號'''
(5) +號運算符可以連接字符串為1個字符串
(6) *號運算符可以復制多個相同字符串
列表和元組應用于字符串,所有標準的序列操作均適用于字符串。
>>> str1 = 'hello, python!' ?#字符串相當于元素是字符的元組
>>> str1 = str1[:5] + ';' + str1[5:]
>>> str1
'hello;, python!'
字符串常用方法: find()/join()/lower()/replace()/split()/strip()/translate()/
>>> dir(str)
...'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'...
【F1】可以從python的幫助文檔中【索引】查找操作方法的介紹內容及舉例。
capitalize() 返回新字符串,把字符串的第一個字符改為大寫
casefold() 返回新字符串,把整個字符串的所有字符改為小寫
center(width) 將字符串居中,并使用空格填充至長度 width 的新字符串
count(sub[, start[, end]]) 返回 sub 在字符串里邊出現的次數,start 和 end 參數表示范圍,可選。
encode(encoding='utf-8', errors='strict') 以 encoding 指定的編碼格式對字符串進行編碼。
endswith(sub[, start[, end]]) 檢查字符串是否以 sub 子字符串結束,如果是返回 True,否則返回 False。start 和 end 參數表示范圍,可選。
expandtabs([tabsize=8]) 把字符串中的 tab 符號(\t)轉換為空格,如不指定參數,默認的空格數是 tabsize=8。
find(sub[, start[, end]]) 檢測 sub 是否包含在字符串中,如果有則返回索引值,否則返回 -1,start 和 end 參數表示范圍,可選。
index(sub[, start[, end]]) 跟 find 方法一樣,不過如果 sub 不在 string 中會產生一個異常。
isalnum() 如果字符串至少有一個字符并且所有字符都是字母或數字則返回 True,否則返回 False。
isalpha() 如果字符串至少有一個字符并且所有字符都是字母則返回 True,否則返回 False。
isdecimal() 如果字符串只包含十進制數字則返回 True,否則返回 False。
isdigit() 如果字符串只包含數字則返回 True,否則返回 False。
islower() 如果字符串中至少包含一個區分大小寫的字符,并且這些字符都是小寫,則返回 True,否則返回 False。
isnumeric() 如果字符串中只包含數字字符,則返回 True,否則返回 False。
isspace() 如果字符串中只包含空格,則返回 True,否則返回 False。
istitle() 如果字符串是標題化(所有的單詞都是以大寫開始,其余字母均小寫),則返回 True,否則返回 False。
isupper() 如果字符串中至少包含一個區分大小寫的字符,并且這些字符都是大寫,則返回 True,否則返回 False。
join(sub) 以字符串作為分隔符,插入到 sub 中所有的字符之間。
ljust(width) 返回一個左對齊的字符串,并使用空格填充至長度為 width 的新字符串。
lower() 轉換字符串中所有大寫字符為小寫。
lstrip() 去掉字符串左邊的所有空格
partition(sub) 找到子字符串 sub,把字符串分成一個 3 元組 (pre_sub, sub, fol_sub),如果字符串中不包含 sub 則返回 ('原字符串', '', '')
replace(old, new[, count]) 把字符串中的 old 子字符串替換成 new 子字符串,如果 count 指定,則替換不超過 count 次。
rfind(sub[, start[, end]]) 類似于 find() 方法,不過是從右邊開始查找。
rindex(sub[, start[, end]]) 類似于 index() 方法,不過是從右邊開始。
rjust(width) 返回一個右對齊的字符串,并使用空格填充至長度為 width 的新字符串。
rpartition(sub) 類似于 partition() 方法,不過是從右邊開始查找。
rstrip() 刪除字符串末尾的空格。
split(sep=None, maxsplit=-1) 不帶參數默認是以空格為分隔符切片字符串,如果 maxsplit 參數有設置,則僅分隔 maxsplit 個子字符串,返回切片后的子字符串拼接的列表。
splitlines(([keepends])) 按照 '\n' 分隔,返回一個包含各行作為元素的列表,如果 keepends 參數指定,則返回前 keepends 行。
startswith(prefix[, start[, end]]) 檢查字符串是否以 prefix 開頭,是則返回 True,否則返回 False。start 和 end 參數可以指定范圍檢查,可選。
strip([chars]) 刪除字符串前邊和后邊所有的空格,chars 參數可以定制刪除的字符,可選。
swapcase() 翻轉字符串中的大小寫。
title() 返回標題化(所有的單詞都是以大寫開始,其余字母均小寫)的字符串。
translate(table) 根據 table 的規則(可以由 str.maketrans('a', 'b') 定制)轉換字符串中的字符。
upper() 轉換字符串中的所有小寫字符為大寫。
zfill(width) 返回長度為 width 的字符串,原字符串右對齊,前邊用 0 填充。
字符串操作:格式化
(1) 通過format方法將位置參數傳遞給對應字段
(2) : 冒號表示格式化符號的開始
位置參數:{0~n}
>>> "{0} love {1},{2}.".format("I", "you", "too")
'I love you,too.'
關鍵字參數:{自定義}
>>> "{a} love {b}, {c}.".format(a="I", b="you", c="too")
'I love you, too.'
注意:位置參數和關鍵字參數可以同時使用,但位置參數必須在關鍵字參數的前面。
字符串格式化符號含義
%c 格式化字符及其 ASCII 碼
%s 格式化字符串
%d 格式化整數
%o 格式化無符號八進制數
%x 格式化無符號十六進制數
%X 格式化無符號十六進制數(大寫)
%f 格式化浮點數字,可指定小數點后的精度,默認精確到小數點后6位
%e 用科學計數法格式化浮點數
%E 作用同 %e,用科學計數法格式化浮點數
%g 根據值的大小決定使用 %f 或 %e
%G 作用同 %g,根據值的大小決定使用 %f 或者 %E
舉例:
>>> '%c' % 97 # 此處 % 為占位符,同C語言中printf函數中的%
'a'
>>> '%c %c %c' % (97, 98, 99) #此處的元組()小括號不能省略
'a b c'
格式化操作符輔助命令
m.n m 是顯示的最小總寬度,n 是小數點后的位數
- 用于左對齊
+ 在正數前面顯示加號(+)
# 在八進制數前面顯示 '0o',在十六進制數前面顯示 '0x' 或 '0X'
0 顯示的數字前面填充 '0' 取代空格
舉例:
>>> '%5.1f' % 27.658 #m.n
' 27.7'
>>> '%-10d' % 5 #填充的位數都是空格
'5 ? ? ? ? ?'
>>> '%#x' % 160 #對應進制顯示方式
'0xa0'
>>> '%010d' % 5 #用0填充。'%-010d' % 5 負號的時候填充的只會是空格
'0000000005'
Python 的轉義字符及其含義
\' 單引號
\" 雙引號
\a 發出系統響鈴聲
\b 退格符
\n 換行符
\t 橫向制表符(TAB)
\v 縱向制表符
\r 回車符
\f 換頁符
\o 八進制數代表的字符
\x 十六進制數代表的字符
\0 表示一個空字符
\\ 反斜杠
09丶序列方法 sequence method
列表、元組、字符串的共同點:
(1) 都可以通過索引得到每一個元素
(2) 默認索引值總是從0開始
(3) 可以通過分片的方法得到一個范圍內的元素的集合
(4) 有很多共同的操作符(重復*、拼接+、成員關系in/not in等)
(5) 統稱為序列,以下(成員函數)為序列方法
list()
list(iterable) 把一個可迭代對象轉換為列表
舉例:
>>> b = 'I love you.' # b也可以是元組 b = (1, 2, 3, 4, 5)
>>> b = list(b)
>>> b
['I', ' ', 'l', 'o', 'v', 'e', ' ', 'y', 'o', 'u', '.']
tuple()
tuple(iterable) 把一個可迭代對象轉換為元組
舉例:
>>> b = 'I love you.'
>>> b = tuple(b)
>>> b
('I', ' ', 'l', 'o', 'v', 'e', ' ', 'y', 'o', 'u', '.')
max(...) 返回集合或者序列中的最大值(要求類型一致)
min(...) 返回集合或者序列中的最小值(要求類型一致)
>>> max(iterable, *[, default=obj, key=func]) -> value
>>> max(arg1, arg2, *args, *[, key=func]) -> value
舉例:
>>> numbers = [1, 18, 13, 0, -98, 34, 53, 76, 32]
>>> max(numbers)
76
>>> min(numbers)
-98
sum(...) 返回序列iterable和可選參數的總和(要求類型一致)
>>> sum(iterable, start=0, /)
舉例:
>>> tuple1 = (3.1, 2.3, 3.4)
>>> sum(tuple1)
8.8
>>> sum(tuple1, 0.2) #0.2為可選參數,會加在一起
9.0
sorted(...) 返回序列的排序結果
>>> sorted(iterable, /, *, key=None, reverse=False)
舉例:
>>> tuple1 = (3.1, 2.3, 3.4)
>>> sorted(tuple1)
[2.3, 3.1, 3.4]
reversed(...) 翻轉一個序列的內容
>>> reversed(sequence)
舉例:
>>> numbers = [1, 24, 5, -98, 54, 32]
>>> reversed(numbers)
<list_reverseiterator object at 0x000002C3EE5046A0>#這種格式都是:迭代器對象
>>> list(reversed(numbers)) # 將迭代器對象轉換為list列表
[32, 54, -98, 5, 24, 1]
enumerate(...) 生成由序列組成的元組
>>> enumerate(iterable[, start])
舉例:
>>> numbers = [1, 24, 5, -98, 54, 32]
>>> list(enumerate(numbers))
[(0, 1), (1, 24), (2, 5), (3, -98), (4, 54), (5, 32)]
zip(...) 返回由各個參數的序列組成的元組
>>> zip(iter1 [,iter2 [...]])
舉例:
>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> b = [4, 5, 6, 7, 8]
>>> zip(a, b)
<zip object at 0x000002C3EE562948>
>>> list(zip(a, b))
[(1, 4), (2, 5), (3, 6), (4, 7), (5, 8)]
>>> for i,j in zip(a, b): ?#并行迭代,同時迭代兩個變量
print(str(i) + ' is ' + str(j))
1 is 4
2 is 5
3 is 6
4 is 7
5 is 8
10丶函數 function
(1) python只有函數(return)沒有過程(no return)
(2) 函數返回多個值的時候,使用list列表或tuple元組進行返回
(3) 局部變量和全局變量的規則同C語言
(4) 在函數內部使用 global 修飾變量,使函數可以修改同名的全局變量
(5) 函數嵌套時,內部函數的作用域都在外部函數之內,出了外部函數就不能被調用
函數定義和調用
def function_name():
#函數體內容
function_name() #函數調用,執行函數體的內容
函數返回值
def function_name():
#函數體中返回
return value
print(function_name()) #調用函數并打印其返回值
函數參數
def function_name(param): #形參:多個參數使用,逗號隔開
#函數體使用參數param
function_name(parameter) #實參:傳遞實際參數
函數文檔
舉例:
>>> def my_sec_func(name):
'function document.'#函數文檔部分,單引號引起來即可
print(name)
>>> my_sec_func('myname')
myname
>>> my_sec_func.__doc__ ?#打印輸出函數文檔部分
'function document.'
>>> help(my_sec_func)
Help on function my_sec_func in module __main__:
my_sec_func(name)
? ? function document.
關鍵字參數與默認參數
舉例:
>>> def say_some(name, words):
#>> def say_some(name='abc', words='string'): #形參可設置默認值
print(name + ' -> ' + words)
>>> say_some('Jan', 'learning python.')
Jan -> learning python.
>>> say_some(words='learning python.', name='Jan') #指定形參對應實參
Jan -> learning python.
#>>> say_some()
#abc -> string
*params搜集其余的位置參數
>>> def test(*params): # *params把實參打包為元組
print('len = ', len(params))
print('second params = ', params[1])
>>> test(1, 'Jan', 3.14)
len = ?3
second params = ?Jan
#搜集參數param加上普通形參
>>> def test(*params, tmp):
print('len = ', len(params))
print('second params = ', params[1])
print('tmp = ', tmp)
>>> test(1, 'Jan', 3.14, tmp = 520) #注意傳參需要單獨指定
len = ?3
second params = ?Jan
tmp = ?520
global 關鍵字
舉例:
>>> cnt = 5
>>> def my_func():
global cnt
cnt= 10
print(cnt)
>>> my_func()
10
>>> print(cnt)
10
函數嵌套
舉例:
>>> def func1():
print('func1 called...')
def func2():
print('func2 called...')
func2()
>>> func1() #調用func1
func1 called...
func2 called...
閉包closure
舉例1:
>>> def funX(x):
def funY(y):
return x * y
return funY
>>> i = funX(8)
>>> i
<function funX.<locals>.funY at 0x000001EFE75E87B8>
>>> type(i)
<class 'function'>
>>> i(5)
40
>>> funX(8)(5)
40
>>> funY(5) #不可被調用,解決辦法有2:list或者nonlocal
舉例2 - list:
>>> def fun1():
x = [5] #對func2函數來說x是全局變量,在func2中沒有定義x,是用list即可安全
def fun2():
x[0] *= x[0]
return x[0]
return fun2()
>>> fun1()
25
舉例2 - nonlocal:
>>> def fun1():
x = 5
def fun2():
nonlocal x #在內部函數中聲明x為非局部變量,再調用func1()也是安全的
x *= x
return x
return fun2()
>>> fun1()
25
lambda 表達式(匿名函數)
(1) 不需要考慮函數名的命名問題
(2) 極大簡化函數編寫的步驟
舉例:
>>> def ds(x):
return 2*x + 1
>>> ds(5)
11
>>> lambda x : 2*x + 1
<function <lambda> at 0x000002170B3D87B8> #可以理解為返回的是C語言的函數指針
>>> g = lambda x : 2*x + 1 #賦值后,傳參即可,g相當于接收了匿名函數
>>> g(5)
11
>>> g = lambda x, y : x+y #lambda匿名函數多個參數
>>> g(1, 3)
4
兩個牛逼的BIF:filter和map
(1) filter 過濾:返回其函數為真的元素的列表
>>> filter(function or None, iterable)
舉例:
>>> filter(None, [1, 0, False, True])
<filter object at 0x000001CE5BCB0710>
>>> list(filter(None, [1, 0, False, True]))
[1, True] #驗證filter過濾的是非true的內容
>>> def odd(x):
return x % 2
>>> temp = range(10)
>>> show = filter(odd, temp)
>>> list(show)
[1, 3, 5, 7, 9]
>>> list(filter(lambda x : x % 2, range(10))) ?#簡化一行實現求奇數
[1, 3, 5, 7, 9]
(2) map 映射:對序列中每個元素都應用函數
>>> list(map(lambda x : x + 2, range(10)))
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
---------------------------------2017.08.28--------------------------------------
11丶遞歸 recursion
#遞歸求階乘:
def factorial(n):
? ? if n == 1:
? ? ? ? return 1 #(1)必須包含退出條件,同C語言
? ? else:
? ? ? ? return n * factorial(n-1) #(2)必須調用函數自身,同C語言
number = int(input("請輸入一個正整數:"))
result = factorial(number)
print("%d 的階乘為:%d" % (number, result))
#運行:
請輸入一個正整數:10
10 的階乘為:3628800
斐波那契數列(遞歸)
def fab(n):
? ? if n < 1:
? ? ? ? print("input error!")
? ? ? ? return -1
? ? if n == 1 or n == 2:
? ? ? ? return 1
? ? else:
? ? ? ? return fab(n-1) + fab(n-2)
num = int(input("請輸入一個數字:"))
result = fab(num)
print("斐波那契數列結果為:%d" % result)
漢諾塔游戲(遞歸)
def hanoi(n, x, y, z):
? ? if n == 1:
? ? ? ? print(x, '-->', z)
? ? else:
? ? ? ? hanoi(n-1, x, y, z) ? ? #將前n-1個盤子從x移動到y上
? ? ? ? print(x, '-->', z) ? ? ?#將最底下的最后一個盤子從x移動到z上
? ? ? ? hanoi(n-1, y, x, z) ? ? #將y上的n-1個盤子移動到z上
n = int(input('請輸入漢諾塔的層數:'))
hanoi(n, 'x', 'y', 'z')
---------------------------------2017.08.29--------------------------------------
12丶字典 dict
(1) 字典是一種映射類型(key:value 鍵值映射項),類型名為 dict
(2) 字典的表示使用{}大括號,元素映射之間使用:冒號,使用dictname[]訪問字典映射的值
(3) 新建字典有兩種方法:三層小括號,一層小括號中key=value
(4) 字典中的鍵值映射項是無序的,popitem時是隨機彈出
(5) 字典基本操作:
len(d) 返回d中項的數量
d[k] 返回映射到鍵k上的值
d[k]=v 將值v映射到鍵k上
del d[k] 刪除鍵為k的項
k in d 檢查d中是否含有鍵為k的項
(6) 字典常用方法: clear()/copy()/fromkeys()/get()/has_key()/items()/iteritems()/keys()/iterkeys()/pop()/popitem()/setdefault()/update()/values()/itervalues()
映射關系示例
>>> brand = ['李寧', '耐克', '阿迪達斯', 'xx工作室']
>>> slogan = ['一切皆有可能', 'Just do it', 'Impossible is nothing', '讓編程改變世界']
>>> print('魚c工作室的口號是: ', slogan[brand.index('xx工作室')])
xx工作室的口號是: ?讓編程改變世界
#使用字典來完成映射工作
>>> dict1 = {'李寧':'一切皆有可能', '耐克':'Just do it', '阿迪達斯':'Impossible is nothing', 'xx工作室':'讓編程改變世界'}
>>> print('xx工作室的口號是: ', dict1['xx工作室'])
xx工作室的口號是: ?讓編程改變世界
#新建一個字典方法1:dict(((key1, value1), (key2, value2), ...))
>>> dictname = dict((('y', 1), ('u', 2), ('a', 3), ('n', 4)))
>>> dictname
{'u': 2, 'a': 3, 'y': 1, 'n': 4}
#新建一個字典方法2:(key1=value1, key2=value2, ...)
>>> dictname = dict(蒼井空='讓AV改變宅男', 工作室='讓編程改變世界')
>>> dictname
{'工作室': '讓編程改變世界', '蒼井空': '讓AV改變宅男'}
>>> dictname['蒼井空']
'讓AV改變宅男'
#字典中新增映射元素
>>> dictname['愛迪生'] = '天才是99%的汗水+1%的靈感,但這1%的靈感比99%的汗水更重要。'
>>> dictname
{'工作室': '讓編程改變世界', '愛迪生': '天才是99%的汗水+1%的靈感,但這1%的靈感比99%的汗水更重要。', '蒼井空': '讓AV改變宅男'}
字典中鍵、值、鍵值映射項的訪問
>>> dict1 = dict1.fromkeys(range(10), '贊')
>>> dict1
{0: '贊', 1: '贊', 2: '贊', 3: '贊', 4: '贊', 5: '贊', 6: '贊', 7: '贊', 8: '贊', 9: '贊'}
>>> for eachKey in dict1.keys():
print(eachKey, end=' ')
0 1 2 3 4 5 6 7 8 9
>>> for eachValue in dict1.values():
print(eachValue, end=' ')
贊 贊 贊 贊 贊 贊 贊 贊 贊
>>> for eachItems in dict1.items():
print(eachItems, end=' ')
(0, '贊') (1, '贊') (2, '贊') (3, '贊') (4, '贊') (5, '贊') (6, '贊') (7, '贊') (8, '贊') (9, '贊')
fromkeys(...) ?創建并返回一個新的字典
dictname.fromkeys(S[, V])
@S key;@V value 可選參數
舉例:
>>> dict1 = {}
>>> dict1.fromkeys((1, 2, 3))
{1: None, 2: None, 3: None}
>>> dict1.fromkeys((1, 2, 3), 'number')
{1: 'number', 2: 'number', 3: 'number'}
>>> dict1.fromkeys((1, 2, 3), ('one', 'two', 'three'))
{1: ('one', 'two', 'three'), 2: ('one', 'two', 'three'), 3: ('one', 'two', 'three')}
>>> dict1.fromkeys((1, 3), 'num')
{1: 'num', 3: 'num'} ? #還是返回新的字典,并不會修改dict1
get(...) ?從字典中找到key的映射值value
舉例:
>>> dict1 = dict.fromkeys(range(10), 'Yes!')
>>> dict1
{0: 'Yes!', 1: 'Yes!', 2: 'Yes!', 3: 'Yes!', 4: 'Yes!', 5: 'Yes!', 6: 'Yes!', 7: 'Yes!', 8: 'Yes!', 9: 'Yes!'}
>>> dict1.get(10)
>>> print(dict1.get(10))
None
>>> dict1.get(10, '木有')
'木有'
>>> dict1.get(9, '木有')
'Yes!'
setdefault(...) ?類似于get但在字典里如果找不到的話會將映射項添加到字典中
dictname.setdefault(key, value)
舉例:
>>> a
{3: 'three', 4: 'four'}
>>> a.setdefault(5, '小白')
'小白'
>>> a
{3: 'three', 4: 'four', 5: '小白'}
clear() ?清空一個字典(包括使用當前字典賦值的其他字典)
舉例:
>>> dict1.clear()
>>> dict1
{}
copy() ?拷貝一個字典(淺拷貝,不受字典修改影響)
>>> a = {1:'one', 2:'two', 3:'three'}
>>> b = a.copy()
>>> c = a #相當于C的指針,C++的引用,修改字典c的值會同時影響字典a
>>> a
{1: 'one', 2: 'two', 3: 'three'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}
>>> c
{1: 'one', 2: 'two', 3: 'three'}
>>> print(id(a), id(b), id(c))
2334673012680 2334672609672 2334673012680
>>> c[4] = 'four'
>>> c
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}
pop(...) ?給定一個鍵彈出一個值
popitem() ?隨機彈出一個項(映射關系的鍵和值)
舉例:
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a.pop(2)
'two'
>>> a
{1: 'one', 3: 'three', 4: 'four'}
>>> a.popitem()
(1, 'one')
>>> a
{3: 'three', 4: 'four'}
update(...) ?使用一個子字典去更新原字典
dictname1.update(dictname2)
舉例:
>>> a
{3: 'three', 4: 'four', 5: '小白'}
>>> b = {'小白':'狗'}
>>> a.update(b)
>>> a
{'小白': '狗', 3: 'three', 4: 'four', 5: '小白'}
13丶集合 set
(1) 使用{}創建的沒有映射關系的字典,成為集合類型,如num = {1, 2, 3, 4, 5}
(2) 集合中元素唯一,重復的數據會被自動清理掉
(3) 集合中元素無序,不能索引取到其元素的值
(4) 集合使用關鍵字 set([]) 來創建
(5) 集合支持 in 和 not in 來判斷是否屬于集合
舉例:
>>> num = {}
>>> type(num)
<class 'dict'>
#set沒有體現字典的映射
>>> num1 = {1, 2, 3, 4, 5}
>>> type(num1)
<class 'set'>
#set唯一性
>>> num2 = {1, 2, 3, 4, 2, 3, 5, 1, 5, 5}
>>> num2
{1, 2, 3, 4, 5}
#set無序性
>>> num2[2]
TypeError: 'set' object does not support indexing
#set關鍵字創建集合
>>> set1 = set([1, 2, 3, 4, 5, 5, 5, 3, 1])
>>> set1
{1, 2, 3, 4, 5}
#list實現set的唯一性
>>> num1 = [1, 2, 3, 4, 5, 5, 3, 1, 0]
>>> temp = []
>>> for each in num1:
if each not in temp:
temp.append(each)
>>> temp
[1, 2, 3, 4, 5, 0]
#簡化: 實現set的唯一性,并且會把set的無序性變為有序
>>> num1
[1, 2, 3, 4, 5, 5, 3, 1, 0]
>>> num1 = list(set(num1))
>>> num1
[0, 1, 2, 3, 4, 5]
add(...) ?往集合中加入元素
remove(...) ?從集合中刪除指定元素
舉例:
>>> num2
{1, 2, 3, 4, 5}
>>> num2.add(6)
>>> num2
{1, 2, 3, 4, 5, 6}
>>> num2.remove(4)
>>> num2
{1, 2, 3, 5, 6}
frozenset(...) ?將集合設置為不可變集合,frozen:冰凍的,凍結的
舉例:
>>> num3 = frozenset([1, 2, 3, 4, 5])
>>> num3
frozenset({1, 2, 3, 4, 5})
>>> num3.add(6)
AttributeError: 'frozenset' object has no attribute 'add'
集合內建方法(整理出來):
http://bbs.fishc.com/forum.php?mod=viewthread&tid=45276&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
14丶文件操作 file operation
open(...) ?打開一個文件返回一個流對象
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) ?#除了file參數,其他參數均有默認值
'r' 只讀模式
'w' 寫入(會覆蓋已存在的文件)模式
'x' 文件存在,報異常的模式
'a' 寫入(文件存在則追加)模式
'b' 二進制模式
't' 文本模式
'+' 可讀寫模式(可添加到其他模式)
'U' 通用換行符支持
舉例:
#打開一個文件,注意路徑的中\反斜杠的轉義(或用/斜杠一根即可)
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt')
>>> f
<_io.TextIOWrapper name='C:\\Users\\Jan\\Desktop\\IP.txt' mode='r' encoding='cp936'>
文件對象方法
(整理)
http://bbs.fishc.com/forum.php?mod=viewthread&tid=45279&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
(1) 文件對象支持直接使用list轉換讀出
(2) 文件對象支持 for...in 的迭代方式讀取
舉例:
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt') #f,打開的文件流對象
>>> f.read()
'【本機】\nIP:192.168.31.217\n[ Ctrl + r ]\ncmd\nping 192.168.31.207\nmstsc\n\n\n【虛擬機】 - 虛擬網絡編輯器(自動) - 橋接模式\nIP:192.168.31.207\nlinux賬戶:jiangyuan\nlinux密碼:123456\n'
>>> f.read()
''
>>> f.close()
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt')
>>> f.read(5)
'【本機】\n'
>>> f.tell()
10
>>> f.seek(45, 0) #0,文件起始位置;45,偏移字節數。從文件起始位置偏移一定量字節
45
>>> f.readline()
'md\n'
>>> list(f)
['ping 192.168.31.207\n', 'mstsc\n', '\n', '\n', '【虛擬機】 - 虛擬網絡編輯器(自動) - 橋接模式\n', 'IP:192.168.31.207\n', 'linux賬戶:jiangyuan\n', 'linux密碼:123456\n']
>>> for each_line in f:
print(each_line)#逐行讀取文件內容的高效方法
【本機】
IP:192.168.31.217
[ Ctrl + r ]
cmd
ping 192.168.31.207
mstsc
...
#創建一個新的可寫入的文件,寫入內容,然后關閉文件流對象
>>> f = open('C:\\Users\\Jan\\Desktop\\test.txt', 'w')
>>> f.write('some lines')
10
>>> f.close()
任務:將文件record.txt中的數據進行分割并且按照規律保存起來。
record.txt下載:
鏈接:http://pan.baidu.com/s/1sjzAhNR (密碼:tf2e)
#最終代碼如下:
def save_file(boy, girl, count):
? ? # 文件的分別保存操作
? ? file_name_boy = 'boy_' + str(count) + '.txt'
? ? file_name_girl = 'girl_' + str(count) + '.txt'
? ? boy_f = open(file_name_boy, 'w')
? ? girl_f = open(file_name_girl, 'w')
? ? boy_f.writelines(boy)
? ? girl_f.writelines(girl)
? ? boy_f.close()
? ? girl_f.close()
def split_file(filename):
? ? f = open(filename)
? ? boy = []
? ? girl = []
? ? count = 1
? ? for each_line in f:
? ? ? ? if each_line[:6] != '======':
? ? ? ? ? ? # 我們再這里進行字符串分割操作
? ? ? ? ? ? (role, line_spoken) = each_line.split(':', 1) ?#中文冒號:否則會報錯
? ? ? ? ? ? if role == '小甲魚':
? ? ? ? ? ? ? ? boy.append(line_spoken)
? ? ? ? ? ? if role == '小客服':
? ? ? ? ? ? ? ? girl.append(line_spoken)
? ? ? ? else:
? ? ? ? ? ? save_file(boy, girl, count)
? ? ? ? ? ? boy = []
? ? ? ? ? ? girl = []
? ? ? ? ? ? count += 1
? ? save_file(boy, girl, count)
? ? f.close()
split_file('C:\\Users\\Jan\\Desktop\\python_study\\record.txt')
文件操作練習題及答案(偽代碼可以保存一下):
http://blog.csdn.net/junwei0206/article/details/44988195
---------------------------------2017.08.30--------------------------------------
15丶模塊 modules
(1) 模塊是.py的python文件
(2) 使用模塊是需要進行導入,使用關鍵字 import
舉例:
>>> import random
>>> secret = random.randint(1, 10)
>>> secret
3
os 模塊(系統模塊)
os模塊方法表格:http://bbs.fishc.com/thread-45512-1-2.html
舉例:
>>> import os
>>> os.getcwd() ?#輸出當前工作目錄
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35'
>>> os.chdir('E:\\') ?#改變工作目錄
>>> os.getcwd()
'E:\\'
>>> os.listdir('E:\\') ?#列舉指定目錄中的文件名
['$RECYCLE.BIN', '.cache', '360Downloads', 'Jan_mi', 'Jan個人總資料', 'Qiyi', 'QQMusicCache', 'qycache', 'System Volume Information', 'Youku Files', 'Youxun', '博客'] ?#RECYCLE.BIN是個回收站
>>> os.mkdir('E:\\A') ?#創建單層目錄,如該目錄已存在拋出異常
>>> os.mkdir('E:\\A\\B')
>>> os.mkdir('E:\\C\\D')
FileNotFoundError: [WinError 3] 系統找不到指定的路徑。: 'E:\\C\\D'
>>> os.remove('E:\\A\\B\\test.txt') ?#刪除文件
>>> os.rmdir('E:\\A\\B\\') ?#刪除單層目錄,如該目錄非空則拋出異常
>>> os.system('cmd') ?#運行系統的shell命令:windows shell窗口
-1073741510
>>> os.system('calc') ?#運行系統的shell命令:calc計算器
0
>>> os.curdir ?#當前目錄('.')
'.'
>>> os.listdir(os.curdir) ?# 等同于 os.listdir('.')
['$RECYCLE.BIN', '.cache', '360Downloads', 'A', 'Jan_mi', 'Jan個人總資料', 'Qiyi', 'QQMusicCache', 'qycache', 'System Volume Information', 'Youku Files', 'Youxun', '博客']
>>> os.sep ?#輸出操作系統特定的路徑分隔符(Win下為'\\',Linux下為'/')
'\\'
>>> os.linesep ?#當前平臺使用的行終止符(Win下為'\r\n',Linux下為'\n')
'\r\n'
>>> os.name ?#指代當前使用的操作系統(包括:'posix', ?'nt', 'mac', 'os2', 'ce', 'java')
'nt' ?#nt是windows系統平臺
os.path 模塊(系統路徑模塊屬于os的子模塊)
>>> os.path.basename('E:\\A\\B\\C\\sexy.avi') ?#去掉目錄路徑,單獨返回文件名
'sexy.avi'
>>> os.path.dirname('E:\\A\\B\\C\\sexy.avi') ?#去掉文件名,單獨返回目錄路徑
'E:\\A\\B\\C'
>>> os.path.join('A', 'B', 'C') ?#將path1, path2...各部分組合成一個路徑名
'A\\B\\C'
>>> os.path.join('D:', 'A', 'B', 'C')
'D:A\\B\\C'
>>> os.path.join('D:\\', 'A', 'B', 'C') ?#注意盤符需要帶上斜杠
'D:\\A\\B\\C'
>>> os.path.split('E:\\A\\SEXY.AVI') ?#分割文件名與路徑,返回(f_path, f_name)元組。
('E:\\A', 'SEXY.AVI')
>>> os.path.split('E:\\A\\B\\C')
('E:\\A\\B', 'C')
>>> os.path.splitext('E:\\A\\SEXY.AVI') ?#分離文件名與擴展名,返回(f_name, f_extension)元組
('E:\\A\\SEXY', '.AVI')
>>> os.path.getatime('E:\\A\\test.txt') ?#返回指定文件最近的訪問時間
1504103243.229383 ?#浮點型秒數,可用time模塊的gmtime()或localtime()函數換算
>>> import time
>>> time.gmtime(os.path.getatime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=14, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getatime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getmtime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=30, tm_sec=1, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getctime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> os.path.ismount('E:\\') ?#判斷指定路徑是否存在且是一個掛載點
True
>>> os.path.ismount('E:\\A')
False
pickle 模塊(泡菜模塊)
舉例:
>>> import pickle
>>> my_list = [123, 3.14, '名字', ['another list']]
>>> pickle_f = open('E:\\A\\my_list.pkl', 'wb')
>>> pickle.dump(my_list, pickle_f) ?#將list的內容傾倒入文件流對象中
>>> pickle_f.close()
>>> pickle_f = open('E:\\A\\my_list.pkl', 'rb')
>>> my_list2 = pickle.load(pickle_f) ?#將.pkl文件的內容裝載到list中
>>> print(my_list2)
[123, 3.14, '名字', ['another list']]
>>> city = {'城市1':'000001', '城市2':'000002', '城市n':'999999'} ?#此字典映射有70k這么大
>>> import pickle
>>> pickle_f = open('E:\\A\\city.pkl', 'wb') ?#將70k的字典映射寫入文件
>>> pickle.dump(city, pickle_f)
>>> pickle_f.close()
>>> pickle_file = open('E:\\A\\city.pkl', 'rb') ?#使用字典的時候打開文件裝載即可
>>> city = pickle.load(pickle_file)
>>> print(city)
{'城市2': '000002', '城市n': '999999', '城市1': '000001'}
---------------------------------2017.08.31--------------------------------------
16丶異常 exception
異常匯總
AssertionError 斷言語句(assert)失敗<eg1>
AttributeError 嘗試訪問未知的對象屬性<eg2>
EOFError 用戶輸入文件末尾標志EOF(Ctrl+d)?
FloatingPointError 浮點計算錯誤?
GeneratorExit generator.close()方法被調用的時候?
ImportError 導入模塊失敗的時候?
IndexError 索引超出序列的范圍<eg3>
KeyError 字典中查找一個不存在的關鍵字<eg4>
KeyboardInterrupt 用戶輸入中斷鍵(Ctrl+c)?
MemoryError 內存溢出(可通過刪除對象釋放內存)?
NameError 嘗試訪問一個不存在的變量?
NotImplementedError 尚未實現的方法?
OSError 操作系統產生的異常(例如打開一個不存在的文件)?
OverflowError 數值運算超出最大限制?
ReferenceError 弱引用(weak reference)試圖訪問一個已經被垃圾回收機制回收了的對象?
RuntimeError 一般的運行時錯誤?
StopIteration 迭代器沒有更多的值?
SyntaxError Python的語法錯誤?
IndentationError 縮進錯誤?
TabError Tab和空格混合使用?
SystemError Python編譯器系統錯誤?
SystemExit Python編譯器進程被關閉?
TypeError 不同類型間的無效操作?
UnboundLocalError 訪問一個未初始化的本地變量(NameError的子類)?
UnicodeError Unicode相關的錯誤(ValueError的子類)?
UnicodeEncodeError Unicode編碼時的錯誤(UnicodeError的子類)?
UnicodeDecodeError Unicode解碼時的錯誤(UnicodeError的子類)?
UnicodeTranslateError Unicode轉換時的錯誤(UnicodeError的子類)?
ValueError 傳入無效的參數?
ZeroDivisionError 除數為零?
部分舉例:
>>> my_list = ['我是帥哥', '你是美女']
>>> assert len(my_list) > 0
>>> my_list.pop()
'你是美女'
>>> my_list.pop()
'我是帥哥'
>>> assert len(my_list) > 0
Traceback (most recent call last):
? File "<pyshell#856>", line 1, in <module>
? ? assert len(my_list) > 0
AssertionError #斷言語句(assert)失敗
>>> my_list.abcd
Traceback (most recent call last):
? File "<pyshell#857>", line 1, in <module>
? ? my_list.abcd
AttributeError: 'list' object has no attribute 'abcd'#嘗試訪問未知的對象屬性
>>> my_list = [1, 2, 3]
>>> my_list[3]
Traceback (most recent call last):
? File "<pyshell#859>", line 1, in <module>
? ? my_list[3]
IndexError: list index out of range #索引超出序列的范圍
>>> my_list[2]
3
>>> my_dict = {'one':1, 'two':2, 'three':3}
>>> my_dict['one']
1
>>> my_dict['four']
Traceback (most recent call last):
? File "<pyshell#863>", line 1, in <module>
? ? my_dict['four']
KeyError: 'four' #字典中查找一個不存在的關鍵字
>>> my_dict.get('four')
>>> #dict.get(...)方法比較安全合適
異常檢測與處理
(1) try語句一旦檢測出現異常,則剩下的其他代碼則不會執行
(2) raise Exception_name 主動引發一個自定義異常名字的異常,可定義異常描述
try:
#檢測范圍
except Exception[as reason]:
#出現異常(Exception)后的處理代碼
finally:
#無論如何都會被執行的代碼(收尾工作)
舉例:
try:
? ? f = open('我為什么是一個文件.txt')
? ? print(f.read())
? ? f.close()
except OSError:
? ? print('文件出錯啦T_T')
運行:
文件出錯啦T_T
try:
? ? f = open('我為什么是一個文件.txt')
? ? print(f.read())
? ? f.close()
except OSError as reason:
? ? print('文件出錯啦T_T\n錯誤的原因是:' + str(reason))
運行:
文件出錯啦T_T
錯誤的原因是:[Errno 2] No such file or directory: '我為什么是一個文件.txt'
try:
? ? sum = 1 + '1'
? ? f = open('我為什么是一個文件.txt')
? ? print(f.read())
? ? f.close()
except (OSError, TypeError): ?#多個異常同時捕獲
? ? print('出錯啦T_T')
運行:出錯啦T_T
try:
? ? f = open('我為什么是一個文件.txt', 'w')
? ? print(f.write('我存在了!')) ?#沒有finally時并不會寫入文件
? ? sum = 1 + '1'
? ? f.close()
except (OSError, TypeError):
? ? print('出錯啦T_T')
finally:
? ? f.close()
運行:
5
出錯啦T_T
>>> raise ZeroDivisionError('除數為0的異常')
Traceback (most recent call last):
? File "<pyshell#872>", line 1, in <module>
? ? raise ZeroDivisionError('除數為0的異常')
ZeroDivisionError: 除數為0的異常
17丶豐富的esle-簡潔的with
else
舉例:while-else / for-else
def showMaxFactor(num):
? ? count = num // 2
? ? while count > 1:
? ? ? ? if num % count == 0:
? ? ? ? ? ? print('%d最大的約數是%d' % (num, count))
? ? ? ? ? ? break
? ? ? ? count -= 1
? ? else: #while循環完沒有break就會執行else
? ? ? ? print('%d是素數!' % num)
num = int(input('請輸入一個數:'))
showMaxFactor(num)
舉例:try-else
try:
? ? print(int('123'))
except ValueError as reason:
? ? print('出錯啦:' + str(reason))
else:
? ? print('Good!沒有任何異常。')
運行:
123
Good!沒有任何異常。
with as
舉例:
try:
? ? with open('data.txt', 'w') as f: #比 f = open(...) 多了文件不使用時自動關閉功能
? ? for each_line in f:
? ? ? ? print(each_line)
except OSError as reason:
? ? print('出錯啦:' + str(reason))
#finally: ? ? ? #有了with就不需要finally去調用關閉,會自動關閉
# ? ?f.close() ?#如果文件data.txt不存在就試圖去關閉一個不存在的文件
18丶圖形用戶界面 EasyGui
EasyGui官網:http://easygui.sourceforge.net
中文的教學文檔:http://bbs.fishc.com/thread-46069-1-1.html (要看完并實操)
模塊庫:easygui-0.96.zip
安裝方法:
(1) 使用命令窗口切換到easygui-docs-0.96的目錄下
(2) 【Windows下】執行C:\Python33\python.exe setup.py install
> cd Desktop
> cd puthon_study\easygui-0.96
#然后修改C:\Program Files (x86)\python\python.exe為管理員權限:右鍵-兼容性-更改所有用戶的設置-以管理員身份運行此程序-確定
> "C:\Program Files (x86)\python\python.exe" setup.py install
#生成了文件模塊庫C:\Program Files (x86)\python\Lib\site-packages\easygui.py
> "C:\Program Files (x86)\python\python.exe" easygui.py
#easygui的演示程序
PS: 【Linux或Mac下】sudo /Library/Framworks/Python.framework/Versions/3.3/bin/python3.3 setup.py install
使用方法:
【遇到難題】import easygui 出錯~!!!
【解決辦法】
(1) 重裝python IDLE勾選添加python路徑,選擇目錄安裝到C:\python文件夾,如重裝則忽略(2),如此一來win-cmd下的python中sys.path和IDLE中的sys.path則一致了。
(2) 對比windows命令窗口中啟動python與IDLE中python的系統路徑,添加到IDLE即可。
windows中系統路徑:
C:\Users\Jan> "C:\Program Files (x86)\python\python.exe"
>>> import sys
>>> sys.path
['',?
'C:\\Program Files (x86)\\python\\python35.zip',?
'C:\\Program Files (x86)\\python\\DLLs',?
'C:\\Program Files (x86)\\python\\lib',?
'C:\\Program Files (x86)\\python',?
'C:\\Program Files (x86)\\python\\lib\\site-packages']
IDLE中系統路徑:
>>> import easygui as g
Traceback (most recent call last):
? File "<pyshell#0>", line 1, in <module>
? ? import easygui as g
ImportError: No module named 'easygui'
>>> import sys
>>> sys.path
['',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\Lib\\idlelib',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\python35.zip',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\DLLs',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\lib',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\lib\\site-packages']
>>> sys.path.append('C:\\Program Files (x86)\\python\\python35.zip')
>>> sys.path.append('C:\\Program Files (x86)\\python\\DLLs')
>>> sys.path.append('C:\\Program Files (x86)\\python\\lib')
>>> sys.path.append('C:\\Program Files (x86)\\python')
>>> sys.path.append('C:\\Program Files (x86)\\python\\lib\\site-packages')
>>> import easygui as g ?#import ... as ... 導入模塊的同時重定義模塊名字
>>> g.msgbox('嗨,python!')
'OK'
>>>?
# No error, success... 但每次重啟IDLE都需要將windows下的sys.path進行添加。
# 示例,gui界面文字小游戲
import easygui as g
import sys
while 1:
? ? ? ? g.msgbox("嗨,歡迎進入第一個界面小游戲^_^")
? ? ? ? msg ="請問你希望在魚C工作室學習到什么知識呢?"
? ? ? ? title = "小游戲互動"
? ? ? ? choices = ["談戀愛", "編程", "OOXX", "琴棋書畫"]
? ? ? ??
? ? ? ? choice = g.choicebox(msg, title, choices)
? ? ? ? # note that we convert choice to string, in case
? ? ? ? # the user cancelled the choice, and we got None.
? ? ? ? g.msgbox("你的選擇是: " + str(choice), "結果")
? ? ? ? msg = "你希望重新開始小游戲嗎?"
? ? ? ? title = "請選擇"
? ? ? ??
? ? ? ? if g.ccbox(msg, title): ? ? # show a Continue/Cancel dialog
? ? ? ? ? ? ? ? pass ?# user chose Continue
? ? ? ? else:
? ? ? ? ? ? ? ? sys.exit(0) ? ? # user chose Cancel
---------------------------------2017.09.01--------------------------------------
19丶類和對象 class and object
面向對象(Object Oriented)
(1) python約定類名以大寫字母開頭
(2) 面向對象特征:封裝(信息隱蔽)、繼承(子類共享父類公共內容)、多態(不同對象對同一方法響應不同的行動)
類的示例:
class Turtle:
#屬性
color = 'green'
weight = 60
legs = 2
shell = True
age = 26
#方法
def climb(self):
print('我正在學習...')
def run(self):
print('我正在奔跑...')
運行:
>>> tt = Turtle() ?#類Turtle的示例對象tt
>>> Turtle
<class '__main__.Turtle'>
>>> type(Turtle)
<class 'type'>
>>> type('abc')
<class 'str'>
>>> tt.climb()
我正在學習...
>>> tt.run()
我正在奔跑...
#封裝
>>> list1 = [2, 1, 7, 5, 3]
>>> list1.sort() ?#sort() 方法封裝在list1對象中
>>> list1
[1, 2, 3, 5, 7]
>>> list1.append(9) ?#append() 方法封裝在list1對象中
>>> list1
[1, 2, 3, 5, 7, 9]
#繼承
>>> class Mylist(list):
pass
>>> list2 = Mylist()
>>> list2.append(5) ?#list2可以使用append()方法,繼承了Mylist(list)中的list參數類
>>> list2.append(3)
>>> list2.append(7)
>>> list2
[5, 3, 7]
>>> list2.sort()
>>> list2
[3, 5, 7]
#多態
>>> class A:
def fun(self):
print('我是小A')
>>> class B:
def fun(self):
print('我是小B')
>>> a = A()
>>> b = B()
>>> a.fun() ?#不同對象對同一方法響應不同的行動
我是小A
>>> b.fun() ?#不同對象對同一方法響應不同的行動
我是小B
self
相當于C++的this指針(指向當前對象本身的地址),表明類自身
舉例:
>>> class Ball:
def setName(self, name): ?#默認self的寫法
self.name = name
def kick(self): ?#默認self的寫法
print('我叫%s, 該死的誰踢我...' % self.name)
>>> a = Ball()
>>> a.setName('球A')
>>> b = Ball()
>>> b.setName('球B')
>>> c = Ball()
>>> c.setName('土豆')
>>> a.kick()
我叫球A, 該死的誰踢我...
>>> c.kick()
我叫土豆, 該死的誰踢我...
魔法方法:__init__(self)
__init__(self, parma1, parma2, ...)
舉例:
>>> class Ball:
def __init__(self, name):
self.name = name
def kick(self):
print('我叫%s,該死的,誰踢我!!' % self.name)
>>> b = Ball('土豆')
>>> b.kick()
我叫土豆,該死的,誰踢我!!
>>> a = Ball() ?#__init__默認設置了name,所以必須傳遞name實參,否則報錯
TypeError: __init__() missing 1 required positional argument: 'name'
公有和私有
name mangling 名字改變/名字重造
公有成員:默認創建的成員均為公有。
私有成員:
(1) 在變量或函數名前加上"_"兩個下劃線即可。
(2) python中類的私有均屬于偽私有,通過"對象._類_變量"的形式可以訪問私有成員
舉例:
>>> class Person:
__name = 'yuan.jiang'
>>> p = Person()
>>> p.name
AttributeError: 'Person' object has no attribute 'name'
>>> p.__name
AttributeError: 'Person' object has no attribute '__name'
>>> class Person:
__name = 'yuan.jiang'
def getName(self):
return self.__name
>>> p = Person()
>>> p.getName()
'yuan.jiang'
>>> p._Person__name ?#python中類的私有屬于偽私有,此方式可訪問私有成員
'yuan.jiang'
繼承 inherit
class DerivedClassName(BaseClassName):
...
(1) 如果子類中定義于父類同名的成員時,則會自動覆蓋父類對應的方法或屬性
(2) 解決子類中__init()
舉例:
>>> class Parent:
def hello(self):
print('正在調用父類的方法...')
>>> class Child(Parent):
pass
>>> p = Parent()
>>> p.hello()
正在調用父類的方法...
>>> c = Child()
>>> c.hello()
正在調用父類的方法...
>>> class Child(Parent):
def hello(self):
print('正在調用子類的方法...')
>>> c = Child()
>>> c.hello()
正在調用子類的方法...
>>> p.hello()
正在調用父類的方法...
舉例:
import random as r
class Fish:
? ? def __init__(self):
? ? ? ? self.x = r.randint(0, 10)
? ? ? ? self.y = r.randint(0, 10)
? ? def move(self):
? ? ? ? self.x -= 1
? ? ? ? print('我的位置是:', self.x, self.y)
class Goldfish(Fish):
? ? pass
class Carpfish(Fish):
? ? pass
class Salmonfish(Fish):
? ? pass
class Sharkfish(Fish):
? ? def __init__(self): ?#重寫了__init__方法覆蓋了父類的__init__子類無法調用到self.x和self.y屬性成員,導致了子類無法訪問到父類的屬性或方法的問題
? ? ? ? self.hungry = True
? ? def eat(self):
? ? ? ? if self.hungry:
? ? ? ? ? ? print('吃貨的夢想就是天天有的吃^_^')
? ? ? ? ? ? self.hungry = False
? ? ? ? else:
? ? ? ? ? ? print('太撐了,吃不下了!')
運行:
>>> fish = Fish()
>>> fish.move()
我的位置是: 3 0
>>> fish.move()
我的位置是: 2 0
>>> goldfish = Goldfish()
>>> goldfish.move()
我的位置是: 4 9
>>> goldfish.move()
我的位置是: 3 9
>>> shark = Sharkfish()
>>> shark.eat()
吃貨的夢想就是天天有的吃^_^
>>> shark.eat()
太撐了,吃不下了!
>>> shark.move() ?#無法訪問到父類的__init__()方法中的x變量
AttributeError: 'Sharkfish' object has no attribute 'x'
--------------------------------2017.09.02----------------------------------------
覆蓋屬性或方法問題優化
問題:針對子類屬性或方法覆蓋父類屬性或方法的情況,導致子類無法訪問父類中被覆蓋的屬性
(1) 調用未綁定的父類的方法
(2) 使用super方法(推薦)
舉例:
def __init__(self):
Fish.__init__(self) ?#調用未綁定的父類的方法,相當于>>>Fish.__init__(Sharkfish)
self.hungry = True
運行:
>>> shark = Sharkfish()
>>> shark.move()
我的位置是: -1 2
>>> shark.move()
我的位置是: -2 2
舉例:
def __init__(self):
super().__init__() ?#使用super方法解決
self.hungry = True
運行:
>>> shark = Sharkfish()
>>> shark.move()
我的位置是: 8 3
>>> shark.move()
我的位置是: 7 3
多重繼承
class DerivedClassName(Base1, Base2, Base3, ...):
...
#建議少用,有可能會導致不可預見的bug(不可預見最麻煩)
>>> class Base1:
def fool(self):
print('我是fool,我為Base1代言...')
>>> class Base2:
def fool2(self):
print('我是fool2,我為Base2代言...')
>>> class C(Base1, Base2):
pass
>>> c = C()
>>> c.fool()
我是fool,我為Base1代言...
>>> c.fool2()
我是fool2,我為Base2代言...
組合
class Turtle:
? ? def __init__(self, x):
? ? ? ? self.num = x
class Fish:
? ? def __init__(self, x):
? ? ? ? self.num = x
class Pool:
? ? def __init__(self, x, y): ?#組合的方式嵌套class
? ? ? ? self.turtle = Turtle(x)
? ? ? ? self.fish ?= Fish(y)
? ? def print_num(self):
? ? ? ? print('水池里總共有烏龜 %d 只,小魚 %d 條!' % (self.turtle.num, self.fish.num))
運行:
>>> pool = Pool(1, 10)
>>> pool.print_num()
水池里總共有烏龜 1 只,小魚 10 條!
類、類對象、示例對象
類定義 ? ?C
類對象 ? ?C
實例對象 ?a ?b ?c
舉例:
>>> class C: ? #C, 既是類,也是類對象
count = 0
>>> a = C() ? ?#a,實例對象
>>> b = C() ? ?#b,實例對象
>>> c = C() ? ?#c,實例對象
>>> a.count
0
>>> b.count
0
>>> c.count
0
>>> c.count += 10
>>> c.count
10
>>> a.count
0
>>> b.count
0
>>> C.count ? ?#C,作為類對象
0
>>> C.count += 100 ? ?#C,作為類對象
>>> a.count
100
>>> b.count
100
>>> c.count
10
(1) 當屬性名與方法名沖突,會導致方法不能正常調用。
(2) 一般遵循規則:屬性名用英文名詞,方法名用英文動詞。
(3) python嚴格要求方法需要有實例才能被調用,即綁定的概念。
舉例:
>>> class C:
def x(self):
print('X-man!')
>>> c = C()
>>> c.x()
X-man!
>>> c.x = 1
>>> c.x
1
>>> c.x() ?#方法名字被屬性名字覆蓋,調用出錯
TypeError: 'int' object is not callable
>>> class BB:
def printBB():
print('no zuo no die.')
>>> BB.printBB()
no zuo no die.
>>> #沒有self,也沒有將類實例化
>>> bb = BB()
>>> bb.printBB()
Traceback (most recent call last):
? File "<pyshell#187>", line 1, in <module>
? ? bb.printBB()
TypeError: printBB() takes 0 positional arguments but 1 was given
>>> class CC:
def setXY(self, x, y):
self.x = x;
self.y = y
>>> class CC:
def setXY(self, x, y):
self.x = x
self.y = y
def printXY(self):
print(self.x, self.y)
>>> dd = CC()
>>> dd.__dict__
{} ?#返回空的字典類型
>>> CC.__dict__
mappingproxy({'printXY': <function CC.printXY at 0x0000020483176EA0>, '__doc__': None, '__dict__': <attribute '__dict__' of 'CC' objects>, 'setXY': <function CC.setXY at 0x0000020483176E18>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'CC' objects>}) ?#使用類對象顯示類的屬性詳情
>>> dd.setXY(4, 5)
>>> dd.__dict__
{'y': 5, 'x': 4} ?#將實例對象dd使用類的屬性詳情實例化了
>>> # setXY(self, x, y) <==> dd.setXY(dd, x, y)
>>> del CC
>>> ee = CC()
NameError: name 'CC' is not defined
>>> dd.printXY()
4 5 ?#類中定義的屬性是靜態的,類的實例對象中也會靜態存儲,所以實例對象dd正常存在。
類與對象的內置函數
issubclass
功能:測試一個類是否是另外一個類的子類
issubclass(class, classinfo)
(1) 一個類被認為是其自身的子類
(2) classinfo可以是類對象的元組,只要class屬于其中任何一個候選類的子類,則返回True
舉例:
>>> class A:
pass
>>> class B(A):
pass
>>> issubclass(B, A)
True
>>> issubclass(B, B)
True
>>> issubclass(B, object) ?#object是所有類的基類
True
>>> class C:
pass
>>> issubclass(B, C)
isinstance
功能:測試一個對象是否是一個類的實例對象
isinstance(object, classinfo)
(1) object為類的實例對象,如果不是類的實例對象,永遠返回False
(2) 如果第二個參數不是類或者由類對象組成的元組,會拋出一個TypeError異常
舉例:
>>> class A:
pass
>>> class B(A):
pass
>>> class C:
pass
>>> b1 = B()
>>> isinstance(b1, B)
True
>>> isinstance(b1, A)
True
>>> isinstance(b1, C)
False
>>> isinstance(b1, (A, B, C)) ?#b1對象是否在A/B/C里面,答案是True
True
hasattr
功能:測試一個對象里面是否有指定的屬性
hasattr(object, name)
(1) object 對象名, name 是屬性名(需要用引號引起來,否則報錯)
getattr
功能:返回對象指定的屬性值
getattr(object, name[, default])
(1) 如果屬性值不存在打印default,沒有default則拋出異常
setattr
功能:設置對象中指定屬性的值,如果屬性不存在則創建并賦值
setattr(object, name, value)
delattr
功能:刪除對象中指定的屬性,如果屬性不存在則拋出異常
delattr(object, name)
舉例:
>>> class C:
def __init__(self, x=0):
self.x = x
>>> c1 = C()
>>> hasattr(c1, 'x') ?#測試對象屬性是否存在
True
>>> hasattr(c1, x)\
NameError: name 'x' is not defined
>>> getattr(c1, 'x') ?#獲取對象屬性的值
0
>>> getattr(c1, 'y')
AttributeError: 'C' object has no attribute 'y'
>>> getattr(c1, 'y', '您所訪問的屬性不存在!') ?#設置default默認提示語
'您所訪問的屬性不存在!'
>>> setattr(c1, 'y', 100) ?#設置對象屬性的值
>>> getattr(c1, 'y')
100
>>> delattr(c1, 'y') ?#刪除對象屬性的值
>>> delattr(c1, 'y')
Traceback (most recent call last):
? File "<pyshell#264>", line 1, in <module>
? ? delattr(c1, 'y')
AttributeError: y
property
功能:設置一個定義好的屬性,通過對象屬性來設置對象屬性
property(fget=None, fset=None, fdel=None, doc=None)
(1) fget獲取屬性的方法, fset設置屬性的方法, fdel刪除屬性的方法
舉例:
>>> class C:
def __init__(self, size=10):
self.size = size
def getSize(self):
return self.size
def setSize(self, value):
self.size = value
def delSize(self):
del self.size
x = property(getSize, setSize, delSize)
>>> c1 = C()
>>> c1.getSize()
10
>>> c1.x
10
>>> c1.x = 18
>>> c1.x
18
>>> c1.getSize()
18
>>> c1.size
18
>>> del c1.x
>>> c1.size ? ?#x與size相當于相互引用關系,刪除其中一個另一個即不能訪問
AttributeError: 'C' object has no attribute 'size'
20丶魔法方法 magic methods
(1) 魔法方法總是被雙下劃綫包圍,如 __init__
(2) 魔法方法是面向對象的python的一切
(3) 魔法方法的魔力體現在能夠在適當的時候被調用
魔法方法匯總:http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
__init__(self[, ...])
功能:初始化類對象(根據需求決定是否增加屬性參數)
返回值: None
舉例:
>>> class Rectangle: #矩形類,需要長和寬,所以重寫__init__
def __init__(self, x, y):
self.x = x
self.y = y
def getPeri(self): ?#獲得周長
return (self.x + self.y) * 2
def getArea(self): ?#獲得面積
return self.x * self.y
>>> rect = Rectangle(3, 4)
>>> rect.getPeri()
14
>>> rect.getArea()
12
__new__(class[, ...])
功能:創建一個類對象
返回值:返回一個對象
(1) 在__init__方法之前被調用,屬于類創建時第一個被調用的方法
舉例:
>>> class CapStr(str): ?#繼承一個不可改變的類型str
def __new__(cls, string): ?#使用new將類型的功能進行轉換
string = string.upper()
return str.__new__(cls, string) ?#把重寫后的str中的new方法帶傳代餐返回
>>> a = CapStr("I love M.")
>>> a
'I LOVE M.'
__del__(self)
功能:對象將要被銷毀的時候,自動調用,屬于自動垃圾回收方法
注意:del x != x.__del__()
舉例:
>>> class C:
def __init__(self):
print('我是init方法,我被調用了!')
def __del__(self):
print('我是del方法,我被調用了!')
>>> c1 = C()
我是init方法,我被調用了!
>>> c2 = c1 ?#對象的賦值不會調用__init__
>>> c3 = c2
>>> del c3
>>> del c2
>>> del c1 ? #其他的賦值對象del時不會調用__del__ (c2和c3只是c1的一份拷貝)
我是del方法,我被調用了!
算術運算魔法方法
__add__(self, other) 加法:+
__sub__(self, other) 減法:-
__mul__(self, other) 乘法:*
__truediv__(self, other) 真除法:/
__floordiv__(self, other) 整數除法://
__mod__(self, other) 取模算法:%
__divmod__(self, other) divmod()調用時的行為
__pow__(self, other[, modulo]) power()調用或 ** 運算時的行為
__lshift__(self, other) 按位左移:<<
__rshift__(self, other) 按位右移:>>
__and__(self, other) 按位與:&
__xor__(self, other) 按位異或:^
__or__(self, other) 按位或:|
舉例:
>>> class New_int(int):
def __add__(self, other):
return int.__sub__(self, other)
def __sub__(self, other):
return int.__add__(self, other)
>>> a = New_int(3)
>>> b = New_int(5)
>>> a + b
-2
>>> a - b
8
>>> class Try_int(int):
def __add__(self, other):
return int(self) + int(other)
def __sub__(self, other):
return int(self) - int(other)
>>> a = Try_int(3)
>>> b = Try_int(5)
>>> a + b
8
類定制的計時器
(1) 定制一個計時器的類
(2) start和stop方法代表啟動計時和停止計時
(3) 假設計時器對象t1,print(t1)和直接調用t1均顯示結果
(4) 當計時器未啟動或已經停止計時,調用stop方法會給與溫馨的提示
(5) 兩個計時器對象可以進行相加:t1 + t2
需要的資源:
(1) 使用time模塊的localtime方法獲取時間
(2) __str__ 方法 __repr__ 方法可用來打印文字
time 模塊
詳解鏈接:http://bbs.fishc.com/forum.php?mod=viewthread&tid=51326&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
struct_time元組
time.struct_time(tm_year=2017, tm_mon=9, tm_mday=2, tm_hour=12, tm_min=18, tm_sec=55, tm_wday=5, tm_yday=245, tm_isdst=0)
類定制計時器代碼:http://blog.csdn.net/sinat_36184075/article/details/77806778
屬性訪問
__getattribute__(self, name) #定義當該類的屬性被訪問時的行為
__getattr__(self, name) #定義當用戶試圖獲取一個不存在的屬性時的行為
__setattr__(self, name, value) #定義當一個屬性被設置(包括初始化)時的行為
__delattr__(self, name) #定義一個屬性被刪除時的行為
舉例:
>>> class C:
def __getattribute__(self, name):
print('getattribute')
return super().__getattribute__(name)
def __getattr__(self, name):
print('getattr')
def __setattr__(self, name, value):
print('setattr')
super().__setattr__(name, value)
def __delattr__(self, name):
print('delattr')
super().__delattr__(name)
>>> c = C()
>>> c.x
getattribute
getattr
>>> c.x = 1
setattr ?#初始化時自動調用setattr
>>> c.x
getattribute
1
>>> del c.x
delattr
舉例:屬性訪問時的嚴重問題,無限遞歸
class Rectangle: ?#矩形
? ? def __init__(self, width=0, height=0): ?#寬高不相等,長方形
? ? ? ? self.width = width
? ? ? ? self.height = height
? ? def __setattr__(self, name, value):
? ? ? ? if name == 'square': ?#寬高相等,正方形
? ? ? ? ? ? self.width = value
? ? ? ? ? ? self.height = value
? ? ? ? else:
? ? ? ? ? ? #self.name = value ? #會導致類無限遞歸自己
? ? ? ? ? ? super().__setattr__(name, value) ?#解決辦法①:super() 推薦。
? ? ? ? ? ? #self.__dict__[name] = value ? ? ?#解決辦法②:字典
? ? def getArea(self):
? ? ? ? return self.width * self.height
運行:
>>> r1 = Rectangle(4, 5)
>>> r1.getArea()
20
>>> r1.square = 10 ?#正方形
>>> r1.width
10
>>> r1.height
10
>>> r1.getArea()
100
>>> r1.__dict__ ?#以字典的形式查看類中的屬性和值
{'width': 10, 'height': 10}
--------------------------------2017.09.03----------------------------------------
描述符 decriptor
描述符就是將某種特殊類型的類的實例指派給另一個類的屬性。
__get__(self, instance, owner) ?#用于訪問屬性,返回屬性的值
__set__(self, instance, value) ?#將在屬性分配操作中調用,不反悔任何內容
__delete__(self, instance) ? ?#控制刪除操作,不返回任何內容
@self, 描述符類本身的類實例
@instance, 擁有者的類實例
@owner, 擁有者類本身
@value, 所賦的值
舉例:
>>> class MyDecriptor:
def __get__(self, instance, owner):
print('getting: ', self, instance, owner)
def __set__(self, instance, value):
print('setting: ', self, instance, value)
def __delete__(self, instance):
print('deleting: ', self, instance)
>>> class Test:
x = MyDecriptor()
>>> #MyDecriptor是x的描述符類
>>> test = Test() ? #實例化Test()類
>>> test.x
getting: ?<__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28> <class '__main__.Test'>
>>> test
<__main__.Test object at 0x000002164DBB6F28>
>>> test.x = 'X-man'
setting: ?<__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28> X-man
>>> del test.x
deleting: ?<__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28>
自定義的描述符
>>> class MyProperty:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, owner):
return self.fget(instance) ?#instance擁有者的實例對象
def __set__(self, instance, value):
self.fset(instance, value)
def __delete__(self, instance):
self.fdel(instance)
>>> class C:
def __init__(self):
self._x = None
def getX(self):
return self._x
def setX(self, value):
self._x = value
def delX(self):
del self._x
x = MyProperty(getX, setX, delX)
>>> c = C()
>>> c.x = 'X-man'
>>> c.x
'X-man' ?#使用x影響_x的值
>>> c._x
'X-man'
>>> del c.x ?#刪除后,c.x和c._x都不存在
練習:溫度轉換
定義一個溫度類,然后定義兩個描述符類用于描述攝氏度和華氏度兩個屬性。
要求兩個屬性會自動進行轉換,也就是說可以給攝氏度這個屬性賦值,打印華氏度是自動轉換后的結果。
代碼:
class Celsius:
? ? def __init__(self, value = 26.0):
? ? ? ? self.value = float(value)
? ? def __get__(self, instance, owner):
? ? ? ? return self.value
? ? def __set__(self, instance, value):
? ? ? ? self.value = float(value)
class Fahrenheit:
? ? def __get__(self, instance, owner): ?#instance就是Temperature(屬性:cel, fah)
? ? ? ? return instance.cel * 1.8 + 32
? ? def __set__(self, instance, value):
? ? ? ? #instance.cel = ('%.1f' % ((float(value) - 32) / 1.8)) ?#控制精度方法1
? ? ? ? instance.cel = round((float(value) - 32) / 1.8, 1) ? ? ?#控制精度方法2
class Temperature:
? ? cel = Celsius() ?#攝氏度
? ? fah = Fahrenheit() ?#華氏度, fah在實例對象中被賦值時調用對應類的__set__
運行:
>>> temp = Temperature()
>>> temp.cel
26.0
>>> temp.cel = 30
>>> temp.fah
86.0
>>> temp.fah = 100
>>> temp.cel
37.8
定制序列(容器)
(1) 如果希望定制的容器不可變,只需要定義魔法方法__len__()和__getitem__()
(2) 如果希望定制的容器可變,需要定義__len__()和__getitem__()和__setitem__()和__delitem__()
魔法方法詳解:
http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
練習:
編寫一個不可改變的自定義列表,要求記錄列表中每個元素被訪問的次數。
class CountList:
? ? def __init__(self, *args): ?#*args, 參數數量可變
? ? ? ? self.values = [x for x in args]
? ? ? ? self.count = {}.fromkeys(range(len(self.values)), 0)
? ? def __len__(self):
? ? ? ? return len(self.values)
? ? def __getitem__(self, key):
? ? ? ? self.count[key] += 1
? ? ? ? return self.values[key]
運行:
>>> c1 = CountList(1, 3, 5, 7, 9)
>>> c2 = CountList(2, 4, 6, 7, 10)
>>> c1[1] ?#c1[1] == 3被訪問1次
3
>>> c2[1]
4
>>> c1[1] + c2[1] ?#c1[1] == 3被訪問2次
7
>>> c1.count
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
>>> c1[1] ?#c1[1] == 3被訪問3次
3
>>> c1.count
{0: 0, 1: 3, 2: 0, 3: 0, 4: 0}
迭代器 iter-next
iter
iter() 內置方法, 功能:返回一個迭代器對象
__iter__() 魔法方法
next
next() 內置方法
__next__() ?魔法方法
for循環迭代器:
>>> links = {'百度':'http://www.baidu.com', \
'谷歌':'http://www.google.com', \
'搜狗':'http://www.sougou.com', \
'騰訊':'http://www.qq.com'}
>>> for each in links:
print("%s -> %s" % (each, links[each]))
谷歌 -> http://www.google.com
搜狗 -> http://www.sougou.com
騰訊 -> http://www.qq.com
百度 -> http://www.baidu.com
iter迭代器:
>>> string = 'yuan.jiang'
>>> it = iter(string)
>>> while True:
try:
each = next(it)
except StopIteration:
break;
print(each, end=' ')
運行:
y u a n . j i a n g?
斐波那契數列迭代器
>>> class Fibs: ?#斐波那契數列
def __init__(self, n=10): ? ?#加一個參數n控制迭代范圍
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self ?#本身就是一個迭代器
def __next__(self):
self.a, self.b = self.b, self.a+self.b
if self.a > self.n:
raise StopIteration
return self.a
>>> fibs = Fibs()
>>> for each in fibs:
print(each, end=' ')
1 1 2 3 5 8
>>> fibs = Fibs(100)
>>> for each in fibs:
print(each, end=' ')
1 1 2 3 5 8 13 21 34 55 89
生成器 yield
(1) 生成器是一種特殊的迭代器,兼容next()內置方法
(2) 生成器模仿了協同程序
協同程序:可以運行的對立函數調用,函數可以暫停或掛起,并再需要的時候從程序離開的地方繼續活著重新開始。
舉例:
>>> def MyGen():
print('生成器被執行!')
yield 1
yield 2
>>> myg = MyGen()
>>> next(myg)
生成器被執行!
1
>>> next(myg)
2
>>> next(myg)
StopIteration
>>> for i in MyGen(): ?#for循環自動檢測迭代器的StopIteration異常
print(i)
生成器被執行!
1
2
>>> def fibs():
a = 0
b = 1
while True:
a, b = b, a+b
yield a
>>> for each in fibs():
if each > 100:
break
print(each, end=' ')
1 1 2 3 5 8 13 21 34 55 89?
列表推導式
>>> a = [i for i in range(100) if not (i % 2) and (i % 3)] ?#列表推導式
>>> a
[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]
>>> b = {i:i % 2 == 0 for i in range(10)} ?#字典推導式(例子:小于10以內的偶數)
>>> b
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}
>>> c = {i for i in [1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 3, 2, 1]} ?#集合推導式(元素不重復)
>>> c
{1, 2, 3, 4, 5, 6, 7, 8}
#沒有字符串推導式,引號內的強制解釋為字符串
>>> e = (i for i in range(10)) ?#沒有元組推導式,()小括號生成的是生成器推導式
>>> e
<generator object <genexpr> at 0x00000261E200A7D8>
>>> next(e)
0
>>> next(e)
1
>>> for each in e:
print(each, end=' ')
2 3 4 5 6 7 8 9?
>>> sum(i for i in range(100) if i % 2)
2500
生成器擴展閱讀:
http://bbs.fishc.com/forum.php?mod=viewthread&tid=56023&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
21丶模塊 module
容器 -> 數據的封裝
函數 -> 語句的封裝
類 ? -> 方法和屬性的封裝
模塊 -> 程序的封裝,其實就是.py的python程序
(1) import導入的.py模塊文件必須放在與python.exe同一目錄下,即可正確導入。
(2) 導入方法有三種:
① import 模塊名
② from 模塊名 import 函數名1, 函數名2, ... ?#不建議這樣用,可能會覆蓋系統函數
③ import 模塊名 as 新名字
舉例:
在python下新建test_module文件夾:C:\python\test_module
C:\python\test_module\TempeatureConversion.py
C:\python\test_module\calc.py
#TempeatureConversion.py
def c2f(cel):
? ? fah = cel * 1.8 + 32
? ? return fah
def f2c(fah):
? ? cel = round((fah - 32) / 1.8, 1)
? ? return cel
#calc.py
import TemperatureConversion as tc
print('32攝氏度 = %.1f華氏度' % tc.c2f(32))
print('99華氏度 = %.1f攝氏度' % tc.f2c(99))
運行calc.py:
=================== RESTART: C:\python\test_module\calc.py ===================
32攝氏度 = 89.6華氏度
99華氏度 = 37.2攝氏度
>>>?
__name__
if __name__ = '__main__': ?#決定是.py文件中的代碼是當前程序運行,還是導入到其他程序中作為模塊使用而運行
作用:限制為自身.py程序運行才執行的代碼區域
搜索路徑 path
(1) 最佳存放模塊的目錄:C:\\python\\lib\\site-packages
>>> import sys
>>> sys.path
['', 'C:\\python\\Lib\\idlelib', 'C:\\python\\python35.zip', 'C:\\python\\DLLs', 'C:\\python\\lib', 'C:\\python', 'C:\\python\\lib\\site-packages']
>>> sys.path.append('C:\\python\\test_module') ?#自定義的模塊目錄可以append進去
>>> sys.path
['', 'C:\\python\\Lib\\idlelib', 'C:\\python\\python35.zip', 'C:\\python\\DLLs', 'C:\\python\\lib', 'C:\\python', 'C:\\python\\lib\\site-packages', 'C:\\python\\test_module']
>>> import TemperatureConversion as temp
>>> temp.c2f(32)
89.6
包 package
(1) python目錄下創建一個文件夾,用于存放相關的模塊,文件夾的名字即包(package)的名字
(2) 在文件夾中創建一個 __init__.py 的模塊文件,內容可以為空
舉例:
C:\python\test_module\calc.py
C:\python\test_module\M1\TemperatureConversion.py ?#M1文件夾名,即為包名
C:\python\test_module\M1\__init__.py ?#告訴python運行時將其解釋為包
#calc.py中修改為:包名.模塊名
import M1.TemperatureConversion as tc
print('32攝氏度 = %.1f華氏度' % tc.c2f(32))
print('99華氏度 = %.1f攝氏度' % tc.f2c(99))
自帶電池:python標準庫
(1) 電池:python-IDLE 幫助文檔 F1
(2) 來自全球開發者貢獻的python模塊:https://pypi.python.org/pypi
#也可以自己寫模塊發布上去。
(3) PEP:python增強建議書,規范與定義python各種加強和延伸功能的技術規格,即參考標準
(4) PEP規范內容歷史:http://www.python.org/dev/peps
(5) IDLE中模塊信息查看:
>>> import timeit
>>> print(timeit.__doc__) ?#幫助文檔
>>> dir(timeit) ?#內置方法
>>> timeit.__all__ ?#__all__屬性是可供外界調用的類或接口函數
>>> timeit.__file__ ?#__file__屬性是顯示模塊源代碼在本地的位置(學習高手的代碼)
>>> help(timeit) ?#幫助文檔
timeit 模塊詳解
地址:http://bbs.fishc.com/thread-55593-1-1.html
22丶python實例:網絡爬蟲
python訪問網絡: urllib (是個包模塊)
URL一般格式:
protocol://hostname[:port]/path/[;parameters][?query]#fragment
URL三部分組成:
(1) 協議:http, https, ftp, file, ed2k...
(2) 域名/IP地址:如http默認端口號80
(3) 資源具體地址:如目錄或文件名
查看幫助文檔后發現urllib包有4個模塊:
urllib.request #for opening and reading URLs?
urllib.error #containing the exceptions raised by urllib.request?
urllib.parse #for parsing URLs?
urllib.robotparser #for parsing robots.txt files?
嘗鮮:
>>> import urllib.request
>>> response = urllib.request.urlopen('http://www.fishc.com')
>>> html = response.read()
>>> print(html)
b'\xef...\r\n</html>\r\n' ?#整個網頁的二進制文件以16進制顯示
>>> html = html.decode('utf-8') ?#按其編碼方式解碼
>>> print(html)
"""
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
</body>
</html>
"""
訪問網頁內容存儲本地
舉例:
import urllib.request as url_req
response = url_req.urlopen('http://placekitten.com/g/1920/1080')
cat_img = response.read()
with open('cat_1920_1080.jpg', 'wb') as f:
? ? f.write(cat_img)
運行:
會生成這個文件:C:\Users\Jan\Desktop\python_study\cat_1920_1080.jpg
實現POST請求 - 自動翻譯機
import urllib.request as url_req
import urllib.parse ? as url_prs
import json ?#json, 輕量級的數據交換格式
while True:
? ? content = input('請輸入需要翻譯的內容<.q退出>:')
? ? if content == '.q':
? ? ? ? break
? ? else:
? ? ? ? #注意url地址<有道翻譯>,按小甲魚視頻中的可能不對,需到網上查別人的
? ? ? ? url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=http://www.youdao.com/'
? ? ? ? data = {} ? #字典類型
? ? ? ? data['type'] = 'AUTO'
? ? ? ? data['i'] = content
? ? ? ? data['doctype'] = 'json'
? ? ? ? data['xmlVersion'] = '1.8'
? ? ? ? data['keyfrom'] = 'fanyi.web'
? ? ? ? data['ue'] = 'UTF-8'
? ? ? ? data['action'] = 'FY_BY_CLICKBUTTON'
? ? ? ? data['typoResult'] = 'true'
? ? ? ? data = url_prs.urlencode(data).encode('utf-8')
? ? ? ? response = url_req.urlopen(url, data)
? ? ? ? html = response.read().decode('utf-8')
? ? ? ? target = json.loads(html)
? ? ? ? print('翻譯結果:%s' % (target['translateResult'][0][0]['tgt']))
#缺陷:能夠被識別為代碼訪問,而非瀏覽器,即非人類訪問
運行:
========= RESTART: C:\Users\Jan\Desktop\python_study\translation.py =========
請輸入需要翻譯的內容<.q退出>:生存,還是毀滅,這是一個問題
翻譯結果:To survive, or not to be, this is a problem
請輸入需要翻譯的內容<.q退出>:To be or not to be, it's a question.
翻譯結果:生存還是毀滅,這是一個問題。
請輸入需要翻譯的內容<.q退出>:.q
>>>?
修改header
(1) 通過Request的headers參數修改,字典形式
(2) 通過Request.add_header()方法修改
追加header模擬瀏覽器訪問:
import urllib.request as url_req
import urllib.parse ? as url_prs
import json ?#json, 輕量級的數據交換格式
while True:
? ? content = input('請輸入需要翻譯的內容<.q退出>:')
? ? if content == '.q':
? ? ? ? break
? ? else:
? ? ? ? #注意url地址,視頻中的可能不對需到網上查
? ? ? ? url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=http://www.youdao.com/'
? ? ? ? #header方法1:創建字典,請求中傳參
? ? ? ? '''
? ? ? ? head = {} ?#模擬瀏覽器訪問 Request Headers
? ? ? ? head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
? ? ? ? '''
? ? ? ? data = {} ?#From data
? ? ? ? data['type'] = 'AUTO'
? ? ? ? data['i'] = content
? ? ? ? data['doctype'] = 'json'
? ? ? ? data['xmlVersion'] = '1.8'
? ? ? ? data['keyfrom'] = 'fanyi.web'
? ? ? ? data['ue'] = 'UTF-8'
? ? ? ? data['action'] = 'FY_BY_CLICKBUTTON'
? ? ? ? data['typoResult'] = 'true'
? ? ? ? data = url_prs.urlencode(data).encode('utf-8')
? ? ? ? '''req = url_req.Request(url, data, head) ?#調用請求的方法:data, head '''
? ? ? ? #header方法2:請求中追加header
? ? ? ? req = url_req.Request(url, data)
? ? ? ? req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36')
? ? ? ? response = url_req.urlopen(req)
? ? ? ? html = response.read().decode('utf-8')
? ? ? ? target = json.loads(html)
? ? ? ? print('翻譯結果:%s' % (target['translateResult'][0][0]['tgt']))
運行:
========= RESTART: C:\Users\Jan\Desktop\python_study\translation.py =========
請輸入需要翻譯的內容<.q退出>:生存,還是毀滅,這是一個問題
翻譯結果:To survive, or not to be, this is a problem
請輸入需要翻譯的內容<.q退出>:To be or not to be, it's a question.
翻譯結果:生存還是毀滅,這是一個問題。
請輸入需要翻譯的內容<.q退出>:.q
>>>?
代理
作用:讓爬蟲偽裝瀏覽器請求,讓http服務器不會認為是非人類訪問。
步驟:
(1) 參數是一個字典{'類型':'代理ip:端口號'}
proxy_support = urllib.request.ProxyHandler({})
(2) 定制、創建一個opener
opener = urllib.request.build_opener(proxy_support)
(3) 安裝opener
urllib.request.install_opener(opener)
(4) 調用opener
opener.open(url)
#或:urllib.request.urlopen(url)
代碼:
import urllib.request as url_req
import random
url = 'http://www.whatismyip.com.tw' ?#這個網站訪問它會顯示自己的ip地址
#待完善:抓取代理ip網站上的ip和端口,存入iplist
iplist = ['115.197.136.78:8118', '118.250.50.69:80', '183.133.81.57:8118', ?'113.77.240.236:9797', '139.129.166.68:3128'] ?#使用random隨機取ip
#網上查的免費代理ip網站:http://www.xicidaili.com/
proxy_support = url_req.ProxyHandler({'http':random.choice(iplist)})
opener = url_req.build_opener(proxy_support)
#headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
opener.addheaders = [('User-Agent', 'Chrome/55.0.2883.87')]
url_req.install_opener(opener)
#req = url_req.Request(url, headers=headers)
#response = url_req.urlopen(req)
response = url_req.urlopen(url)
html = response.read().decode('utf-8')
print(html)
補充:
Beautiful Soup 是用Python寫的一個HTML/XML的解析器,使用安裝python-IDLE時附帶的pip命令,直接在windows下執行:
C:\python> pip install bs4
#一鍵安裝搞定,python中測試能否導入成功
>>> from bs4 import BeautifulSoup
>>> #成功導入,失敗會報異常。
采集代理ip
import urllib.request as url_req
from bs4 import BeautifulSoup ?#此庫需要安裝:win-cmd執行"pip install bs4"即可
import random
import pprint as ppr
#這個網站訪問它會顯示自己的ip地址
display_ip_url = 'http://www.whatismyip.com.tw' ? #'http://ip.chinaz.com/getip.aspx'
#代理ip網站, http協議類型
proxy_ip_url = 'http://www.xicidaili.com/wt/'
header = {}
header['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
def getProxyIp(): ?#獲取代理ip
? ? proxyip_list = []
? ? for i in range(1, 2):
? ? ? ? try:
? ? ? ? ? ? url = proxy_ip_url + str(i) ?#抓取前2頁
? ? ? ? ? ? req = url_req.Request(url, headers=header)
? ? ? ? ? ? res = url_req.urlopen(req).read()
? ? ? ? ? ? soup = BeautifulSoup(res, "html.parser") ?#BeautifulSoup(markup, “html.parser”) html解析器
? ? ? ? ? ? ips = soup.findAll('tr') ?#findAll()搜索解析器解析出來的html文檔樹
? ? ? ? ? ? for x in range(1, len(ips)):
? ? ? ? ? ? ? ? ip = ips[x]
? ? ? ? ? ? ? ? tds = ip.findAll('td') ?#ip和端口都在tr標簽中的td標簽中
? ? ? ? ? ? ? ? ip_tmp = tds[1].contents[0] + ':' + tds[2].contents[0]
? ? ? ? ? ? ? ? proxyip_list.append(ip_tmp) ?#追加到列表
? ? ? ? except:
? ? ? ? ? ? continue
? ? return proxyip_list
iplist = getProxyIp()
#print(iplist) ? #for test
ppr.pprint(iplist) ?#以更規范的格式顯示輸出結果
#第一步:ProxyHandler傳參
ip_port = random.choice(iplist)
proxy_support = url_req.ProxyHandler({'http':ip_port}) ?#從列表中隨機選擇代理ip和端口項
print('ip:port ? ?' + ip_port)
#第二步:opener創建
opener = url_req.build_opener(proxy_support)
#第三步:opener安裝
opener.addheaders = [('User-Agent', 'Chrome/55.0.2883.87')]
url_req.install_opener(opener)
#第四步:opener調用
#response = url_req.urlopen(display_ip_url)
response = opener.open(display_ip_url) ?
html = response.read().decode('utf-8')
print(html)
運行:
======== RESTART: C:\Users\Jan\Desktop\python_study\proxy_support.py ========
<!DOCTYPE HTML>
<html>
? <head>
? ...
? </head>
? <body>
? <h1>IP位址</h1>
? <span data-ip='183.56.177.130'><b style='font-size: 1.5em;'>183.56.177.130</b> ?</span>
? <span data-ip-country='CN'><i>CN</i></span>
? <h1>真實IP</h1>
? <span data-ip-real='113.110.143.94'><b style='font-size: 1.5em;'>113.110.143.94</b></span>
? <span data-ip-real-country='CN'><i>CN</i></span>
? <script type="application/json" id="ip-json">
{
"ip": "183.56.177.130",
"ip-country": "CN",
"ip-real": "113.110.143.94",
"ip-real-country": "CN"
}
? </script>
? ...
? </body>
</html>
--------------------------------2017.09.04----------------------------------------
urllib.request 返回響應后的內置方法
import urllib.request as url_req
req = url_req.Request('http://url')
res = url_req.urlopen(req) #打開一個鏈接,參數可以是一個字符串或者Request對象
res.geturl() #返回鏈接的字符串,即urlopen的字符串參數
res.info() #返回http響應數據包的頭headers, 輸出:print(res.info())
res.getcode() #返回http響應的狀態碼
舉例:
=============== RESTART: C:/Users/Jan/Desktop/download_cat.py ===============
>>> res.geturl()
'http://placekitten.com/g/500/600'
>>> res.info()
<http.client.HTTPMessage object at 0x0000022E09C006D8>
>>> res.headers
<http.client.HTTPMessage object at 0x0000022E09C006D8>
>>> print(res.info())
Date: Mon, 04 Sep 2017 13:11:21 GMT
Content-Type: image/jpeg
Content-Length: 26590
Connection: close
Set-Cookie: __cfduid=d8354310653b8846db674de048175187b1504530681; expires=Tue, 04-Sep-18 13:11:21 GMT; path=/; domain=.placekitten.com; HttpOnly
Accept-Ranges: bytes
X-Powered-By: PleskLin
Access-Control-Allow-Origin: *
Cache-Control: public
Expires: Thu, 31 Dec 2020 20:00:00 GMT
Server: cloudflare-nginx
CF-RAY: 399131b5435b6d4e-SJC
>>> res.getcode()
200
python爬蟲下載妹子圖
代碼:#代理ip不太穩定,免費代理很多時好時壞
import urllib.request
import os
import random
import pprint as ppr
from bs4 import BeautifulSoup
header = {}
header_key = 'User-Agent'
header_value = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
header[header_key] = header_value
def get_proxy_ip(): ?#獲取代理ip
? ? proxyip_list = []
? ? proxy_ip_url = 'http://www.xicidaili.com/wt/'
? ? for i in range(1, 2):
? ? ? ? try:
? ? ? ? ? ? url = proxy_ip_url + str(i)
? ? ? ? ? ? req = urllib.request.Request(url, headers=header)
? ? ? ? ? ? res = urllib.request.urlopen(req).read()
? ? ? ? ? ? soup = BeautifulSoup(res, "html.parser")
? ? ? ? ? ? ips = soup.findAll('tr')
? ? ? ? ? ? for x in range(1, len(ips)):
? ? ? ? ? ? ? ? ip = ips[x]
? ? ? ? ? ? ? ? tds = ip.findAll('td')
? ? ? ? ? ? ? ? ip_tmp = tds[1].contents[0] + ':' + tds[2].contents[0]
? ? ? ? ? ? ? ? proxyip_list.append(ip_tmp)
? ? ? ? except:
? ? ? ? ? ? continue
? ? return proxyip_list
#打開url接口函數
def url_open(url):
? ? req = urllib.request.Request(url)
? ? req.add_header(header_key, header_value)
? ? '''
? ? #使用代理模擬真人訪問而不是代碼訪問
? ? iplist = get_proxy_ip()
? ? #ppr.pprint(iplist) ?#for test
? ? ip_port = random.choice(iplist)
? ? proxy_support = urllib.request.ProxyHandler({'http':ip_port})
? ? print('ip:port ? ?' + ip_port) ?#for test
? ? opener = urllib.request.build_opener(proxy_support)
? ? opener.addheaders = [('User-Agent', 'Chrome/55.0.2883.87')]
? ? urllib.request.install_opener(opener)
? ? '''
? ? res = urllib.request.urlopen(url)
? ? html = res.read()
? ? print(url)
? ? return html
def get_page(url):
? ? html = url_open(url).decode('utf-8')
? ? a = html.find('current-comment-page') + 23
? ? b = html.find(']', a) ?#從a位置開始找到一個]符號
? ? print (html[a:b]) ?#for test
? ? return html[a:b]
def find_imgs(url):
? ? html = url_open(url).decode('utf-8')
? ? img_addrs = []
? ? a = html.find('img src=') ?#找到 img src= 的位置
? ? while a != -1:
? ? ? ? b = html.find('.jpg', a, a+255) ? #找到從a位置開始,以 .jpg 結尾的地方
? ? ? ? if b != -1: ?#find找不到時返回-1
? ? ? ? ? ? img_addrs.append('http:' + html[a+9:b+4]) ?#圖片鏈接地址追加到列表中, 9=len('img src="'), 4=len('.jpg')
? ? ? ? else:
? ? ? ? ? ? b = a + 9
? ? ? ??
? ? ? ? a = html.find('img src=', b) ? ? ?#下一次循環所找的位置就是從b開始
? ? #for each in img_addrs:
? ? # ? ?print(each)
? ? return img_addrs
def save_imgs(folder, img_addrs):
? ? for each in img_addrs:
? ? ? ? filename = each.split('/')[-1] ?#split以/分割字符串,-1取最后一個元素
? ? ? ? with open(filename, 'wb') as f:
? ? ? ? ? ? img = url_open(each)
? ? ? ? ? ? f.write(img)
def download_mm(folder='mm_dir', pages=25):
? ? if os.path.exists(folder):
? ? ? ? os.chdir(folder)
? ? else:
? ? ? ? os.mkdir(folder)
? ? ? ? os.chdir(folder)
? ? url = 'http://jandan.net/ooxx/' ?#實際圖源來源于新浪服務器
? ? page_num = int(get_page(url)) ? ?#函數get_page()
? ? for i in range(pages):
? ? ? ? page_num -= i
? ? ? ? page_url = url + 'page-' + str(page_num) + '#comments'
? ? ? ? img_addrs = find_imgs(page_url) ?#函數find_imgs()
? ? ? ? save_imgs(folder, img_addrs)
if __name__ == '__main__':
? ? download_mm()
--------------------------------2017.09.05----------------------------------------
正則表達式
"我知道,可以使用正則表達式解決現在遇到的難題。"于是,現在他就有兩個問題了。
>>> import re
>>> re.search(r'Hello', 'I love you, Hello!~') ?#search()方法用于在字符串中搜索正則表達式模式第一次出現的位置
<_sre.SRE_Match object; span=(12, 17), match='Hello'> ?#第12-16個字符位置
>>> re.search(r'lo', 'hello')
<_sre.SRE_Match object; span=(3, 5), match='lo'>
>>> 'hello'.find('lo')
3
#.點號:匹配除了換行符的任何字符
>>> re.search(r'.', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(0, 1), match='I'>
#匹配點號本身,使用\反斜杠轉義即可
>>> re.search(r'\.', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(17, 18), match='.'>
#\d表示匹配一個0~9的數字
>>> re.search(r'\d', 'I love 123, baidu.com!~')
<_sre.SRE_Match object; span=(7, 8), match='1'>
>>> re.search(r'\d\d\d', 'I love 123, baidu.com!~')
<_sre.SRE_Match object; span=(7, 10), match='123'>
>>> re.search(r'\d\d\d.\d\d\d.\d\d\d.\d\d\d', '192.168.111.123:8080')
<_sre.SRE_Match object; span=(0, 15), match='192.168.111.123'>
>>> re.search(r'\d\d\d.\d\d\d.\d\d\d.\d\d\d', '192.168.1.1') #無法匹配,位數不同
#使用[]創建一個字符類
>>> re.search(r'[aeiou]', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(3, 4), match='o'>
>>> re.search(r'[aeiouAEIOU]', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(0, 1), match='I'>
#-短杠:表示匹配的范圍
>>> re.search(r'[a-z]', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(2, 3), match='l'>
>>> re.search(r'[0-9]', 'I love 123, baidu.com!~')
<_sre.SRE_Match object; span=(7, 8), match='1'>
#{}大括號:來限定匹配的次數
>>> re.search(r'ab{3}c', 'zabbbcz')
<_sre.SRE_Match object; span=(1, 6), match='abbbc'>
#{}3,10代表3到10次重復次數,不能有空格出現
>>> re.search(r'ab{3, 10}c', 'zabbbbbcz')
>>> re.search(r'ab{3,10}c', 'zabbbbbcz')
<_sre.SRE_Match object; span=(1, 8), match='abbbbbc'>
>>> re.search(r'[0-2][0-5][0-5]', '188') ?#錯誤示范
>>> re.search(r'[0-255]', '188') ?#0,1,2,5其中任何一個,匹配
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.search(r'[01]\d\d|2[0-4]\d|25[0-5]', '188') ?#0-255正則表達式
<_sre.SRE_Match object; span=(0, 3), match='188'>
#ip地址正則表達式
>>> re.search(r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])', '192.168.1.1')
<_sre.SRE_Match object; span=(0, 11), match='192.168.1.1'>
>>> re.search(r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])', '255.255.255.0')
<_sre.SRE_Match object; span=(0, 13), match='255.255.255.0'>
#此ip表達式的一點bug:
>>> re.search(r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])', '11192.168.41.8888')
<_sre.SRE_Match object; span=(2, 15), match='192.168.41.88'>
#ip地址匹配的正則表達式【嚴謹版】
import re
ptnIP = re.compile(r'(?<![\d.])' # 前導 無 數字和小數點
? ? ? ? ? ? ? ? ? ?r'(?:(?:'
? ? ? ? ? ? ? ? ? ?r'[01]?\d?\d' # ? 0 ~ 199
? ? ? ? ? ? ? ? ? ?r'|2[0-4]\d' ?# 200 ~ 249
? ? ? ? ? ? ? ? ? ?r'|25[0-5])' ?# 250 ~ 255
? ? ? ? ? ? ? ? ? ?r'\.){3}' ? ? # 3組 xxx.
? ? ? ? ? ? ? ? ? ?r'(?:'
? ? ? ? ? ? ? ? ? ?r'[01]?\d?\d'
? ? ? ? ? ? ? ? ? ?r'|2[0-4]\d'
? ? ? ? ? ? ? ? ? ?r'|25[0-5])'
? ? ? ? ? ? ? ? ? ?r'(?![\d.])' ?# 后續 無 數字和小數點
? ? ? ? ? ? ? ? ? )
test_IP = (
? ? ? ? '0.0.0.0'
? ? ? ? ';1.22.333.444' ? ? ? ? #不合法
? ? ? ? ';2.0.0.256' ? ? ? ? ? ?#不合法
? ? ? ? ';3.22.33.23333333' ? ? #不合法
? ? ? ? ';4.2.3.4.5' ? ? ? ? ? ?#不合法
? ? ? ? ';5.111.222.99'
? ? ? ? ';6.0.0.0'
? ? ? ? ';7.234.234.234'
? ? ? ? ';255.255.255.255'
? ? ? ? ';234.234.234.234'
? ? ? ? ';1192.168.41.888' ? ? ?#不合法
? ? ? ? )
match = ptnIP.findall(test_IP)
print(match)
運行:
========== RESTART: C:\Users\Jan\Desktop\python_study\ip_regular.py ==========
['0.0.0.0', '5.111.222.99', '6.0.0.0', '7.234.234.234', '255.255.255.255', '234.234.234.234'] ?#輸出均為合法ip
--------------------------------2017.09.07----------------------------------------
Python3 正則表達式特殊符號及用法(詳細列表)
http://blog.csdn.net/riba2534/article/details/54288552
正則表達式舉例:
import urllib.request
import re
header = {}
header_key = 'User-Agent'
header_value = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
header[header_key] = header_value
def open_url(url):
? ? req = urllib.request.Request(url)
? ? req.add_header(header_key, header_value)
? ? page = urllib.request.urlopen(req)
? ? html = page.read().decode('utf-8')
? ? return html
def get_img(html):
? ? p = r'<img class="BDE_Image" src="([^"]+\.jpg)' ?# 正則表達式匹配貼吧圖片鏈接
? ? imglist = re.findall(p, html) ?# findall中的p包含子組()的話,會單獨返回子組
? ? # test start
? ? for each in imglist:
? ? ? ? print(each)
? ? # test end
? ? for each in imglist:
? ? ? ? filename = each.split("/")[-1]
? ? ? ? urllib.request.urlretrieve(each, filename, None)
if __name__ == '__main__':
? ? url = 'https://tieba.baidu.com/p/5310571187' ?# 下載百度貼吧圖片示例
? ? get_img(open_url(url))
運行:
https://imgsa.baidu.com/forum/w%3D580/sign=0b340d2849a7d933bfa8e47b9d4ad194/f1f8e3dde71190ef7241a5e3c51b9d16fcfa60a4.jpg
https://imgsa.baidu.com/forum/w%3D580/sign=6ff2514ff0f2b211e42e8546fa816511/fe4fbf014a90f6030c47ab7b3212b31bb151ed60.jpg
https://imgsa.baidu.com/forum/w%3D580/sign=7f8aadd5f9d3572c66e29cd4ba136352/b9dc748b4710b912bda70cc2c8fdfc03934522f1.jpg
優化采集代理ip:
import urllib.request
import re
header = {}
header_key = 'User-Agent'
header_value = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
header[header_key] = header_value
def open_url(url):
? ? req = urllib.request.Request(url)
? ? req.add_header(header_key, header_value)
? ? page = urllib.request.urlopen(req)
? ? html = page.read().decode('utf-8')
? ? return html
def get_ip(html):
? ? ptnIP = (r'(?<![\d.])' # 前導 無 數字和小數點
? ? ? ? ? ? ?r'(?:(?:'
? ? ? ? ? ? ?r'[01]?\d?\d' # ? 0 ~ 199
? ? ? ? ? ? ?r'|2[0-4]\d' ?# 200 ~ 249
? ? ? ? ? ? ?r'|25[0-5])' ?# 250 ~ 255
? ? ? ? ? ? ?r'\.){3}' ? ? # 3組 xxx.
? ? ? ? ? ? ?r'(?:'
? ? ? ? ? ? ?r'[01]?\d?\d'
? ? ? ? ? ? ?r'|2[0-4]\d'
? ? ? ? ? ? ?r'|25[0-5])'
? ? ? ? ? ? ?r'(?![\d.])') # 后續 無 數字和小數點
? ? iplist = re.findall(ptnIP, html) ?# findall中的p包含子組()的話,會單獨返回子組
? ? # test start
? ? for each in iplist:
? ? ? ? print(each)
? ? # test end
if __name__ == '__main__':
? ? url = 'http://www.xicidaili.com/wt/' ?# 下載代理ip
? ? get_ip(open_url(url))
異常處理
URLError 舉例:
>>> import urllib.request
>>> import urllib.error
>>> req = urllib.request.Request('http://www.ooxx-hello.com') ?#打開一個不存在的鏈接
>>> try:
urllib.request.urlopen(req)
except urllib.error.URLError as e:
print(e.reason)
[Errno 11001] getaddrinfo failed ?#錯誤信息
HTTPError 舉例:
>>> import urllib.request
>>> import urllib.error
>>> req = urllib.request.Request('http://www.fishC.com/ooxx.html')
>>> try:
urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
print(e.code)
print(e.read())
404
b'<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested URL /ooxx.html was not found on this server.</p>\n<hr>\n<address>Apache Server at www.fishc.com Port 80</address>\n</body></html>\n'
處理異常的寫法:
from urllib.request import Request, urlopen
from urllib.error import URLError
req = Request('http://someurl/')
try:
response = urlopen(req)
except URLError as e:
if hasattr(e, 'reason'):
print('We failed to reach a server.')
print('Reason: ', e.reason)
elif hasattr(e, 'code'):
print('The server couldn\'t fulfill the request.')
print('Error code: ', e.code)
else:
#everything is fine.
--------------------------------2017.09.08----------------------------------------
Scrapy爬蟲框架
① Scrapy的安裝與環境搭建
Scrapy對應python2.7的版本。(安裝過程中如遇任何問題均可百度搜索一下,這是程序員必須學會的快速解決問題的辦法)
1. 安裝python2.7(32位版本)
安裝包:python-2.7.6-win32.msi
設置環境變量:win-運行-cmd
> C:\Python27\python.exe C:\Python27\tools\Scripts\win_add2path.py
重啟windows系統,驗證安裝是否成功:
> python --version
#如果顯示是3.多的版本,請參考python2/3版本切換任性切換設置:http://blog.csdn.net/sinat_36184075/article/details/77872708
2. 安裝pywin32(32位版本)
安裝包:pywin32-215.win32-py2.7.exe
3. 安裝python2.7的pip程序
安裝程序:get-pip.py
安裝方法:win-cmd> python C:\python\Scrapy\get-pip.py
先把pip的路徑添加到windows的環境變量中。
重啟windows系統,驗證安裝是否成功:
> pip --version
#如果沒有顯示版本信息,請參考pip2/3任性切換設置:http://blog.csdn.net/sinat_36184075/article/details/77872708
4. 安裝lxml
安裝環境包:VCForPython27.msi
> pip2 install lxml
#如果pip2的路徑有添加到windows中的話,安裝可以成功。如果不成功,使用下面安裝包安裝
安裝包:lxml-3.2.3.win32-py2.7.exe
5. 安裝OpenSSL
> pip2 install pyOpenSSL
#如果pip2的路徑有添加到windows中的話,安裝可以成功。如果不成功,使用下面安裝包安裝
安裝包:egenix-pyopenssl-0.13.7.win32-py2.7.msi
6. 安裝Scrapy
> pip2 install service_identity
> pip2 install Scrapy
驗證是否安裝成功:
> Scrapy
#如果提示找不到命令的話,可能需要一個工具環境支持:Twisted-15.0.0.win32-py2.7.msi
安裝完Twisted后再次嘗試驗證即可。
② Scrapy框架爬蟲程序初探
一個為了爬取網站數據,提取結構性數據而編寫的應用框架。最初是為了頁面抓取所設計的,也可以應用在獲取API所訪問的數據上,或者說通用的網絡爬蟲上。
使用Scrapy抓取一個網站一共需要四個步驟:
1. 創建一個Scrapy項目;
2. 定義Item容器;
3. 編寫爬蟲;
4. 存儲內容。
---Scrapy框架(官網)圖示---
實驗網站對象:www.dmoz.org
1. 創建一個Scrapy項目:crawler
C:\Users\Jan\Desktop\python_study>Scrapy startproject crawler
#crawler是我們的項目名稱
在\python_study\crawler\文件夾中即是我們的爬蟲框架。
Item是保存爬取到的數據的容器,其使用方法和python字典類似,并且提供了額外保護機制來避免拼寫錯誤導致的未定義字段錯誤。
2. 定義Item容器:
#crawler\crawler\items.py
import scrapy
class CrawlerItem(scrapy.Item):
? ? # define the fields for your item here like:
? ? # name = scrapy.Field()
? ? title = scrapy.Field()
? ? link = scrapy.Field()
? ? desc = scrapy.Field()
3. 編寫爬蟲:
編寫爬蟲類Spider,Spider是用戶編寫用于從網站上爬取數據的類。其包含了一個用于下載的初始化URL,然后是如何跟進網頁中的鏈接以及如何分析頁面中的內容,還有提取生成item的方法。
#crawler\crawler\spiders\crawler_spider.py 新建文件
import scrapy
class CrawlerSpider(scrapy.Spider):
? ? name = 'csdn' ?#爬蟲名字,調用的時候使用
? ? allowed_domains = ['csdn.net']
? ? start_urls = ['http://geek.csdn.net/AI']
? ? def parse(self, response):
? ? ? ? filename = response.url.split('/')[-2]
? ? ? ? with open(filename, 'wb') as f:
? ? ? ? ? ? f.write(response.body)
3.1 爬
win-cmd:
C:\Users\Jan\Desktop\python_study>cd crawler
C:\Users\Jan\Desktop\python_study\crawler>scrapy crawl csdn ?#csdn爬蟲類中的name
2017-09-08 21:56:28 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: crawler)
...
2017-09-08 21:56:30 [scrapy.core.engine] INFO: Spider opened
2017-09-08 21:56:30 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-09-08 21:56:30 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-09-08 21:56:30 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://geek.csdn.net/robots.txt> (referer: None) ?#Here: robots.txt
2017-09-08 21:56:30 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://geek.csdn.net/AI> (referer: None) ?#Here: 我們的目標爬取鏈接
2017-09-08 21:56:31 [scrapy.core.engine] INFO: Closing spider (finished)
...
2017-09-08 21:56:31 [scrapy.core.engine] INFO: Spider closed (finished)
#爬取的內容存儲位置(爬取網站的源碼文件):
C:\Users\Jan\Desktop\python_study\crawler\ 目錄下 geek.csdn.net 的NET文件。
3.2 取
在Scrapy中使用的是一種基于XPath和CSS的表達式機制:Scrapy Selectors(選擇器)
Selector是一個選擇器,有4個基本方法:
xpath() 傳入xpath表達式,返回該表達式所對應的所有節點的selector list列表。
css() 傳入CSS表達式,返回該表達式所對應的所有節點的selector list列表。
extract() 序列化該節點為unicode字符串并返回list。
re() 根據傳入的正則表達式對數據進行提取,返回unicode字符串list列表。
win-cmd進入項目根目錄后執行:scrapy shell "http://target_url/"
C:\Users\Jan\Desktop\python_study\crawler>scrapy shell "http://geek.csdn.net/AI"
2017-09-08 22:05:48 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: crawler)
...
2017-09-08 22:05:50 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-09-08 22:05:50 [scrapy.core.engine] INFO: Spider opened
2017-09-08 22:05:50 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://geek.csdn.net/robots.txt> (referer: None)
2017-09-08 22:05:50 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://geek.csdn.net/AI> (referer: None)
...
>>> response.body #輸出網頁的源碼信息
>>> response.headers ?#輸出網頁的頭部信息
{'Date': ['Fri, 08 Sep 2017 14:06:31 GMT'], 'Content-Type': ['text/html; charset=utf-8'], 'Server': ['openresty'], 'Vary': ['Accept-Encoding', 'Accept-Encoding']}
XPath是一門在網頁中查找特定信息的語言,所以用XPath來篩選數據,要比使用正則表達式容易些。
/html/head/title 選擇HTML文檔中<head>標簽內的<title>元素
/html/head/title/text() 選擇上面提到的<title>元素的文字
//td 選擇所有的<td>元素
//div[@class="mine"] 選擇所有具有 class="mine" 屬性的div元素
response.xpath() = response.selector.xpath() ?#已經映射。可以直接使用.xpath()
>>> response.xpath('//title')
[<Selector xpath='//title' data=u'<title>CSDN\u6781\u5ba2\u5934\u6761-\u63a8\u8350\u6bcf\u65e5\u6700\u65b0\u6700\u70edIT\u8d44\u8baf</title>'>] ?#\u的那些是中文字符,編碼方式決定顯示
>>> response.xpath('//title/text()').extract() ?#截圖title內容
[u'CSDN\u6781\u5ba2\u5934\u6761-\u63a8\u8350\u6bcf\u65e5\u6700\u65b0\u6700\u70edIT\u8d44\u8baf']
>>> sel.xpath('//span/a') ?#輸出所有<span><a>標簽的內容全部輸出
2017-09-08 22:36:08 [py.warnings] WARNING: <string>:1: ScrapyDeprecationWarning: "sel" shortcut is deprecated. Use "response.xpath()", "response.css()" or "response.selector" instead
>>> sel.xpath('//span/a/text()').extract() ?#獲取所有<span><a>標簽中的字符串,即標題
>>> sel.xpath('//span/a/@href').extract() ?#獲取<span><a>中的連接地址
>>> sites = sel.xpath('//div/div/div/dl/dd/span/a/text()').extract() ?#按照標簽包裹的層級<body>下開始找到包裹標題的<a>標簽寫入xpath中
>>> for title in sites: ?#使用for循環打印可以自動將Unicode轉換為對應中文編碼顯示
... ? ? print(title)
自己動手做聊天機器人 四十二-(重量級長文)從理論到實踐開發自己的聊天機器人
微軟攜手 Facebook 推出開源項目 打造共享神經網絡模型
Taylor Swift vs 人工智能:作詞誰更強?
推薦13個機器學習框架
...
>>> sites = sel.xpath('//div/div/div[@class="directory-url"]/dl/dd/span/a/text()').extract()
#其中[@class="directory-url"]的功能是:過濾掉對應樣式類的內容,此處僅做演示
#crawler\crawler\spiders\crawler_spider.py 修改代碼
import scrapy
class CrawlerSpider(scrapy.Spider):
? ? name = 'csdn'
? ? allowed_domains = ['csdn.net']
? ? start_urls = ['http://geek.csdn.net/AI']
? ? def parse(self, response):
? ? ? ? sel = scrapy.selector.Selector(response)
? ? ? ? sites = sel.xpath('//div/div/div/dl/dd/span')
? ? ? ? for site in sites:
? ? ? ? ? ? title = site.xpath('a/text()').extract()
? ? ? ? ? ? link ?= site.xpath('a/@href').extract()
? ? ? ? ? ? desc ?= site.xpath('text()').extract()
? ? ? ? ? ? print(title, link, desc)
win-cmd:
C:\Users\Jan\Desktop\python_study\crawler>scrapy crawl csdn
#運行就可以將print中的內容在爬取時一并顯示出來(輸出內容略)
4. 存儲內容
最常見的導出為json格式。
中文亂碼問題:http://bbs.fishc.com/thread-85672-1-1.html
#crawler\crawler\spiders\crawler_spider.py ?構造items的列表對象
import scrapy
from crawler.items import CrawlerItem
class CrawlerSpider(scrapy.Spider):
? ? name = 'csdn'
? ? allowed_domains = ['csdn.net']
? ? start_urls = ['http://geek.csdn.net/AI']
? ? def parse(self, response):
? ? ? ? sel = scrapy.selector.Selector(response)
? ? ? ? items = []
? ? ? ? sites = sel.xpath('//div/div/div/dl/dd/span')
? ? ? ? for site in sites:
? ? ? ? ? ? item = CrawlerItem() ?#實例化一個item類(類似于字典)
? ? ? ? ? ? item['title'] = site.xpath('a/text()').extract()
? ? ? ? ? ? item['link'] ?= site.xpath('a/@href').extract()
? ? ? ? ? ? item['desc'] ?= site.xpath('text()').extract()
? ? ? ? ? ? print(item['title'], item['link'], item['desc'])
? ? ? ? ? ? items.append(item)
? ? ? ? return items
#crawler\crawler\pipelines.py ?設置抓取內容存儲的文件名以及校正中文亂碼
import json
import codecs
store_filename = 'items.json' ? ?#item.json指的是要保存的json格式文件的名稱
class CrawlerPipeline(object):
? ? def __init__(self):
? ? ? ? self.file = codecs.open(store_filename, 'wb', encoding='utf-8') ?#中文編碼格式一般都是'utf-8'
? ? def process_item(self, item, spider):
? ? ? ? line = json.dumps(dict(item), ensure_ascii=False) + '\n' ?#這一句會將你每次返回的字典抓取出來,“ensure_ascii=False”這一句話很重要,如果是True的話就是我們保存的\u4e2d\u56fd這種格式了
? ? ? ? self.file.write(line) ?#寫入到文件中
? ? ? ? return item
#crawler\crawler\setting.py ?使pipelines.py生效,取消注釋ITEM_PIPELINES
ITEM_PIPELINES = {
? ? 'crawler.pipelines.CrawlerPipeline': 300, ?#300是正常值,不變。
}
win-cmd運行scrapy,即可自動在\crawler\目錄下生成items.json文件,并且中文顯示正常:
C:\Users\Jan\Desktop\python_study\crawler>scrapy crawl csdn
C:\Users\Jan\Desktop\python_study\crawler\items.json ?#中文正常。
{"title": ["自己動手做聊天機器人 四十二-(重量級長文)從理論到實踐開發自己的聊天機器人"], "link": ["http://www.shareditor.com/blogshow?blogId=136&hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io"], "desc": ["\n ? ? ? ? ? ? ? ? ? ? ? ? ? ?", "\n ? ? ? ? ? ? ? ? ? ? ? ?"]}
{"title": ["微軟攜手 Facebook 推出開源項目 打造共享神經網絡模型"], "link": ["http://tech.163.com/17/0908/08/CTQ1403R00097U80.html"], "desc": ["\n ? ? ? ? ? ? ? ? ? ? ? ? ? ?", "\n ? ? ? ? ? ? ? ? ? ? ? ?"]}
{"title": ["Taylor Swift vs 人工智能:作詞誰更強?"], "link": ["http://dataquestion.com/taylor-vs-ai"], "desc": ["\n ? ? ? ? ? ? ? ? ? ? ? ? ? ?", "\n ? ? ? ? ? ? ? ? ? ? ? ?"]}
...
--------------------------------2017.09.09----------------------------------------
23丶GUI界面的終極選擇 Tkinter
Tkinter是python的默認GUI模塊庫。
示例1:主窗口及標題
import tkinter as tk
app = tk.Tk() ?#根窗口的實例(root窗口)
app.title('Tkinter root window') ?#根窗口標題
theLabel = tk.Label(app, text='我的第2個窗口程序!') ?#label組件及文字內容
theLabel.pack() ?#pack()用于自動調節組件的尺寸
app.mainloop() ?#窗口的主事件循環,必須的。
示例2:按鈕
import tkinter as tk
class APP:
? ? def __init__(self, master): ?#root 傳參賦值給master
? ? ? ? frame = tk.Frame(master) ?#frame 組件
? ? ? ? frame.pack(side=tk.LEFT, padx=10, pady=10)
? ? ? ? self.hi_there = tk.Button(frame, text='打招呼', bg='black', fg='white', command=self.say_hi) ?#Button按鈕, command中調用定義的方法
? ? ? ? self.hi_there.pack()
? ? def say_hi(self):
? ? ? ? print('臥槽,居然打了個招呼!~')
root = tk.Tk()
app = APP(root)
root.mainloop()
示例3:圖片
from tkinter import *
root = Tk()
textLabel = Label(root,
? ? ? ? ? ? ? ? ? text='請重試!\n您的操作不被允許!', ?#文字支持換行
? ? ? ? ? ? ? ? ? justify=LEFT, ?#左對齊
? ? ? ? ? ? ? ? ? padx=10, ?#左邊距10px
? ? ? ? ? ? ? ? ? pady=10) ?#右邊距10px?
textLabel.pack(side=LEFT)
#顯示圖片
photo = PhotoImage(file='tk_image.png')
imageLabel = Label(root, image=photo)
imageLabel.pack(side=RIGHT)
mainloop()
示例4:背景
from tkinter import *
root = Tk()
photo = PhotoImage(file='tk4_bg.png')
theLabel = Label(root,
? ? ? ? ? ? ? ? ?text='生存還是毀滅\n這是一個問題',
? ? ? ? ? ? ? ? ?justify=LEFT,
? ? ? ? ? ? ? ? ?image=photo,
? ? ? ? ? ? ? ? ?compound=CENTER,
? ? ? ? ? ? ? ? ?font=('華文隸書', 20),
? ? ? ? ? ? ? ? ?fg='blue')
theLabel.pack()
mainloop()
示例5:按鈕交互
from tkinter import *
def callback():
? ? var.set('吹吧你,我才不信呢!')
root = Tk()
frame1 = Frame(root)
frame2 = Frame(root)
var = StringVar()
var.set('請重試!\n您的操作不被允許!')
textLabel = Label(frame1,
? ? ? ? ? ? ? ? ? textvariable=var,
? ? ? ? ? ? ? ? ? justify=LEFT) ?#左對齊
textLabel.pack(side=LEFT)
#顯示圖片
photo = PhotoImage(file='tk_image.png')
imageLabel = Label(root, image=photo)
imageLabel.pack(side=RIGHT)
theButton = Button(frame2, text='我是超級管理員', command=callback)
theButton.pack()
frame1.pack(padx=10, pady=10)
frame2.pack(padx=10, pady=10)
mainloop()
示例6:選項按鈕
from tkinter import *
root = Tk()
v = IntVar()
c = Checkbutton(root, text='測試一下', variable=v) ?#v用來存放選中狀態
c.pack()
l = Label(root, textvariable=v)
l.pack() ?#未選中顯示為0,選中顯示1
mainloop()
示例7:多個方框選項
from tkinter import *
root = Tk()
GIRLS = ['西施', '貂蟬', '王昭君', '楊玉環']
v = ?[]
for girl in GIRLS:
? ? v.append(IntVar())
? ? b = Checkbutton(root, text=girl, variable=v[-1])
? ? b.pack(anchor=W) ?#設置對齊方位,東E南S西W北N
mainloop()
示例8:多個圓點選項 Radiobutton
from tkinter import *
root = Tk()
v = IntVar()
Radiobutton(root, text='one', variable=v, value=1).pack(anchor=W)
Radiobutton(root, text='two', variable=v, value=2).pack(anchor=W)
Radiobutton(root, text='three', variable=v, value=3).pack(anchor=W)
Radiobutton(root, text='four', variable=v, value=4).pack(anchor=W)
mainloop()
示例9:內陷填充按鈕選項 Radiobutton indicatoron
from tkinter import *
root = Tk()
LANGS = [
? ? ('C', 1),
? ? ('C++', 2),
? ? ('shell', 3),
? ? ('python', 4)]
v = IntVar()
v.set(1)
for lang, num in LANGS: ?#對應列表中包含元組同時執行多個循環
? ? b = Radiobutton(root, text=lang, variable=v, value=num, indicatoron=False)
? ? b.pack(fill=X)
mainloop()
示例10:附帶標題的圓點選項 LabelFrame
from tkinter import *
root = Tk()
group = LabelFrame(root, text='最好的開發語言是?', padx=5, pady=5)
group.pack(padx=10, pady=10)
LANGS = [
? ? ('C', 1),
? ? ('C++', 2),
? ? ('shell', 3),
? ? ('python', 4)]
v = IntVar()
v.set(1)
for lang, num in LANGS: ?#對應列表中包含元組同時執行多個循環
? ? b = Radiobutton(group, text=lang, variable=v, value=num)
? ? b.pack(anchor=W)
mainloop()
示例11:輸入框 Entry
from tkinter import *
root = Tk()
e = Entry(root)
e.pack(padx=20, pady=20)
e.delete(0, END)
e.insert(0, '默認文本...')
mainloop()
示例12:按鈕和輸入框交互
from tkinter import *
root = Tk()
root.title('輸入框與按鈕程序')
Label(root, text='作品:').grid(row=0, column=0)
Label(root, text='作者:').grid(row=1, column=0)
e1 = Entry(root)
e2 = Entry(root)
e1.grid(row=0, column=1, padx=10, pady=5)
e2.grid(row=1, column=1, padx=10, pady=5)
def show(): ?#當輸入內容時點擊獲取信息會打印
? ? print('作品:《%s》' % e1.get())
? ? print('作者:《%s》' % e2.get())
Button(root, text='獲取信息', width=10, command=show) \
? ? ? ? ? ? ?.grid(row=3, column=0, sticky=W, padx=10, pady=5)
Button(root, text='點擊退出', width=10, command=root.quit) \
? ? ? ? ? ? ?.grid(row=3, column=1, sticky=E, padx=10, pady=5)
#退出按鈕必須是雙擊打開.py文件才可以,而不是在IDLE下調試運行時
mainloop()
示例12:登陸框程序
from tkinter import *
root = Tk()
root.title('登陸程序')
Label(root, text='賬號:').grid(row=0, column=0)
Label(root, text='密碼:').grid(row=1, column=0)
v1 = StringVar()
v2 = StringVar()
e1 = Entry(root, textvariable=v1)
e2 = Entry(root, textvariable=v2, show='*')
e1.grid(row=0, column=1, padx=10, pady=5)
e2.grid(row=1, column=1, padx=10, pady=5)
def show():
? ? print('賬號:%s' % e1.get())
? ? print('密碼:%s' % e2.get())
Button(root, text='芝麻開門', width=10, command=show) \
? ? ? ? ? ? ?.grid(row=3, column=0, sticky=W, padx=10, pady=5)
Button(root, text='點擊退出', width=10, command=root.quit) \
? ? ? ? ? ? ?.grid(row=3, column=1, sticky=E, padx=10, pady=5)
#退出按鈕必須是雙擊打開.py文件才可以,而不是在IDLE下調試運行時
mainloop()
示例13:輸入對錯驗證程序
from tkinter import *
root = Tk()
root.title('輸入對錯驗證')
def test():
? ? if e1.get() == '張三':
? ? ? ? print('正確!')
? ? ? ? return True
? ? else:
? ? ? ? print('錯誤!')
? ? ? ? e1.delete(0, END)
? ? ? ? return False
v = StringVar()
#focusout指定在當前輸入框失去焦點時,代表輸入完,會去調用test校驗<tab>鍵可測試
e1 = Entry(root, textvariable=v, validate='focusout', validatecommand=test)
e2 = Entry(root)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)
mainloop()
示例13:簡單計算器程序
from tkinter import *
root = Tk()
root.title('計算器程序')
frame = Frame(root)
frame.pack(padx=10, pady=10)
v1 = StringVar()
v2 = StringVar()
v3 = StringVar()
def test(content):
? ? return content.isdigit()
testCMD = frame.register(test)
#focusout指定在當前輸入框失去焦點時,代表輸入完,會去調用test校驗<tab>鍵可測試
e1 = Entry(frame, width=10, textvariable=v1, validate='key', \
? ? ? ? ? ?validatecommand=(testCMD, '%P')).grid(row=0, column=0) ?#width的單位是字符數
Label(frame, text='+').grid(row=0, column=1)
e2 = Entry(frame, width=10, textvariable=v2, validate='key', \
? ? ? ? ? ?validatecommand=(testCMD, '%P')).grid(row=0, column=2)
Label(frame, text='=').grid(row=0, column=3)
e3 = Entry(frame, width=10, textvariable=v3, state='readonly').grid(row=0, column=4)
def calc():
? ? result = int(v1.get()) + int(v2.get())
? ? v3.set(str(result))
Button(frame, text='計算結果', command=calc).grid(row=1, column=2, pady=5)
mainloop()
示例14:按鈕刪除列表中的選項
from tkinter import *
master= Tk()
theLB = Listbox(master, selectmode=SINGLE, height=15) ?#SINGLE單選,MULTIPLE多選,height設置顯示項數
theLB.pack()
for item in ['筆', '墨', '紙', '硯']:
? ? theLB.insert(END, item) ?#END表示最后一個
for item in range(11):
? ? theLB.insert(END, item)
? ??
theButton = Button(master, text='刪除', \
? ? ? ? ? ? ? ? ? ?command=lambda x=theLB:x.delete(ACTIVE) ) #ACTIVE表示當前選中的值
theButton.pack()
mainloop()
示例15:為列表組件添加滾動條
安裝垂直滾動條步驟:
1) 設置該組件的yscrollbarcommand選項為Scrollbar組件的set方法;
2) 設置Scrollbar組件的command選項為該組件的yview()方法。
from tkinter import *
root = Tk()
root.title('滾動條程序')
sb = Scrollbar(root)
sb.pack(side=RIGHT, fill=Y)
lb = Listbox(root, yscrollcommand=sb.set)
for i in range(1000):
? ? lb.insert(END, i)
lb.pack(side=LEFT, fill=BOTH)
#讓滾動條與選項互通互連
sb.config(command=lb.yview)
mainloop()
示例16:滑塊滾動條 Scale
from tkinter import *
root = Tk()
root.title('滑塊程序')
s1 = Scale(root, from_=0, to=100, tickinterval=5, resolution=5, length=200) ?#默認是垂直, tickinterval精度刻度, length單位是像素
s1.pack()
s2 = Scale(root, from_=0, to=100, tickinterval=5, orient=HORIZONTAL, length=400)
s2.pack()
def show():
? ? print(s1.get(), s2.get())
#獲取滑塊的當前位置,點擊后才有效
Button(root, text='音量:', command=show).pack()
mainloop()
示例17:文本組件 Text ?(插入按鈕)
from tkinter import *
root = Tk()
root.title('Text')
text = Text(root, width=30, height=20)
text.pack()
#窗口中的文本可編輯
text.insert(INSERT, '這里是顯示的文本信息內容。\n') ?#INSERT表示輸入光標插入的位置
text.insert(END, '對比一下效果。')
def show():
? ? print('提交中...') ?#此行內容顯示在IDLE中
#插入一個Button組件
b1 = Button(text, text='提交', command=show)
text.window_create(INSERT, window=b1) ?#將b1插入
mainloop()
示例18:文本組件 Text ?(插入圖片)
from tkinter import *
root = Tk()
root.title('Text')
text = Text(root, width=100, height=30)
text.pack()
photo = PhotoImage(file="tk_image.png")
def show_img():
? ? text.image_create(END, image=photo)
#插入一個圖片
b1 = Button(text, text='插入圖片', command=show_img)
text.window_create(INSERT, window=b1) ?#將b1插入
mainloop()
示例19:文本組件 Text ?(Indexes:索引定位)
from tkinter import *
root = Tk()
root.title('Text')
text = Text(root, width=30, height=10)
text.pack()
text.insert(INSERT, 'I love baidu.com!')
text.tag_add('tag1', '1.7', '1.12', '1.14') ?#1.7~1.12 baidu ? 1.14 o
text.tag_add('tag2', '1.7', '1.12', '1.14')
text.tag_config('tag1', background='blue', foreground='yellow')
text.tag_config('tag2', foreground='red') ?#文字會以red為準
mainloop()
示例20:文本組件中可點擊連接
from tkinter import *
import webbrowser as wb
root = Tk()
root.title('GUI link show')
text = Text(root, width=30, height=5)
text.pack()
text.insert(INSERT, 'I love baidu.com!')
text.tag_add('link', '1.7', '1.16')
text.tag_config('link', foreground='blue', underline=True)
def show_arrow_cursor(event):
? ? text.config(cursor='arrow')
def show_xterm_cursor(event):
? ? text.config(cursor='xterm')
def click(event):
? ? wb.open('http://www.baidu.com')
#綁定事件
text.tag_bind('link', '<Enter>', show_arrow_cursor) ?#<Enter>鼠標進入
text.tag_bind('link', '<Leave>', show_xterm_cursor) ?#<Enter>鼠標離開
text.tag_bind('link', '<Button-1>', click) ?#<Enter>鼠標點擊
mainloop()
示例21:文本組件之MD5
from tkinter import *
import hashlib ?#用于獲取文件的MD5值,檢查內容是否有修改
root = Tk()
root.title('link click')
text = Text(root, width=50, height=10)
text.pack()
text.insert(INSERT, 'I love www.baidu.com')
contents = text.get('1.0', END)
def getSig(contents):
? ? m = hashlib.md5(contents.encode())
? ? return m.digest()
sig = getSig(contents)
def check():
? ? contents = text.get('1.0', END)
? ? if sig != getSig(contents):
? ? ? ? print('內容有修改,是否保存?')
? ? else:
? ? ? ? print('無任何修改!')
Button(root, text='檢查', command=check).pack()
mainloop()
示例22:文本組件之全文搜索
from tkinter import *
root = Tk()
root.title('link click')
text = Text(root, width=50, height=10)
text.pack()
text.insert(INSERT, 'I love www.baidu.com')
def getIndex(text, index):
? ? return tuple(map(int, str.split(text.index(index), '.')))
start = '1.0' ?#開頭的位置,第1行的第0個下標位置
while True:
? ? pos = text.search('o', start, stopindex=END) ?#查找文本中字符o的位置
? ? if not pos:
? ? ? ? break
? ? print('找到啦,位置是:', getIndex(text, pos))
? ? start = pos + '+1c' ?#'+1c'指向下一個字符
mainloop()
示例23:文本組件之撤銷操作
from tkinter import *
root = Tk()
root.title('link click')
text = Text(root, width=50, height=10, undo=True) ?#undo模式開啟
text.pack()
text.insert(INSERT, 'I love www.baidu.com')
def show():
? ? text.edit_undo()
Button(root, text='撤銷', command=show).pack() ?#多次撤銷會刪除文本組件內的內容
mainloop()
示例24:繪制組件 Canvas
from tkinter import *
root = Tk()
root.title('Canvas')
w = Canvas(root, width=500, height=300) ?#background='black' 改變背景色
w.pack()
#黃色的矩形
w.create_rectangle(50, 50, 450, 250, fill='yellow') ?#參數:左邊距, 上邊距, 寬, 高
#紅色的橫線
w.create_line(0, 300//2, 500, 300//2, fill='red')
#藍色的豎虛線
w.create_line(500//2, 0, 500//2, 300, fill='blue', dash=(4, 4)) ?#dash 虛線
mainloop()
示例25:繪制組件 Canvas (修改和刪除圖形)
from tkinter import *
root = Tk()
root.title('Canvas')
w = Canvas(root, width=500, height=300) ?#background='black' 改變背景色
w.pack()
rect1 = w.create_rectangle(50, 50, 450, 250, fill='yellow') ?#參數:左邊距, 上邊距, 寬, 高
line1 = w.create_line(0, 300//2, 500, 300//2, fill='red')
line2 = w.create_line(500//2, 0, 500//2, 300, fill='blue', dash=(4, 4)) ?#dash 虛線
w.coords(line1, 0, 25, 500, 25) ?#移動位置
w.itemconfig(rect1, fill='red')
w.delete(line2)
Button(root, text='刪除全部', command=(lambda x=ALL:w.delete(x))).pack()
mainloop()
示例26:繪制組件 Canvas (圖形正中心)
from tkinter import *
root = Tk()
root.title('Canvas')
w = Canvas(root, width=600, height=300)
w.pack()
line1 = w.create_line(0, 0, 600, 300, fill='green', width=3)
line1 = w.create_line(600, 0, 0, 300, fill='green', width=3)
rect1 = w.create_rectangle(60, 30, 540, 270, fill='green')
rect2 = w.create_rectangle(120, 60, 480, 240, fill='yellow')
w.create_text(300, 150, text='Hello, python!')
mainloop()
示例27:繪制組件 Canvas (橢圓和圓形)
from tkinter import *
root = Tk()
root.title('Canvas')
w = Canvas(root, width=600, height=300)
w.pack()
w.create_rectangle(60, 30, 540, 270, dash=(4, 4))
w.create_oval(60, 30, 540, 270, fill='pink') ?#橢圓是通過限定矩形的方式畫出來,圓形通過正方形
#w.create_oval(60, 30, 300, 270, fill='pink') ?#正方形對應正圓(60-300=30-270)
w.create_text(300, 150, text='wow~')
mainloop()
示例28:繪制組件 Canvas (五角星)
from tkinter import *
import math as m ?#用到sin和cos數學函數
root = Tk()
root.title('Canvas')
w = Canvas(root, width=600, height=300, background='red')
w.pack()
center_x = 300
center_y = 150
r = 150
points = [
? ? #左上點
? ? center_x - int(r * m.sin(2 * m.pi / 5)),
? ? center_y - int(r * m.cos(2 * m.pi / 5)),
? ? #右上點
? ? center_x + int(r * m.sin(2 * m.pi / 5)),
? ? center_y - int(r * m.cos(2 * m.pi / 5)),
? ? #左下點
? ? center_x - int(r * m.sin(m.pi / 5)),
? ? center_y + int(r * m.cos(m.pi / 5)),
? ? #頂點
? ? center_x,
? ? center_y - r,
? ? #右下點
? ? center_x + int(r * m.sin(m.pi / 5)),
? ? center_y + int(r * m.cos(m.pi / 5)),
? ? ]
w.create_polygon(points, outline='yellow', fill='yellow') ?#polygon多邊形
mainloop()
示例29:繪制組件 Canvas (自定義畫板)
#繪制一個極小的圓來代表一個點(tkinter本身不支持畫點)
from tkinter import *
root = Tk()
root.title('Canvas draw tool')
w = Canvas(root, width=400, height=200, background='white')
w.pack()
def paint(event):
? ? x1, y1 = (event.x - 1), (event.y - 1)
? ? x2, y2 = (event.x + 1), (event.y + 1)
? ? w.create_oval(x1, y1, x2, y2, fill='red')
w.bind('<B1-Motion>', paint) ?#<B1-Motion>綁定鼠標左鍵事件
Label(root, text='按住鼠標左鍵并移動,開始繪制吧!~~').pack(side=BOTTOM)
mainloop()
示例30:菜單組件 Menu (主菜單/下拉菜單/右鍵菜單/單多選菜單/按鈕菜單/選項菜單(列表))
from tkinter import *
root = Tk()
root.title('Main Menu Show')
def callback():
? ? print('你好~')
menubar = Menu(root)
#注冊菜單:文件(下拉菜單)
filemenu = Menu(menubar, tearoff=False) ?#來自主菜單,tearoff參數可讓菜單窗口分離
filemenu.add_command(label='新建', command=callback)
filemenu.add_command(label='打開...', command=callback)
filemenu.add_separator() ?#分割線
filemenu.add_command(label='保存', command=callback)
filemenu.add_separator() ?#分割線
filemenu.add_command(label='退出', command=root.quit)
menubar.add_cascade(label='文件(W)', menu=filemenu)
#主菜單:編輯(下拉菜單)
editmenu = Menu(menubar, tearoff=False) ?#來自主菜單
editmenu.add_command(label='撤銷', command=callback)
editmenu.add_command(label='重做', command=callback)
editmenu.add_separator() ?#分割線
editmenu.add_command(label='剪切', command=callback)
editmenu.add_command(label='復制', command=callback)
editmenu.add_command(label='粘貼', command=callback)
editmenu.add_separator() ?#分割線
editmenu.add_command(label='全選', command=callback)
editmenu.add_separator() ?#分割線
editmenu.add_command(label='查找...', command=callback)
menubar.add_cascade(label='編輯(B)', menu=editmenu)
#主菜單:多選√ checkbutton(下拉菜單)
openVar = IntVar()
saveVar = IntVar()
quitVar = IntVar()
optionmenu = Menu(menubar, tearoff=False)
optionmenu.add_checkbutton(label='多選項1', command=callback, variable=openVar)
optionmenu.add_checkbutton(label='多選項2', command=callback, variable=saveVar)
optionmenu.add_checkbutton(label='多選項3', command=callback, variable=quitVar)
menubar.add_cascade(label='選項(C)', menu=optionmenu)
#主菜單:單選√ radiobutton(下拉菜單)
otherVar = IntVar()
othermenu = Menu(menubar, tearoff=False)
othermenu.add_radiobutton(label='單選項1', command=callback, variable=otherVar, value=1)
othermenu.add_radiobutton(label='單選項2', command=callback, variable=otherVar, value=2)
othermenu.add_radiobutton(label='單選項3', command=callback, variable=otherVar, value=3)
menubar.add_cascade(label='其他(C)', menu=othermenu)
#內部菜單:按鈕菜單 Menubutton
mb = Menubutton(root, text='按鈕菜單...', relief=RAISED)
mb.pack()
openVar = IntVar()
saveVar = IntVar()
quitVar = IntVar()
optionmenu = Menu(mb, tearoff=False)
optionmenu.add_checkbutton(label='test', command=callback, variable=openVar)
optionmenu.add_checkbutton(label='test', command=callback, variable=saveVar)
optionmenu.add_checkbutton(label='test', command=callback, variable=quitVar)
mb.config(menu=optionmenu)
#內部菜單:選項菜單 OptionMenu
variable = StringVar()
variable.set('one') ?#默認顯示one
w = OptionMenu(root, variable, 'one', 'two', 'three')
w.pack()
#將列表添加到選項菜單 OptionMenu
OPTIONS = [
? ? '表項1',
? ? '對比2',
? ? '選項3',
? ? '其他4',
? ? '退出5'
? ? ]
var = StringVar()
var.set(OPTIONS[0])
o = OptionMenu(root, var, *OPTIONS) ?#*星號解包可變參數列表為逐個元素
o.pack()
#主菜單:幫助
helpmenu = Menu(menubar, tearoff=False)
helpmenu.add_separator() ?#分割線
helpmenu.add_command(label='關于...', command=callback)
helpmenu.add_separator() ?#分割線
menubar.add_cascade(label='幫助(F1)', menu=helpmenu)
#彈出菜單(暫用編輯菜單作為右鍵)
frame = Frame(root, width=512, height=512)
frame.pack()
def popup(event):
? ? editmenu.post(event.x_root, event.y_root)
frame.bind('<Button-3>', popup) ?#Button-3為鼠標右鍵,1為左鍵,2為中鍵
root.config(menu=menubar) ?#menu參數會將菜單設置添加到root根窗口
mainloop()
示例31:事件綁定 bind (鼠標/按鍵/按鍵組合)
from tkinter import *
root = Tk()
root.title('Event bind')
frame = Frame(root, width=200, height=200)
#鼠標響應事件
def callback1(event): ?#event形參獲取事件描述,必備參數
? ? print('點擊位置:', event.x, event.y)
frame.bind('<Button-1>', callback1) ?#Button表示鼠標點擊事件, 12345分別代表左中右鍵上滾下滾
frame.pack()
#鍵盤響應事件
def callback2(event):
? ? print(event.keysym) ?#打印信息在IDLE, keysym指鍵盤所有按鍵
frame.bind('<Key>', callback2)
frame.focus_set()
frame.pack()
#鼠標即時響應事件
def callback3(event):
? ? print('點擊位置:', event.x, event.y)
frame.bind('<Motion>', callback3) ?#鼠標在窗口內只要有移動就一直輸出位置
frame.pack()
#事件序列(按鍵組合),語法:<modifier-type-detail> 如
#點擊鼠標左鍵:<Button-1> ?ButtonRelease更安全,移除組件釋放點擊時不去觸發
#點擊H字母按鍵:<KeyPress-H>
#同時點擊Ctrl+Shift+H:<Control-Shift-KeyPress-H>
mainloop()
示例32:消息組件 Message | 輸入組件 Spinbox
from tkinter import *
root = Tk()
root.title('Module')
#消息組件:Message
m1 = Message(root, text='這是一個消息:', width=100)
m1.pack()
m2 = Message(root, text='這是一\n則駭人聽聞的長長長長長長長消息!', width=100)
m2.pack()
#輸入組件:Spinbox ?(可指定輸入范圍)
s1 = Spinbox(root, from_=0, to=5)
s1.pack()
s2 = Spinbox(root, values=('zero', 'one', 'two', 'three', 'four', 'five'))
s2.pack()
mainloop()
示例33:窗口布局管理器 PanedWindow
from tkinter import *
root = Tk()
root.title('Module')
#二窗格
'''
p = PanedWindow(orient=VERTICAL)
p.pack(fill=BOTH, expand=1)
top = Label(p, text='top pane')
p.add(top)
bottom = Label(p, text='bottom pane')
p.add(bottom)
'''
#三窗格,同時顯示隱藏布局線(showhandle=True, sashrelief=SUNKEN)
p = PanedWindow(showhandle=True, sashrelief=SUNKEN)
p.pack(fill=BOTH, expand=1)
left = Label(p, text='left pane')
p.add(left)
q = PanedWindow(orient=VERTICAL, showhandle=True, sashrelief=SUNKEN)
p.add(q)
top = Label(q, text='top pane')
q.add(top)
bottom = Label(q, text='bottom pane')
q.add(bottom)
mainloop()
示例34:容器組件 Toplevel (創建頂級窗口,即彈出窗口)
from tkinter import *
root = Tk()
root.title('Toplevel')
def create():
? ? top = Toplevel()
? ? #top.attributes('-alpha', 0.5) 設置彈出的頂級窗口透明度:50%
? ? top.title('Toplevel demo...')
? ? msg = Message(top, text='I love python...')
? ? msg.pack()
Button(root, text='創建頂級窗口', command=create).pack() ?#點擊出現頂級窗口
mainloop()
示例35:幾何管理類,包pack(),網格grid(),位置place()
#pack() ?注意pack和grid不要混合使用
from tkinter import *
root = Tk()
root.title('pack')
#Listbox完全填充測試
listbox = Listbox(root)
listbox.pack(fill=BOTH, expand=True) ?#fill=BOTH將窗口填滿
for i in range(10):
? ? listbox.insert(END, str(i))
#Label縱向填充
Label(root, text='red', bg='red', fg='white').pack(fill=X)
Label(root, text='green', bg='green', fg='black').pack(fill=X)
Label(root, text='blue', bg='blue', fg='white').pack(fill=X)
#Label橫向填充
Label(root, text='red', bg='red', fg='white').pack(side=LEFT)
Label(root, text='green', bg='green', fg='black').pack(side=LEFT)
Label(root, text='blue', bg='blue', fg='white').pack(side=LEFT)
mainloop()
#grid() ?注意pack和grid不要混合使用
from tkinter import *
root = Tk()
root.title('grid')
#兩個sticky=W實現第一列左對齊
Label(root, text='用戶名').grid(row=0, sticky=W)
Label(root, text='密碼').grid(row=1, sticky=W)
#rowspan=2可以讓圖片橫跨2行
photo = PhotoImage(file='tk_image.png')
Label(root, image=photo).grid(row=0, column=2, rowspan=2, padx=5, pady=5)
Entry(root).grid(row=0, column=1)
Entry(root, show='*').grid(row=1, column=1)
def callback():
? ? print('登陸中...')
#columnspan=3可以讓按鈕橫跨3列
Button(text='提交', width=10, command=callback).grid(row=2, columnspan=3, pady=5)
mainloop()
#place() ? 可以實現一些pack和grid實現不了的布局
from tkinter import *
root = Tk()
root.title('place')
#place位置布局測試
'''
photo = PhotoImage(file='tk_image.png')
Label(root, image=photo).pack() ?#按鈕就會出現在圖片的組件上,實現組件疊加顯示
def callback():
? ? print('正中靶心!!!')
#relx,rely相對父組件root的位置,0.5正中間,1最右邊,0最左邊,anchor=CENTER居中顯示
Button(root, text='射擊', command=callback).place(relx=0.5, rely=0.5, anchor=CENTER)
'''
Label(root, bg='red').place(relx=0.5, rely=0.5, relheight=0.75, relwidth=0.75, anchor=CENTER)
Label(root, bg='yellow').place(relx=0.5, rely=0.5, relheight=0.5, relwidth=0.5, anchor=CENTER)
Label(root, bg='blue').place(relx=0.5, rely=0.5, relheight=0.25, relwidth=0.25, anchor=CENTER)
mainloop()
示例35:對話框 (警告 showinfo | 消息 messagebox | 文件 filedialog | 顏色 colorchooser)
from tkinter import *
from tkinter import messagebox ? ?#messagebox()需要單獨導入
from tkinter import filedialog ? ?#filedialog()需要單獨導入
from tkinter import colorchooser ?#colorchooser()需要單獨導入
from tkinter.messagebox import * ?#用戶使用showinfo()
#警告對話框
showinfo(title='test', message='警告')
#消息對話框
result = messagebox.askokcancel('demo', '發射核彈?') ?#返回值是True或False
print(result) ?#根據用戶按下了確定還是取消做進一步的操作
#文件對話框
root = Tk()
def callback1():
? ? filename = filedialog.askopenfilename(defaultextension='.py') ?#指定文件后綴
? ? print(filename) ?#返回的是文件的完整路徑
Button(root, text='打開文件', command=callback1).pack()
#顏色選擇對話框
def callback2():
? ? color_data = colorchooser.askcolor() ?#調用windows的顏色選擇器
? ? print(color_data) ?#選擇紅色打印:((255.99609375, 0.0, 0.0), '#ff0000')
Button(root, text='選擇顏色', command=callback2).pack()
python學習環境:(python3)win10下python3.5.4的IDLE ?+ ?ubuntu下python3輔助
python分享范圍:適合有C/C++/JAVA任意語言之一為基礎,不適合純新手入門
python語言優勢:至今還沒有一門編程語言,開發速度比Python快,運行速度比C快
python常用工具手冊:
http://bbs.fishc.com/forum.php?mod=collection&action=view&ctid=198
---------------------------------2017.08.27--------------------------------------
00丶python背景與特點
Python語言起源
在1989年末,Guido van Rossum為了打發圣誕節的無聊,創造了python(大蟒蛇)。 1991年,第一個 Python 版本誕生。最新版本是Python3 3.6.2 。Guido van Rossum 是蒙提·派森的飛行馬戲團(Monty Python‘s Flying Circus)的愛好者。logo是由兩只蟒蛇的圖形組成。
官網下載地址:
https://www.python.org/downloads/
Python 3 與 Python 2 不完全兼容
官方表示對 Python2 支持到2020年, Python2 2.7.13。Python 2 的生態庫遠遠大于 Python 3。
簡單:
學習曲線平滑, 45分鐘學會基本使用,使用簡單。
跨平臺:
一次編寫、到處運行。 Windows, Linux, Mac, Android
功能強大:
? ? 動態類型、自動內存管理
? ? 非常實用的內置對象類型
? ? 強大的內置工具和標準庫
? ? 易于擴展,很多成熟易用第三方庫
? ? 大型程序支持
應用廣泛:
? ? 數據庫、網絡、圖形圖像、科學計算、機器學習、web開發、操作系統擴展等
缺點:
運行速度不夠快(硬件的發展可以為此彌補不足)
開發速度與運行速度之間的矛盾:
至今還沒有一門編程語言,開發速度比Python快,運行速度比C快
知名軟件包:Django/Numpy/Pandas/Matplotlib/PIL (Pillow)/PyQt5/Tensorflow/Scipy/Theano/NLTK
知名項目:(網站)豆瓣/知乎/美團/Gmail/Youtube/Instagram/Calibre/……
01丶第一次親密接觸 first love
(1) win下的python IDLE集成開發環境自動縮進,table鍵補齊變量名
(2) linux下使用vi編輯.py的python文件,需要聲明 #!/usr/bin/python3
(3) python使用等量(1個tab)的縮進來嚴格對齊表示作用域
#!/usr/bin/python3
#guess game
print ("---------游戲開始-----------")
temp = input ("輸入一個我現在想的數字:")
guess = int (temp)
if guess == 8:
print ("猜對了!!!")
else:
print ("哈哈,猜錯了。。")
print ("游戲結束嘍~")
#---end---
BIF == Built-in functions(內置函數)
>>> dir(__builtins__)
..., 'input', ...
>>> help(input)
#可以查詢內置函數的說明和用法,類似于C語言的man手冊
02丶變量 variable
(1) python沒有"變量"只有"名字"
(2) 變量使用之前,需要對其先賦值
(3) 變量名命名同C的規則,不能以數字開頭,保證可讀性命名即可
(4) 大小寫敏感,區分
(5) =左右依次為左值和右值
(6) 十六進制,以0x 或 0X 開頭 ,數字由"0"到"9" 或者 "a"到"f" 或者 "A"到"F"組成
八進制,0o或0O 開頭,數字由"0" 到 "7"組成
二進制,0b或0B 開頭表示,數字由"0" 或者"1"組成
十進制由數字"0"到"9"組成,并且不能以0開頭
>>> teacher = 'jiangyuan'
>>> print (teacher)
jiangyuan
>>> teacher = 'somebody'
>>> print (teacher)
somebody
>>> first = 3
>>> second = 8
>>> third = first + second
>>> print (third)
11
>>> myteacher = 'jiangyuan'
>>> yourteacher = 'somebody'
>>> ourteacher = myteacher + yourteacher
>>> print (ourteacher)
jiangyuansomebody
03丶運算符及優先級 precedence of operator
#符合數學運算優先原則,括號最優先,最安全。
lambda lambda表達式
or 布爾或
and 布爾與
not 布爾非
in 和 not in 成員是否屬于測試
is 和 is not 對象是否是同一個
> ?>= ?< ?<= ?== ?!= 比較操作符
| 按位或
^ 按位異或
& 按位與
<< 和 >> 移位
+ 和 - 加法和減法
* 和 / 和 % 乘法、除法、取余
+x 和 -x 正負號
~x 按位翻轉
** 指數(冪運算)
// 地板除法,舍棄小數部分
---python運算符優先級(圖)---
#=連續賦值,自右向左,同C語言
>>> a = b = c = d = 10
>>> print (a, b, c, d)
10 10 10 10
>>> a += 1
>>> b -= 1
>>> c *= 10
>>> d /= 8 #真除法,精確值
>>> print (a, b, c, d)
11 9 100 1.25
>>> d = 10
>>> d // 3 ?#地板除法(Floor)舍棄小數部分
3
>>> 3 < 4 < 5 ?#支持連續判斷,不建議這樣用,可讀性不高
True
>>> 3 < 4 and 4 < 5
True
04丶類型 type
數值類型:整型(int)、浮點型(float)、布爾類型(bool)、e記法(科學計數法,屬于float)
(1) 整型與浮點型的區別就是是否含有小數點'.'
(2) bool類型的值是以大寫開頭的兩個單詞: True / False
(3) 純數字的字符串可以使用int轉為數字,進而參與計算,相當于C的atoi,非純數字的不能使用int轉換為數字
(4) float類型轉換為int類型時,會丟棄小數部分
(5) str類型均可被其他類型轉換,即變成字符串無障礙
(6) type (value) 返回變量類型,isinstance(value, type)類型判斷返回bool值
#float→int,丟棄小數部分
>>> a = 5.99
>>> b = int (a)
>>> print (b)
5
#e記法示例
>>> 0.00000000000000111
1.11e-15
>>> 150000000000
150000000000
>>> 15e10
150000000000.0
#isinstance類型判斷
>>> isinstance ('hello', str)
True
>>> isinstance (520, str)
False
>>> isinstance (520, int)
True
05丶條件分支與循環 condition and loop
條件bool值: True ?False
False 的值: False ?None ?0 ?"" ?() ?[] ?{}
if-else
if condition:
#condition == True, 執行的操作,可多層嵌套
else:
#condition == False, 執行的操作,可多層嵌套
if-elif-else
if condition:
#condition == True, 執行的操作,可多層嵌套
elif condition:
#condition == True, 執行的操作,可多層嵌套
else:
#condition == False, 執行的操作,可多層嵌套
x if condition else y ?#三元操作符
舉例:
>>> x, y = 4, 5
>>> small = x if x < y else y
>>> print (small)
4
assert 斷言
當assert關鍵字后面的條件為假的時候,程序自動崩潰并拋出AssertionError異常。
>>> assert 3 > 4
Traceback (most recent call last):
? File "<pyshell#160>", line 1, in <module>
? ? assert 3 > 4
AssertionError
>>> assert 3 < 4
>>>?
while 循環
while condition:
#condition == true, 執行的循環體操作
#condition == false, 循環體外的操作
for 循環
for target in expression:
#循環體
示例:
>>> favourite = 'string'
>>> for i in favourite:
print (i, end=' ') ?#end以空格隔開
s t r i n g
range()函數
range ([start], [stop], [step]) ?#step默認每次遞增1,且range的取值范圍到stop-1
常與for循環一起使用。
示例:
>>> for i in range (2, 5):
print (i, end=' ')
2 3 4
>>> for i in range (1, 10, 2):
print (i, end=' ')
1 3 5 7 9
break 和 continue
同C語言的break和continue,依次為跳出循環和跳過當前循環。
pass 和 del 和 exec
pass 什么也不敢,暫時預留
del 刪除不再使用的對象
exec 執行python語句
exal 計算python表達式,并返回結果值
06丶列表 list
普通列表:member = ['name', 'id', 'age', 'weight']
混合列表:mix = [1, 'name', 3.14, [1, 2, 3]]
空列表:empty = []
列表常用方法: len()/max()/min()/append()/extend()/insert()/remove()/pop()/count()/index()/reverse()/sort()
len()
功能:列表長度(元素個數)
len(listname)
>>> len(member)
4
append()
功能:向列表添加單個元素
listname.append(element)
>>> member.append('class')
>>> member
['name', 'id', 'age', 'weight', 'class']
extend()
功能:使用子列表擴展列表
listname.extend([element1, element2, ...])
>>> member.extend (['str1', 'str2'])
>>> member
['name', 'id', 'age', 'weight', 'class', 'str1', 'str2']
insert()
功能:向列表指定位置插入元素
listname.insert(position, element)
#list和數組一樣,下標/索引均從0開始
>>> member.insert (1, 'new_elem')
>>> member
['name', 'new_elem', 'id', 'age', 'weight', 'class', 'str1', 'str2']
列表元素訪問
listname[index]
#index從0開始,到index-1位置的索引訪問
列表元素刪除
listname.remove(element) #刪除元素element
del listname[index] #刪除index位置的元素
listname.pop() #刪除最后一個元素,相當于C語言的彈棧
listname.pop(index) #刪除index位置指定的元素
列表元素分片
listname[start_index:stop_index]
(1) 分片不會修改原列表的值,輸出的是一份拷貝
(2) 分片輸出的是從 start_index 到 stop_index-1 位置的值
(3) 分片的start和stop位置均可省略,start省略表示從頭取值,stop省略表示取值到結尾,都省略表示取列表所有的值
示例:
>>> member = ['name', 'id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
? ? ? ? ? ? ? ?0 ? ? ? 1 ? ? 2 ? ? ?3 ? ? ? ? 4 ? ? ? ?5 ? ? ? 6 ? ? ? 7
>>> member[1:3]
['id', 'age']
>>> member[1:]
['id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
>>> member[:3]
['name', 'id', 'age']
>>> member[:]
['name', 'id', 'age', 'weight', 'class', 'str1', 'str2', 'str3']
>>> member[5:len(member)] #訪問最后3個元素
['str1', 'str2', 'str3']
>>> member[0:len(member):2] #最后的2代表步長
['name', 'age', 'class', 'str2']
列表常用操作符
(1) list元素的判斷只會判斷第一個元素,然后理解返回bool結果
(2) list支持比較、邏輯、連接(+)、重復(*)、成員關系(in)操作符
(3) list賦值list時需要注意加上[:],左值會表現為一份拷貝
示例:
list2 = list1[:]#list2是list1的一份拷貝
list3 = list1 #list3是list1的一個引用(list1被修改,list3也會跟著被修改)
(4) dir(list) 查看list支持的所有方法:
listname.count(element)#element元素出現的次數
listname.index(element, [range_s], [rang_t])#查找元素在起止范圍里第一次出現的下標位置
listname.reverse()#將list中的元素原地翻轉
listname.sort()#將list中的元素進行排序,默認從小到大(修改原list內容)
listname.sort(reverse=True)#排序元素,實現從大到小(修改原list內容)
07丶元組 tuple
元組和列表使用上相似:
(1) 最大區別:列表可以任意修改和插入等操作,元組是不可改變的
(2) 創建:列表使用[],元組使用()
元組只有1個元素時使用(element,)注意逗號
()可以省略,但是,逗號不能省略
(3) 訪問:都使用name[index]來訪問
(4) 元組在映射中當做鍵使用,而列表不行
示例:
>>> temp = 1,
>>> type (temp)
<class 'tuple'>
>>> 8 * (8)
64
>>> 8 * (8,)
(8, 8, 8, 8, 8, 8, 8, 8) ?#重復元組
#元組元素插入
>>> temp = ('name1','name2','name3','name4')
>>> temp = temp[:2] + ('new_name',) + temp[2:]
>>> temp
('name1', 'name2', 'new_name', 'name3', 'name4')
08丶字符串 ?string
(1) \可以進行符號轉義
(2) 單引號等同于雙引號
(3) 定義字符串時使用r寫在右值前面聲明為原始字符串
(4) 使用三引號('''或""")可以指定多行字符串。并且字符串里可以包含單引號和雙引號'''
(5) +號運算符可以連接字符串為1個字符串
(6) *號運算符可以復制多個相同字符串
列表和元組應用于字符串,所有標準的序列操作均適用于字符串。
>>> str1 = 'hello, python!' ?#字符串相當于元素是字符的元組
>>> str1 = str1[:5] + ';' + str1[5:]
>>> str1
'hello;, python!'
字符串常用方法: find()/join()/lower()/replace()/split()/strip()/translate()/
>>> dir(str)
...'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'...
【F1】可以從python的幫助文檔中【索引】查找操作方法的介紹內容及舉例。
capitalize() 返回新字符串,把字符串的第一個字符改為大寫
casefold() 返回新字符串,把整個字符串的所有字符改為小寫
center(width) 將字符串居中,并使用空格填充至長度 width 的新字符串
count(sub[, start[, end]]) 返回 sub 在字符串里邊出現的次數,start 和 end 參數表示范圍,可選。
encode(encoding='utf-8', errors='strict') 以 encoding 指定的編碼格式對字符串進行編碼。
endswith(sub[, start[, end]]) 檢查字符串是否以 sub 子字符串結束,如果是返回 True,否則返回 False。start 和 end 參數表示范圍,可選。
expandtabs([tabsize=8]) 把字符串中的 tab 符號(\t)轉換為空格,如不指定參數,默認的空格數是 tabsize=8。
find(sub[, start[, end]]) 檢測 sub 是否包含在字符串中,如果有則返回索引值,否則返回 -1,start 和 end 參數表示范圍,可選。
index(sub[, start[, end]]) 跟 find 方法一樣,不過如果 sub 不在 string 中會產生一個異常。
isalnum() 如果字符串至少有一個字符并且所有字符都是字母或數字則返回 True,否則返回 False。
isalpha() 如果字符串至少有一個字符并且所有字符都是字母則返回 True,否則返回 False。
isdecimal() 如果字符串只包含十進制數字則返回 True,否則返回 False。
isdigit() 如果字符串只包含數字則返回 True,否則返回 False。
islower() 如果字符串中至少包含一個區分大小寫的字符,并且這些字符都是小寫,則返回 True,否則返回 False。
isnumeric() 如果字符串中只包含數字字符,則返回 True,否則返回 False。
isspace() 如果字符串中只包含空格,則返回 True,否則返回 False。
istitle() 如果字符串是標題化(所有的單詞都是以大寫開始,其余字母均小寫),則返回 True,否則返回 False。
isupper() 如果字符串中至少包含一個區分大小寫的字符,并且這些字符都是大寫,則返回 True,否則返回 False。
join(sub) 以字符串作為分隔符,插入到 sub 中所有的字符之間。
ljust(width) 返回一個左對齊的字符串,并使用空格填充至長度為 width 的新字符串。
lower() 轉換字符串中所有大寫字符為小寫。
lstrip() 去掉字符串左邊的所有空格
partition(sub) 找到子字符串 sub,把字符串分成一個 3 元組 (pre_sub, sub, fol_sub),如果字符串中不包含 sub 則返回 ('原字符串', '', '')
replace(old, new[, count]) 把字符串中的 old 子字符串替換成 new 子字符串,如果 count 指定,則替換不超過 count 次。
rfind(sub[, start[, end]]) 類似于 find() 方法,不過是從右邊開始查找。
rindex(sub[, start[, end]]) 類似于 index() 方法,不過是從右邊開始。
rjust(width) 返回一個右對齊的字符串,并使用空格填充至長度為 width 的新字符串。
rpartition(sub) 類似于 partition() 方法,不過是從右邊開始查找。
rstrip() 刪除字符串末尾的空格。
split(sep=None, maxsplit=-1) 不帶參數默認是以空格為分隔符切片字符串,如果 maxsplit 參數有設置,則僅分隔 maxsplit 個子字符串,返回切片后的子字符串拼接的列表。
splitlines(([keepends])) 按照 '\n' 分隔,返回一個包含各行作為元素的列表,如果 keepends 參數指定,則返回前 keepends 行。
startswith(prefix[, start[, end]]) 檢查字符串是否以 prefix 開頭,是則返回 True,否則返回 False。start 和 end 參數可以指定范圍檢查,可選。
strip([chars]) 刪除字符串前邊和后邊所有的空格,chars 參數可以定制刪除的字符,可選。
swapcase() 翻轉字符串中的大小寫。
title() 返回標題化(所有的單詞都是以大寫開始,其余字母均小寫)的字符串。
translate(table) 根據 table 的規則(可以由 str.maketrans('a', 'b') 定制)轉換字符串中的字符。
upper() 轉換字符串中的所有小寫字符為大寫。
zfill(width) 返回長度為 width 的字符串,原字符串右對齊,前邊用 0 填充。
字符串操作:格式化
(1) 通過format方法將位置參數傳遞給對應字段
(2) : 冒號表示格式化符號的開始
位置參數:{0~n}
>>> "{0} love {1},{2}.".format("I", "you", "too")
'I love you,too.'
關鍵字參數:{自定義}
>>> "{a} love {b}, {c}.".format(a="I", b="you", c="too")
'I love you, too.'
注意:位置參數和關鍵字參數可以同時使用,但位置參數必須在關鍵字參數的前面。
字符串格式化符號含義
%c 格式化字符及其 ASCII 碼
%s 格式化字符串
%d 格式化整數
%o 格式化無符號八進制數
%x 格式化無符號十六進制數
%X 格式化無符號十六進制數(大寫)
%f 格式化浮點數字,可指定小數點后的精度,默認精確到小數點后6位
%e 用科學計數法格式化浮點數
%E 作用同 %e,用科學計數法格式化浮點數
%g 根據值的大小決定使用 %f 或 %e
%G 作用同 %g,根據值的大小決定使用 %f 或者 %E
舉例:
>>> '%c' % 97 # 此處 % 為占位符,同C語言中printf函數中的%
'a'
>>> '%c %c %c' % (97, 98, 99) #此處的元組()小括號不能省略
'a b c'
格式化操作符輔助命令
m.n m 是顯示的最小總寬度,n 是小數點后的位數
- 用于左對齊
+ 在正數前面顯示加號(+)
# 在八進制數前面顯示 '0o',在十六進制數前面顯示 '0x' 或 '0X'
0 顯示的數字前面填充 '0' 取代空格
舉例:
>>> '%5.1f' % 27.658 #m.n
' 27.7'
>>> '%-10d' % 5 #填充的位數都是空格
'5 ? ? ? ? ?'
>>> '%#x' % 160 #對應進制顯示方式
'0xa0'
>>> '%010d' % 5 #用0填充。'%-010d' % 5 負號的時候填充的只會是空格
'0000000005'
Python 的轉義字符及其含義
\' 單引號
\" 雙引號
\a 發出系統響鈴聲
\b 退格符
\n 換行符
\t 橫向制表符(TAB)
\v 縱向制表符
\r 回車符
\f 換頁符
\o 八進制數代表的字符
\x 十六進制數代表的字符
\0 表示一個空字符
\\ 反斜杠
09丶序列方法 sequence method
列表、元組、字符串的共同點:
(1) 都可以通過索引得到每一個元素
(2) 默認索引值總是從0開始
(3) 可以通過分片的方法得到一個范圍內的元素的集合
(4) 有很多共同的操作符(重復*、拼接+、成員關系in/not in等)
(5) 統稱為序列,以下(成員函數)為序列方法
list()
list(iterable) 把一個可迭代對象轉換為列表
舉例:
>>> b = 'I love you.' # b也可以是元組 b = (1, 2, 3, 4, 5)
>>> b = list(b)
>>> b
['I', ' ', 'l', 'o', 'v', 'e', ' ', 'y', 'o', 'u', '.']
tuple()
tuple(iterable) 把一個可迭代對象轉換為元組
舉例:
>>> b = 'I love you.'
>>> b = tuple(b)
>>> b
('I', ' ', 'l', 'o', 'v', 'e', ' ', 'y', 'o', 'u', '.')
max(...) 返回集合或者序列中的最大值(要求類型一致)
min(...) 返回集合或者序列中的最小值(要求類型一致)
>>> max(iterable, *[, default=obj, key=func]) -> value
>>> max(arg1, arg2, *args, *[, key=func]) -> value
舉例:
>>> numbers = [1, 18, 13, 0, -98, 34, 53, 76, 32]
>>> max(numbers)
76
>>> min(numbers)
-98
sum(...) 返回序列iterable和可選參數的總和(要求類型一致)
>>> sum(iterable, start=0, /)
舉例:
>>> tuple1 = (3.1, 2.3, 3.4)
>>> sum(tuple1)
8.8
>>> sum(tuple1, 0.2) #0.2為可選參數,會加在一起
9.0
sorted(...) 返回序列的排序結果
>>> sorted(iterable, /, *, key=None, reverse=False)
舉例:
>>> tuple1 = (3.1, 2.3, 3.4)
>>> sorted(tuple1)
[2.3, 3.1, 3.4]
reversed(...) 翻轉一個序列的內容
>>> reversed(sequence)
舉例:
>>> numbers = [1, 24, 5, -98, 54, 32]
>>> reversed(numbers)
<list_reverseiterator object at 0x000002C3EE5046A0>#這種格式都是:迭代器對象
>>> list(reversed(numbers)) # 將迭代器對象轉換為list列表
[32, 54, -98, 5, 24, 1]
enumerate(...) 生成由序列組成的元組
>>> enumerate(iterable[, start])
舉例:
>>> numbers = [1, 24, 5, -98, 54, 32]
>>> list(enumerate(numbers))
[(0, 1), (1, 24), (2, 5), (3, -98), (4, 54), (5, 32)]
zip(...) 返回由各個參數的序列組成的元組
>>> zip(iter1 [,iter2 [...]])
舉例:
>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> b = [4, 5, 6, 7, 8]
>>> zip(a, b)
<zip object at 0x000002C3EE562948>
>>> list(zip(a, b))
[(1, 4), (2, 5), (3, 6), (4, 7), (5, 8)]
>>> for i,j in zip(a, b): ?#并行迭代,同時迭代兩個變量
print(str(i) + ' is ' + str(j))
1 is 4
2 is 5
3 is 6
4 is 7
5 is 8
10丶函數 function
(1) python只有函數(return)沒有過程(no return)
(2) 函數返回多個值的時候,使用list列表或tuple元組進行返回
(3) 局部變量和全局變量的規則同C語言
(4) 在函數內部使用 global 修飾變量,使函數可以修改同名的全局變量
(5) 函數嵌套時,內部函數的作用域都在外部函數之內,出了外部函數就不能被調用
函數定義和調用
def function_name():
#函數體內容
function_name() #函數調用,執行函數體的內容
函數返回值
def function_name():
#函數體中返回
return value
print(function_name()) #調用函數并打印其返回值
函數參數
def function_name(param): #形參:多個參數使用,逗號隔開
#函數體使用參數param
function_name(parameter) #實參:傳遞實際參數
函數文檔
舉例:
>>> def my_sec_func(name):
'function document.'#函數文檔部分,單引號引起來即可
print(name)
>>> my_sec_func('myname')
myname
>>> my_sec_func.__doc__ ?#打印輸出函數文檔部分
'function document.'
>>> help(my_sec_func)
Help on function my_sec_func in module __main__:
my_sec_func(name)
? ? function document.
關鍵字參數與默認參數
舉例:
>>> def say_some(name, words):
#>> def say_some(name='abc', words='string'): #形參可設置默認值
print(name + ' -> ' + words)
>>> say_some('Jan', 'learning python.')
Jan -> learning python.
>>> say_some(words='learning python.', name='Jan') #指定形參對應實參
Jan -> learning python.
#>>> say_some()
#abc -> string
*params搜集其余的位置參數
>>> def test(*params): # *params把實參打包為元組
print('len = ', len(params))
print('second params = ', params[1])
>>> test(1, 'Jan', 3.14)
len = ?3
second params = ?Jan
#搜集參數param加上普通形參
>>> def test(*params, tmp):
print('len = ', len(params))
print('second params = ', params[1])
print('tmp = ', tmp)
>>> test(1, 'Jan', 3.14, tmp = 520) #注意傳參需要單獨指定
len = ?3
second params = ?Jan
tmp = ?520
global 關鍵字
舉例:
>>> cnt = 5
>>> def my_func():
global cnt
cnt= 10
print(cnt)
>>> my_func()
10
>>> print(cnt)
10
函數嵌套
舉例:
>>> def func1():
print('func1 called...')
def func2():
print('func2 called...')
func2()
>>> func1() #調用func1
func1 called...
func2 called...
閉包closure
舉例1:
>>> def funX(x):
def funY(y):
return x * y
return funY
>>> i = funX(8)
>>> i
<function funX.<locals>.funY at 0x000001EFE75E87B8>
>>> type(i)
<class 'function'>
>>> i(5)
40
>>> funX(8)(5)
40
>>> funY(5) #不可被調用,解決辦法有2:list或者nonlocal
舉例2 - list:
>>> def fun1():
x = [5] #對func2函數來說x是全局變量,在func2中沒有定義x,是用list即可安全
def fun2():
x[0] *= x[0]
return x[0]
return fun2()
>>> fun1()
25
舉例2 - nonlocal:
>>> def fun1():
x = 5
def fun2():
nonlocal x #在內部函數中聲明x為非局部變量,再調用func1()也是安全的
x *= x
return x
return fun2()
>>> fun1()
25
lambda 表達式(匿名函數)
(1) 不需要考慮函數名的命名問題
(2) 極大簡化函數編寫的步驟
舉例:
>>> def ds(x):
return 2*x + 1
>>> ds(5)
11
>>> lambda x : 2*x + 1
<function <lambda> at 0x000002170B3D87B8> #可以理解為返回的是C語言的函數指針
>>> g = lambda x : 2*x + 1 #賦值后,傳參即可,g相當于接收了匿名函數
>>> g(5)
11
>>> g = lambda x, y : x+y #lambda匿名函數多個參數
>>> g(1, 3)
4
兩個牛逼的BIF:filter和map
(1) filter 過濾:返回其函數為真的元素的列表
>>> filter(function or None, iterable)
舉例:
>>> filter(None, [1, 0, False, True])
<filter object at 0x000001CE5BCB0710>
>>> list(filter(None, [1, 0, False, True]))
[1, True] #驗證filter過濾的是非true的內容
>>> def odd(x):
return x % 2
>>> temp = range(10)
>>> show = filter(odd, temp)
>>> list(show)
[1, 3, 5, 7, 9]
>>> list(filter(lambda x : x % 2, range(10))) ?#簡化一行實現求奇數
[1, 3, 5, 7, 9]
(2) map 映射:對序列中每個元素都應用函數
>>> list(map(lambda x : x + 2, range(10)))
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
---------------------------------2017.08.28--------------------------------------
11丶遞歸 recursion
#遞歸求階乘:
def factorial(n):
? ? if n == 1:
? ? ? ? return 1 #(1)必須包含退出條件,同C語言
? ? else:
? ? ? ? return n * factorial(n-1) #(2)必須調用函數自身,同C語言
number = int(input("請輸入一個正整數:"))
result = factorial(number)
print("%d 的階乘為:%d" % (number, result))
#運行:
請輸入一個正整數:10
10 的階乘為:3628800
斐波那契數列(遞歸)
def fab(n):
? ? if n < 1:
? ? ? ? print("input error!")
? ? ? ? return -1
? ? if n == 1 or n == 2:
? ? ? ? return 1
? ? else:
? ? ? ? return fab(n-1) + fab(n-2)
num = int(input("請輸入一個數字:"))
result = fab(num)
print("斐波那契數列結果為:%d" % result)
漢諾塔游戲(遞歸)
def hanoi(n, x, y, z):
? ? if n == 1:
? ? ? ? print(x, '-->', z)
? ? else:
? ? ? ? hanoi(n-1, x, y, z) ? ? #將前n-1個盤子從x移動到y上
? ? ? ? print(x, '-->', z) ? ? ?#將最底下的最后一個盤子從x移動到z上
? ? ? ? hanoi(n-1, y, x, z) ? ? #將y上的n-1個盤子移動到z上
n = int(input('請輸入漢諾塔的層數:'))
hanoi(n, 'x', 'y', 'z')
---------------------------------2017.08.29--------------------------------------
12丶字典 dict
(1) 字典是一種映射類型(key:value 鍵值映射項),類型名為 dict
(2) 字典的表示使用{}大括號,元素映射之間使用:冒號,使用dictname[]訪問字典映射的值
(3) 新建字典有兩種方法:三層小括號,一層小括號中key=value
(4) 字典中的鍵值映射項是無序的,popitem時是隨機彈出
(5) 字典基本操作:
len(d) 返回d中項的數量
d[k] 返回映射到鍵k上的值
d[k]=v 將值v映射到鍵k上
del d[k] 刪除鍵為k的項
k in d 檢查d中是否含有鍵為k的項
(6) 字典常用方法: clear()/copy()/fromkeys()/get()/has_key()/items()/iteritems()/keys()/iterkeys()/pop()/popitem()/setdefault()/update()/values()/itervalues()
映射關系示例
>>> brand = ['李寧', '耐克', '阿迪達斯', 'xx工作室']
>>> slogan = ['一切皆有可能', 'Just do it', 'Impossible is nothing', '讓編程改變世界']
>>> print('魚c工作室的口號是: ', slogan[brand.index('xx工作室')])
xx工作室的口號是: ?讓編程改變世界
#使用字典來完成映射工作
>>> dict1 = {'李寧':'一切皆有可能', '耐克':'Just do it', '阿迪達斯':'Impossible is nothing', 'xx工作室':'讓編程改變世界'}
>>> print('xx工作室的口號是: ', dict1['xx工作室'])
xx工作室的口號是: ?讓編程改變世界
#新建一個字典方法1:dict(((key1, value1), (key2, value2), ...))
>>> dictname = dict((('y', 1), ('u', 2), ('a', 3), ('n', 4)))
>>> dictname
{'u': 2, 'a': 3, 'y': 1, 'n': 4}
#新建一個字典方法2:(key1=value1, key2=value2, ...)
>>> dictname = dict(蒼井空='讓AV改變宅男', 工作室='讓編程改變世界')
>>> dictname
{'工作室': '讓編程改變世界', '蒼井空': '讓AV改變宅男'}
>>> dictname['蒼井空']
'讓AV改變宅男'
#字典中新增映射元素
>>> dictname['愛迪生'] = '天才是99%的汗水+1%的靈感,但這1%的靈感比99%的汗水更重要。'
>>> dictname
{'工作室': '讓編程改變世界', '愛迪生': '天才是99%的汗水+1%的靈感,但這1%的靈感比99%的汗水更重要。', '蒼井空': '讓AV改變宅男'}
字典中鍵、值、鍵值映射項的訪問
>>> dict1 = dict1.fromkeys(range(10), '贊')
>>> dict1
{0: '贊', 1: '贊', 2: '贊', 3: '贊', 4: '贊', 5: '贊', 6: '贊', 7: '贊', 8: '贊', 9: '贊'}
>>> for eachKey in dict1.keys():
print(eachKey, end=' ')
0 1 2 3 4 5 6 7 8 9
>>> for eachValue in dict1.values():
print(eachValue, end=' ')
贊 贊 贊 贊 贊 贊 贊 贊 贊
>>> for eachItems in dict1.items():
print(eachItems, end=' ')
(0, '贊') (1, '贊') (2, '贊') (3, '贊') (4, '贊') (5, '贊') (6, '贊') (7, '贊') (8, '贊') (9, '贊')
fromkeys(...) ?創建并返回一個新的字典
dictname.fromkeys(S[, V])
@S key;@V value 可選參數
舉例:
>>> dict1 = {}
>>> dict1.fromkeys((1, 2, 3))
{1: None, 2: None, 3: None}
>>> dict1.fromkeys((1, 2, 3), 'number')
{1: 'number', 2: 'number', 3: 'number'}
>>> dict1.fromkeys((1, 2, 3), ('one', 'two', 'three'))
{1: ('one', 'two', 'three'), 2: ('one', 'two', 'three'), 3: ('one', 'two', 'three')}
>>> dict1.fromkeys((1, 3), 'num')
{1: 'num', 3: 'num'} ? #還是返回新的字典,并不會修改dict1
get(...) ?從字典中找到key的映射值value
舉例:
>>> dict1 = dict.fromkeys(range(10), 'Yes!')
>>> dict1
{0: 'Yes!', 1: 'Yes!', 2: 'Yes!', 3: 'Yes!', 4: 'Yes!', 5: 'Yes!', 6: 'Yes!', 7: 'Yes!', 8: 'Yes!', 9: 'Yes!'}
>>> dict1.get(10)
>>> print(dict1.get(10))
None
>>> dict1.get(10, '木有')
'木有'
>>> dict1.get(9, '木有')
'Yes!'
setdefault(...) ?類似于get但在字典里如果找不到的話會將映射項添加到字典中
dictname.setdefault(key, value)
舉例:
>>> a
{3: 'three', 4: 'four'}
>>> a.setdefault(5, '小白')
'小白'
>>> a
{3: 'three', 4: 'four', 5: '小白'}
clear() ?清空一個字典(包括使用當前字典賦值的其他字典)
舉例:
>>> dict1.clear()
>>> dict1
{}
copy() ?拷貝一個字典(淺拷貝,不受字典修改影響)
>>> a = {1:'one', 2:'two', 3:'three'}
>>> b = a.copy()
>>> c = a #相當于C的指針,C++的引用,修改字典c的值會同時影響字典a
>>> a
{1: 'one', 2: 'two', 3: 'three'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}
>>> c
{1: 'one', 2: 'two', 3: 'three'}
>>> print(id(a), id(b), id(c))
2334673012680 2334672609672 2334673012680
>>> c[4] = 'four'
>>> c
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> b
{1: 'one', 2: 'two', 3: 'three'}
pop(...) ?給定一個鍵彈出一個值
popitem() ?隨機彈出一個項(映射關系的鍵和值)
舉例:
>>> a
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> a.pop(2)
'two'
>>> a
{1: 'one', 3: 'three', 4: 'four'}
>>> a.popitem()
(1, 'one')
>>> a
{3: 'three', 4: 'four'}
update(...) ?使用一個子字典去更新原字典
dictname1.update(dictname2)
舉例:
>>> a
{3: 'three', 4: 'four', 5: '小白'}
>>> b = {'小白':'狗'}
>>> a.update(b)
>>> a
{'小白': '狗', 3: 'three', 4: 'four', 5: '小白'}
13丶集合 set
(1) 使用{}創建的沒有映射關系的字典,成為集合類型,如num = {1, 2, 3, 4, 5}
(2) 集合中元素唯一,重復的數據會被自動清理掉
(3) 集合中元素無序,不能索引取到其元素的值
(4) 集合使用關鍵字 set([]) 來創建
(5) 集合支持 in 和 not in 來判斷是否屬于集合
舉例:
>>> num = {}
>>> type(num)
<class 'dict'>
#set沒有體現字典的映射
>>> num1 = {1, 2, 3, 4, 5}
>>> type(num1)
<class 'set'>
#set唯一性
>>> num2 = {1, 2, 3, 4, 2, 3, 5, 1, 5, 5}
>>> num2
{1, 2, 3, 4, 5}
#set無序性
>>> num2[2]
TypeError: 'set' object does not support indexing
#set關鍵字創建集合
>>> set1 = set([1, 2, 3, 4, 5, 5, 5, 3, 1])
>>> set1
{1, 2, 3, 4, 5}
#list實現set的唯一性
>>> num1 = [1, 2, 3, 4, 5, 5, 3, 1, 0]
>>> temp = []
>>> for each in num1:
if each not in temp:
temp.append(each)
>>> temp
[1, 2, 3, 4, 5, 0]
#簡化: 實現set的唯一性,并且會把set的無序性變為有序
>>> num1
[1, 2, 3, 4, 5, 5, 3, 1, 0]
>>> num1 = list(set(num1))
>>> num1
[0, 1, 2, 3, 4, 5]
add(...) ?往集合中加入元素
remove(...) ?從集合中刪除指定元素
舉例:
>>> num2
{1, 2, 3, 4, 5}
>>> num2.add(6)
>>> num2
{1, 2, 3, 4, 5, 6}
>>> num2.remove(4)
>>> num2
{1, 2, 3, 5, 6}
frozenset(...) ?將集合設置為不可變集合,frozen:冰凍的,凍結的
舉例:
>>> num3 = frozenset([1, 2, 3, 4, 5])
>>> num3
frozenset({1, 2, 3, 4, 5})
>>> num3.add(6)
AttributeError: 'frozenset' object has no attribute 'add'
集合內建方法(整理出來):
http://bbs.fishc.com/forum.php?mod=viewthread&tid=45276&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
14丶文件操作 file operation
open(...) ?打開一個文件返回一個流對象
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) ?#除了file參數,其他參數均有默認值
'r' 只讀模式
'w' 寫入(會覆蓋已存在的文件)模式
'x' 文件存在,報異常的模式
'a' 寫入(文件存在則追加)模式
'b' 二進制模式
't' 文本模式
'+' 可讀寫模式(可添加到其他模式)
'U' 通用換行符支持
舉例:
#打開一個文件,注意路徑的中\反斜杠的轉義(或用/斜杠一根即可)
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt')
>>> f
<_io.TextIOWrapper name='C:\\Users\\Jan\\Desktop\\IP.txt' mode='r' encoding='cp936'>
文件對象方法
(整理)
http://bbs.fishc.com/forum.php?mod=viewthread&tid=45279&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
(1) 文件對象支持直接使用list轉換讀出
(2) 文件對象支持 for...in 的迭代方式讀取
舉例:
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt') #f,打開的文件流對象
>>> f.read()
'【本機】\nIP:192.168.31.217\n[ Ctrl + r ]\ncmd\nping 192.168.31.207\nmstsc\n\n\n【虛擬機】 - 虛擬網絡編輯器(自動) - 橋接模式\nIP:192.168.31.207\nlinux賬戶:jiangyuan\nlinux密碼:123456\n'
>>> f.read()
''
>>> f.close()
>>> f = open('C:\\Users\\Jan\\Desktop\\IP.txt')
>>> f.read(5)
'【本機】\n'
>>> f.tell()
10
>>> f.seek(45, 0) #0,文件起始位置;45,偏移字節數。從文件起始位置偏移一定量字節
45
>>> f.readline()
'md\n'
>>> list(f)
['ping 192.168.31.207\n', 'mstsc\n', '\n', '\n', '【虛擬機】 - 虛擬網絡編輯器(自動) - 橋接模式\n', 'IP:192.168.31.207\n', 'linux賬戶:jiangyuan\n', 'linux密碼:123456\n']
>>> for each_line in f:
print(each_line)#逐行讀取文件內容的高效方法
【本機】
IP:192.168.31.217
[ Ctrl + r ]
cmd
ping 192.168.31.207
mstsc
...
#創建一個新的可寫入的文件,寫入內容,然后關閉文件流對象
>>> f = open('C:\\Users\\Jan\\Desktop\\test.txt', 'w')
>>> f.write('some lines')
10
>>> f.close()
任務:將文件record.txt中的數據進行分割并且按照規律保存起來。
record.txt下載:
鏈接:http://pan.baidu.com/s/1sjzAhNR (密碼:tf2e)
#最終代碼如下:
def save_file(boy, girl, count):
? ? # 文件的分別保存操作
? ? file_name_boy = 'boy_' + str(count) + '.txt'
? ? file_name_girl = 'girl_' + str(count) + '.txt'
? ? boy_f = open(file_name_boy, 'w')
? ? girl_f = open(file_name_girl, 'w')
? ? boy_f.writelines(boy)
? ? girl_f.writelines(girl)
? ? boy_f.close()
? ? girl_f.close()
def split_file(filename):
? ? f = open(filename)
? ? boy = []
? ? girl = []
? ? count = 1
? ? for each_line in f:
? ? ? ? if each_line[:6] != '======':
? ? ? ? ? ? # 我們再這里進行字符串分割操作
? ? ? ? ? ? (role, line_spoken) = each_line.split(':', 1) ?#中文冒號:否則會報錯
? ? ? ? ? ? if role == '小甲魚':
? ? ? ? ? ? ? ? boy.append(line_spoken)
? ? ? ? ? ? if role == '小客服':
? ? ? ? ? ? ? ? girl.append(line_spoken)
? ? ? ? else:
? ? ? ? ? ? save_file(boy, girl, count)
? ? ? ? ? ? boy = []
? ? ? ? ? ? girl = []
? ? ? ? ? ? count += 1
? ? save_file(boy, girl, count)
? ? f.close()
split_file('C:\\Users\\Jan\\Desktop\\python_study\\record.txt')
文件操作練習題及答案(偽代碼可以保存一下):
http://blog.csdn.net/junwei0206/article/details/44988195
---------------------------------2017.08.30--------------------------------------
15丶模塊 modules
(1) 模塊是.py的python文件
(2) 使用模塊是需要進行導入,使用關鍵字 import
舉例:
>>> import random
>>> secret = random.randint(1, 10)
>>> secret
3
os 模塊(系統模塊)
os模塊方法表格:http://bbs.fishc.com/thread-45512-1-2.html
舉例:
>>> import os
>>> os.getcwd() ?#輸出當前工作目錄
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35'
>>> os.chdir('E:\\') ?#改變工作目錄
>>> os.getcwd()
'E:\\'
>>> os.listdir('E:\\') ?#列舉指定目錄中的文件名
['$RECYCLE.BIN', '.cache', '360Downloads', 'Jan_mi', 'Jan個人總資料', 'Qiyi', 'QQMusicCache', 'qycache', 'System Volume Information', 'Youku Files', 'Youxun', '博客'] ?#RECYCLE.BIN是個回收站
>>> os.mkdir('E:\\A') ?#創建單層目錄,如該目錄已存在拋出異常
>>> os.mkdir('E:\\A\\B')
>>> os.mkdir('E:\\C\\D')
FileNotFoundError: [WinError 3] 系統找不到指定的路徑。: 'E:\\C\\D'
>>> os.remove('E:\\A\\B\\test.txt') ?#刪除文件
>>> os.rmdir('E:\\A\\B\\') ?#刪除單層目錄,如該目錄非空則拋出異常
>>> os.system('cmd') ?#運行系統的shell命令:windows shell窗口
-1073741510
>>> os.system('calc') ?#運行系統的shell命令:calc計算器
0
>>> os.curdir ?#當前目錄('.')
'.'
>>> os.listdir(os.curdir) ?# 等同于 os.listdir('.')
['$RECYCLE.BIN', '.cache', '360Downloads', 'A', 'Jan_mi', 'Jan個人總資料', 'Qiyi', 'QQMusicCache', 'qycache', 'System Volume Information', 'Youku Files', 'Youxun', '博客']
>>> os.sep ?#輸出操作系統特定的路徑分隔符(Win下為'\\',Linux下為'/')
'\\'
>>> os.linesep ?#當前平臺使用的行終止符(Win下為'\r\n',Linux下為'\n')
'\r\n'
>>> os.name ?#指代當前使用的操作系統(包括:'posix', ?'nt', 'mac', 'os2', 'ce', 'java')
'nt' ?#nt是windows系統平臺
os.path 模塊(系統路徑模塊屬于os的子模塊)
>>> os.path.basename('E:\\A\\B\\C\\sexy.avi') ?#去掉目錄路徑,單獨返回文件名
'sexy.avi'
>>> os.path.dirname('E:\\A\\B\\C\\sexy.avi') ?#去掉文件名,單獨返回目錄路徑
'E:\\A\\B\\C'
>>> os.path.join('A', 'B', 'C') ?#將path1, path2...各部分組合成一個路徑名
'A\\B\\C'
>>> os.path.join('D:', 'A', 'B', 'C')
'D:A\\B\\C'
>>> os.path.join('D:\\', 'A', 'B', 'C') ?#注意盤符需要帶上斜杠
'D:\\A\\B\\C'
>>> os.path.split('E:\\A\\SEXY.AVI') ?#分割文件名與路徑,返回(f_path, f_name)元組。
('E:\\A', 'SEXY.AVI')
>>> os.path.split('E:\\A\\B\\C')
('E:\\A\\B', 'C')
>>> os.path.splitext('E:\\A\\SEXY.AVI') ?#分離文件名與擴展名,返回(f_name, f_extension)元組
('E:\\A\\SEXY', '.AVI')
>>> os.path.getatime('E:\\A\\test.txt') ?#返回指定文件最近的訪問時間
1504103243.229383 ?#浮點型秒數,可用time模塊的gmtime()或localtime()函數換算
>>> import time
>>> time.gmtime(os.path.getatime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=14, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getatime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getmtime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=30, tm_sec=1, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> time.localtime(os.path.getctime('E:\\A\\test.txt'))
time.struct_time(tm_year=2017, tm_mon=8, tm_mday=30, tm_hour=22, tm_min=27, tm_sec=23, tm_wday=2, tm_yday=242, tm_isdst=0)
>>> os.path.ismount('E:\\') ?#判斷指定路徑是否存在且是一個掛載點
True
>>> os.path.ismount('E:\\A')
False
pickle 模塊(泡菜模塊)
舉例:
>>> import pickle
>>> my_list = [123, 3.14, '名字', ['another list']]
>>> pickle_f = open('E:\\A\\my_list.pkl', 'wb')
>>> pickle.dump(my_list, pickle_f) ?#將list的內容傾倒入文件流對象中
>>> pickle_f.close()
>>> pickle_f = open('E:\\A\\my_list.pkl', 'rb')
>>> my_list2 = pickle.load(pickle_f) ?#將.pkl文件的內容裝載到list中
>>> print(my_list2)
[123, 3.14, '名字', ['another list']]
>>> city = {'城市1':'000001', '城市2':'000002', '城市n':'999999'} ?#此字典映射有70k這么大
>>> import pickle
>>> pickle_f = open('E:\\A\\city.pkl', 'wb') ?#將70k的字典映射寫入文件
>>> pickle.dump(city, pickle_f)
>>> pickle_f.close()
>>> pickle_file = open('E:\\A\\city.pkl', 'rb') ?#使用字典的時候打開文件裝載即可
>>> city = pickle.load(pickle_file)
>>> print(city)
{'城市2': '000002', '城市n': '999999', '城市1': '000001'}
---------------------------------2017.08.31--------------------------------------
16丶異常 exception
異常匯總
AssertionError 斷言語句(assert)失敗<eg1>
AttributeError 嘗試訪問未知的對象屬性<eg2>
EOFError 用戶輸入文件末尾標志EOF(Ctrl+d)?
FloatingPointError 浮點計算錯誤?
GeneratorExit generator.close()方法被調用的時候?
ImportError 導入模塊失敗的時候?
IndexError 索引超出序列的范圍<eg3>
KeyError 字典中查找一個不存在的關鍵字<eg4>
KeyboardInterrupt 用戶輸入中斷鍵(Ctrl+c)?
MemoryError 內存溢出(可通過刪除對象釋放內存)?
NameError 嘗試訪問一個不存在的變量?
NotImplementedError 尚未實現的方法?
OSError 操作系統產生的異常(例如打開一個不存在的文件)?
OverflowError 數值運算超出最大限制?
ReferenceError 弱引用(weak reference)試圖訪問一個已經被垃圾回收機制回收了的對象?
RuntimeError 一般的運行時錯誤?
StopIteration 迭代器沒有更多的值?
SyntaxError Python的語法錯誤?
IndentationError 縮進錯誤?
TabError Tab和空格混合使用?
SystemError Python編譯器系統錯誤?
SystemExit Python編譯器進程被關閉?
TypeError 不同類型間的無效操作?
UnboundLocalError 訪問一個未初始化的本地變量(NameError的子類)?
UnicodeError Unicode相關的錯誤(ValueError的子類)?
UnicodeEncodeError Unicode編碼時的錯誤(UnicodeError的子類)?
UnicodeDecodeError Unicode解碼時的錯誤(UnicodeError的子類)?
UnicodeTranslateError Unicode轉換時的錯誤(UnicodeError的子類)?
ValueError 傳入無效的參數?
ZeroDivisionError 除數為零?
部分舉例:
>>> my_list = ['我是帥哥', '你是美女']
>>> assert len(my_list) > 0
>>> my_list.pop()
'你是美女'
>>> my_list.pop()
'我是帥哥'
>>> assert len(my_list) > 0
Traceback (most recent call last):
? File "<pyshell#856>", line 1, in <module>
? ? assert len(my_list) > 0
AssertionError #斷言語句(assert)失敗
>>> my_list.abcd
Traceback (most recent call last):
? File "<pyshell#857>", line 1, in <module>
? ? my_list.abcd
AttributeError: 'list' object has no attribute 'abcd'#嘗試訪問未知的對象屬性
>>> my_list = [1, 2, 3]
>>> my_list[3]
Traceback (most recent call last):
? File "<pyshell#859>", line 1, in <module>
? ? my_list[3]
IndexError: list index out of range #索引超出序列的范圍
>>> my_list[2]
3
>>> my_dict = {'one':1, 'two':2, 'three':3}
>>> my_dict['one']
1
>>> my_dict['four']
Traceback (most recent call last):
? File "<pyshell#863>", line 1, in <module>
? ? my_dict['four']
KeyError: 'four' #字典中查找一個不存在的關鍵字
>>> my_dict.get('four')
>>> #dict.get(...)方法比較安全合適
異常檢測與處理
(1) try語句一旦檢測出現異常,則剩下的其他代碼則不會執行
(2) raise Exception_name 主動引發一個自定義異常名字的異常,可定義異常描述
try:
#檢測范圍
except Exception[as reason]:
#出現異常(Exception)后的處理代碼
finally:
#無論如何都會被執行的代碼(收尾工作)
舉例:
try:
? ? f = open('我為什么是一個文件.txt')
? ? print(f.read())
? ? f.close()
except OSError:
? ? print('文件出錯啦T_T')
運行:
文件出錯啦T_T
try:
? ? f = open('我為什么是一個文件.txt')
? ? print(f.read())
? ? f.close()
except OSError as reason:
? ? print('文件出錯啦T_T\n錯誤的原因是:' + str(reason))
運行:
文件出錯啦T_T
錯誤的原因是:[Errno 2] No such file or directory: '我為什么是一個文件.txt'
try:
? ? sum = 1 + '1'
? ? f = open('我為什么是一個文件.txt')
? ? print(f.read())
? ? f.close()
except (OSError, TypeError): ?#多個異常同時捕獲
? ? print('出錯啦T_T')
運行:出錯啦T_T
try:
? ? f = open('我為什么是一個文件.txt', 'w')
? ? print(f.write('我存在了!')) ?#沒有finally時并不會寫入文件
? ? sum = 1 + '1'
? ? f.close()
except (OSError, TypeError):
? ? print('出錯啦T_T')
finally:
? ? f.close()
運行:
5
出錯啦T_T
>>> raise ZeroDivisionError('除數為0的異常')
Traceback (most recent call last):
? File "<pyshell#872>", line 1, in <module>
? ? raise ZeroDivisionError('除數為0的異常')
ZeroDivisionError: 除數為0的異常
17丶豐富的esle-簡潔的with
else
舉例:while-else / for-else
def showMaxFactor(num):
? ? count = num // 2
? ? while count > 1:
? ? ? ? if num % count == 0:
? ? ? ? ? ? print('%d最大的約數是%d' % (num, count))
? ? ? ? ? ? break
? ? ? ? count -= 1
? ? else: #while循環完沒有break就會執行else
? ? ? ? print('%d是素數!' % num)
num = int(input('請輸入一個數:'))
showMaxFactor(num)
舉例:try-else
try:
? ? print(int('123'))
except ValueError as reason:
? ? print('出錯啦:' + str(reason))
else:
? ? print('Good!沒有任何異常。')
運行:
123
Good!沒有任何異常。
with as
舉例:
try:
? ? with open('data.txt', 'w') as f: #比 f = open(...) 多了文件不使用時自動關閉功能
? ? for each_line in f:
? ? ? ? print(each_line)
except OSError as reason:
? ? print('出錯啦:' + str(reason))
#finally: ? ? ? #有了with就不需要finally去調用關閉,會自動關閉
# ? ?f.close() ?#如果文件data.txt不存在就試圖去關閉一個不存在的文件
18丶圖形用戶界面 EasyGui
EasyGui官網:http://easygui.sourceforge.net
中文的教學文檔:http://bbs.fishc.com/thread-46069-1-1.html (要看完并實操)
模塊庫:easygui-0.96.zip
安裝方法:
(1) 使用命令窗口切換到easygui-docs-0.96的目錄下
(2) 【Windows下】執行C:\Python33\python.exe setup.py install
> cd Desktop
> cd puthon_study\easygui-0.96
#然后修改C:\Program Files (x86)\python\python.exe為管理員權限:右鍵-兼容性-更改所有用戶的設置-以管理員身份運行此程序-確定
> "C:\Program Files (x86)\python\python.exe" setup.py install
#生成了文件模塊庫C:\Program Files (x86)\python\Lib\site-packages\easygui.py
> "C:\Program Files (x86)\python\python.exe" easygui.py
#easygui的演示程序
PS: 【Linux或Mac下】sudo /Library/Framworks/Python.framework/Versions/3.3/bin/python3.3 setup.py install
使用方法:
【遇到難題】import easygui 出錯~!!!
【解決辦法】
(1) 重裝python IDLE勾選添加python路徑,選擇目錄安裝到C:\python文件夾,如重裝則忽略(2),如此一來win-cmd下的python中sys.path和IDLE中的sys.path則一致了。
(2) 對比windows命令窗口中啟動python與IDLE中python的系統路徑,添加到IDLE即可。
windows中系統路徑:
C:\Users\Jan> "C:\Program Files (x86)\python\python.exe"
>>> import sys
>>> sys.path
['',?
'C:\\Program Files (x86)\\python\\python35.zip',?
'C:\\Program Files (x86)\\python\\DLLs',?
'C:\\Program Files (x86)\\python\\lib',?
'C:\\Program Files (x86)\\python',?
'C:\\Program Files (x86)\\python\\lib\\site-packages']
IDLE中系統路徑:
>>> import easygui as g
Traceback (most recent call last):
? File "<pyshell#0>", line 1, in <module>
? ? import easygui as g
ImportError: No module named 'easygui'
>>> import sys
>>> sys.path
['',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\Lib\\idlelib',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\python35.zip',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\DLLs',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\lib',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35',?
'C:\\Users\\Jan\\AppData\\Local\\Programs\\Python\\Python35\\lib\\site-packages']
>>> sys.path.append('C:\\Program Files (x86)\\python\\python35.zip')
>>> sys.path.append('C:\\Program Files (x86)\\python\\DLLs')
>>> sys.path.append('C:\\Program Files (x86)\\python\\lib')
>>> sys.path.append('C:\\Program Files (x86)\\python')
>>> sys.path.append('C:\\Program Files (x86)\\python\\lib\\site-packages')
>>> import easygui as g ?#import ... as ... 導入模塊的同時重定義模塊名字
>>> g.msgbox('嗨,python!')
'OK'
>>>?
# No error, success... 但每次重啟IDLE都需要將windows下的sys.path進行添加。
# 示例,gui界面文字小游戲
import easygui as g
import sys
while 1:
? ? ? ? g.msgbox("嗨,歡迎進入第一個界面小游戲^_^")
? ? ? ? msg ="請問你希望在魚C工作室學習到什么知識呢?"
? ? ? ? title = "小游戲互動"
? ? ? ? choices = ["談戀愛", "編程", "OOXX", "琴棋書畫"]
? ? ? ??
? ? ? ? choice = g.choicebox(msg, title, choices)
? ? ? ? # note that we convert choice to string, in case
? ? ? ? # the user cancelled the choice, and we got None.
? ? ? ? g.msgbox("你的選擇是: " + str(choice), "結果")
? ? ? ? msg = "你希望重新開始小游戲嗎?"
? ? ? ? title = "請選擇"
? ? ? ??
? ? ? ? if g.ccbox(msg, title): ? ? # show a Continue/Cancel dialog
? ? ? ? ? ? ? ? pass ?# user chose Continue
? ? ? ? else:
? ? ? ? ? ? ? ? sys.exit(0) ? ? # user chose Cancel
---------------------------------2017.09.01--------------------------------------
19丶類和對象 class and object
面向對象(Object Oriented)
(1) python約定類名以大寫字母開頭
(2) 面向對象特征:封裝(信息隱蔽)、繼承(子類共享父類公共內容)、多態(不同對象對同一方法響應不同的行動)
類的示例:
class Turtle:
#屬性
color = 'green'
weight = 60
legs = 2
shell = True
age = 26
#方法
def climb(self):
print('我正在學習...')
def run(self):
print('我正在奔跑...')
運行:
>>> tt = Turtle() ?#類Turtle的示例對象tt
>>> Turtle
<class '__main__.Turtle'>
>>> type(Turtle)
<class 'type'>
>>> type('abc')
<class 'str'>
>>> tt.climb()
我正在學習...
>>> tt.run()
我正在奔跑...
#封裝
>>> list1 = [2, 1, 7, 5, 3]
>>> list1.sort() ?#sort() 方法封裝在list1對象中
>>> list1
[1, 2, 3, 5, 7]
>>> list1.append(9) ?#append() 方法封裝在list1對象中
>>> list1
[1, 2, 3, 5, 7, 9]
#繼承
>>> class Mylist(list):
pass
>>> list2 = Mylist()
>>> list2.append(5) ?#list2可以使用append()方法,繼承了Mylist(list)中的list參數類
>>> list2.append(3)
>>> list2.append(7)
>>> list2
[5, 3, 7]
>>> list2.sort()
>>> list2
[3, 5, 7]
#多態
>>> class A:
def fun(self):
print('我是小A')
>>> class B:
def fun(self):
print('我是小B')
>>> a = A()
>>> b = B()
>>> a.fun() ?#不同對象對同一方法響應不同的行動
我是小A
>>> b.fun() ?#不同對象對同一方法響應不同的行動
我是小B
self
相當于C++的this指針(指向當前對象本身的地址),表明類自身
舉例:
>>> class Ball:
def setName(self, name): ?#默認self的寫法
self.name = name
def kick(self): ?#默認self的寫法
print('我叫%s, 該死的誰踢我...' % self.name)
>>> a = Ball()
>>> a.setName('球A')
>>> b = Ball()
>>> b.setName('球B')
>>> c = Ball()
>>> c.setName('土豆')
>>> a.kick()
我叫球A, 該死的誰踢我...
>>> c.kick()
我叫土豆, 該死的誰踢我...
魔法方法:__init__(self)
__init__(self, parma1, parma2, ...)
舉例:
>>> class Ball:
def __init__(self, name):
self.name = name
def kick(self):
print('我叫%s,該死的,誰踢我!!' % self.name)
>>> b = Ball('土豆')
>>> b.kick()
我叫土豆,該死的,誰踢我!!
>>> a = Ball() ?#__init__默認設置了name,所以必須傳遞name實參,否則報錯
TypeError: __init__() missing 1 required positional argument: 'name'
公有和私有
name mangling 名字改變/名字重造
公有成員:默認創建的成員均為公有。
私有成員:
(1) 在變量或函數名前加上"_"兩個下劃線即可。
(2) python中類的私有均屬于偽私有,通過"對象._類_變量"的形式可以訪問私有成員
舉例:
>>> class Person:
__name = 'yuan.jiang'
>>> p = Person()
>>> p.name
AttributeError: 'Person' object has no attribute 'name'
>>> p.__name
AttributeError: 'Person' object has no attribute '__name'
>>> class Person:
__name = 'yuan.jiang'
def getName(self):
return self.__name
>>> p = Person()
>>> p.getName()
'yuan.jiang'
>>> p._Person__name ?#python中類的私有屬于偽私有,此方式可訪問私有成員
'yuan.jiang'
繼承 inherit
class DerivedClassName(BaseClassName):
...
(1) 如果子類中定義于父類同名的成員時,則會自動覆蓋父類對應的方法或屬性
(2) 解決子類中__init()
舉例:
>>> class Parent:
def hello(self):
print('正在調用父類的方法...')
>>> class Child(Parent):
pass
>>> p = Parent()
>>> p.hello()
正在調用父類的方法...
>>> c = Child()
>>> c.hello()
正在調用父類的方法...
>>> class Child(Parent):
def hello(self):
print('正在調用子類的方法...')
>>> c = Child()
>>> c.hello()
正在調用子類的方法...
>>> p.hello()
正在調用父類的方法...
舉例:
import random as r
class Fish:
? ? def __init__(self):
? ? ? ? self.x = r.randint(0, 10)
? ? ? ? self.y = r.randint(0, 10)
? ? def move(self):
? ? ? ? self.x -= 1
? ? ? ? print('我的位置是:', self.x, self.y)
class Goldfish(Fish):
? ? pass
class Carpfish(Fish):
? ? pass
class Salmonfish(Fish):
? ? pass
class Sharkfish(Fish):
? ? def __init__(self): ?#重寫了__init__方法覆蓋了父類的__init__子類無法調用到self.x和self.y屬性成員,導致了子類無法訪問到父類的屬性或方法的問題
? ? ? ? self.hungry = True
? ? def eat(self):
? ? ? ? if self.hungry:
? ? ? ? ? ? print('吃貨的夢想就是天天有的吃^_^')
? ? ? ? ? ? self.hungry = False
? ? ? ? else:
? ? ? ? ? ? print('太撐了,吃不下了!')
運行:
>>> fish = Fish()
>>> fish.move()
我的位置是: 3 0
>>> fish.move()
我的位置是: 2 0
>>> goldfish = Goldfish()
>>> goldfish.move()
我的位置是: 4 9
>>> goldfish.move()
我的位置是: 3 9
>>> shark = Sharkfish()
>>> shark.eat()
吃貨的夢想就是天天有的吃^_^
>>> shark.eat()
太撐了,吃不下了!
>>> shark.move() ?#無法訪問到父類的__init__()方法中的x變量
AttributeError: 'Sharkfish' object has no attribute 'x'
--------------------------------2017.09.02----------------------------------------
覆蓋屬性或方法問題優化
問題:針對子類屬性或方法覆蓋父類屬性或方法的情況,導致子類無法訪問父類中被覆蓋的屬性
(1) 調用未綁定的父類的方法
(2) 使用super方法(推薦)
舉例:
def __init__(self):
Fish.__init__(self) ?#調用未綁定的父類的方法,相當于>>>Fish.__init__(Sharkfish)
self.hungry = True
運行:
>>> shark = Sharkfish()
>>> shark.move()
我的位置是: -1 2
>>> shark.move()
我的位置是: -2 2
舉例:
def __init__(self):
super().__init__() ?#使用super方法解決
self.hungry = True
運行:
>>> shark = Sharkfish()
>>> shark.move()
我的位置是: 8 3
>>> shark.move()
我的位置是: 7 3
多重繼承
class DerivedClassName(Base1, Base2, Base3, ...):
...
#建議少用,有可能會導致不可預見的bug(不可預見最麻煩)
>>> class Base1:
def fool(self):
print('我是fool,我為Base1代言...')
>>> class Base2:
def fool2(self):
print('我是fool2,我為Base2代言...')
>>> class C(Base1, Base2):
pass
>>> c = C()
>>> c.fool()
我是fool,我為Base1代言...
>>> c.fool2()
我是fool2,我為Base2代言...
組合
class Turtle:
? ? def __init__(self, x):
? ? ? ? self.num = x
class Fish:
? ? def __init__(self, x):
? ? ? ? self.num = x
class Pool:
? ? def __init__(self, x, y): ?#組合的方式嵌套class
? ? ? ? self.turtle = Turtle(x)
? ? ? ? self.fish ?= Fish(y)
? ? def print_num(self):
? ? ? ? print('水池里總共有烏龜 %d 只,小魚 %d 條!' % (self.turtle.num, self.fish.num))
運行:
>>> pool = Pool(1, 10)
>>> pool.print_num()
水池里總共有烏龜 1 只,小魚 10 條!
類、類對象、示例對象
類定義 ? ?C
類對象 ? ?C
實例對象 ?a ?b ?c
舉例:
>>> class C: ? #C, 既是類,也是類對象
count = 0
>>> a = C() ? ?#a,實例對象
>>> b = C() ? ?#b,實例對象
>>> c = C() ? ?#c,實例對象
>>> a.count
0
>>> b.count
0
>>> c.count
0
>>> c.count += 10
>>> c.count
10
>>> a.count
0
>>> b.count
0
>>> C.count ? ?#C,作為類對象
0
>>> C.count += 100 ? ?#C,作為類對象
>>> a.count
100
>>> b.count
100
>>> c.count
10
(1) 當屬性名與方法名沖突,會導致方法不能正常調用。
(2) 一般遵循規則:屬性名用英文名詞,方法名用英文動詞。
(3) python嚴格要求方法需要有實例才能被調用,即綁定的概念。
舉例:
>>> class C:
def x(self):
print('X-man!')
>>> c = C()
>>> c.x()
X-man!
>>> c.x = 1
>>> c.x
1
>>> c.x() ?#方法名字被屬性名字覆蓋,調用出錯
TypeError: 'int' object is not callable
>>> class BB:
def printBB():
print('no zuo no die.')
>>> BB.printBB()
no zuo no die.
>>> #沒有self,也沒有將類實例化
>>> bb = BB()
>>> bb.printBB()
Traceback (most recent call last):
? File "<pyshell#187>", line 1, in <module>
? ? bb.printBB()
TypeError: printBB() takes 0 positional arguments but 1 was given
>>> class CC:
def setXY(self, x, y):
self.x = x;
self.y = y
>>> class CC:
def setXY(self, x, y):
self.x = x
self.y = y
def printXY(self):
print(self.x, self.y)
>>> dd = CC()
>>> dd.__dict__
{} ?#返回空的字典類型
>>> CC.__dict__
mappingproxy({'printXY': <function CC.printXY at 0x0000020483176EA0>, '__doc__': None, '__dict__': <attribute '__dict__' of 'CC' objects>, 'setXY': <function CC.setXY at 0x0000020483176E18>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'CC' objects>}) ?#使用類對象顯示類的屬性詳情
>>> dd.setXY(4, 5)
>>> dd.__dict__
{'y': 5, 'x': 4} ?#將實例對象dd使用類的屬性詳情實例化了
>>> # setXY(self, x, y) <==> dd.setXY(dd, x, y)
>>> del CC
>>> ee = CC()
NameError: name 'CC' is not defined
>>> dd.printXY()
4 5 ?#類中定義的屬性是靜態的,類的實例對象中也會靜態存儲,所以實例對象dd正常存在。
類與對象的內置函數
issubclass
功能:測試一個類是否是另外一個類的子類
issubclass(class, classinfo)
(1) 一個類被認為是其自身的子類
(2) classinfo可以是類對象的元組,只要class屬于其中任何一個候選類的子類,則返回True
舉例:
>>> class A:
pass
>>> class B(A):
pass
>>> issubclass(B, A)
True
>>> issubclass(B, B)
True
>>> issubclass(B, object) ?#object是所有類的基類
True
>>> class C:
pass
>>> issubclass(B, C)
isinstance
功能:測試一個對象是否是一個類的實例對象
isinstance(object, classinfo)
(1) object為類的實例對象,如果不是類的實例對象,永遠返回False
(2) 如果第二個參數不是類或者由類對象組成的元組,會拋出一個TypeError異常
舉例:
>>> class A:
pass
>>> class B(A):
pass
>>> class C:
pass
>>> b1 = B()
>>> isinstance(b1, B)
True
>>> isinstance(b1, A)
True
>>> isinstance(b1, C)
False
>>> isinstance(b1, (A, B, C)) ?#b1對象是否在A/B/C里面,答案是True
True
hasattr
功能:測試一個對象里面是否有指定的屬性
hasattr(object, name)
(1) object 對象名, name 是屬性名(需要用引號引起來,否則報錯)
getattr
功能:返回對象指定的屬性值
getattr(object, name[, default])
(1) 如果屬性值不存在打印default,沒有default則拋出異常
setattr
功能:設置對象中指定屬性的值,如果屬性不存在則創建并賦值
setattr(object, name, value)
delattr
功能:刪除對象中指定的屬性,如果屬性不存在則拋出異常
delattr(object, name)
舉例:
>>> class C:
def __init__(self, x=0):
self.x = x
>>> c1 = C()
>>> hasattr(c1, 'x') ?#測試對象屬性是否存在
True
>>> hasattr(c1, x)\
NameError: name 'x' is not defined
>>> getattr(c1, 'x') ?#獲取對象屬性的值
0
>>> getattr(c1, 'y')
AttributeError: 'C' object has no attribute 'y'
>>> getattr(c1, 'y', '您所訪問的屬性不存在!') ?#設置default默認提示語
'您所訪問的屬性不存在!'
>>> setattr(c1, 'y', 100) ?#設置對象屬性的值
>>> getattr(c1, 'y')
100
>>> delattr(c1, 'y') ?#刪除對象屬性的值
>>> delattr(c1, 'y')
Traceback (most recent call last):
? File "<pyshell#264>", line 1, in <module>
? ? delattr(c1, 'y')
AttributeError: y
property
功能:設置一個定義好的屬性,通過對象屬性來設置對象屬性
property(fget=None, fset=None, fdel=None, doc=None)
(1) fget獲取屬性的方法, fset設置屬性的方法, fdel刪除屬性的方法
舉例:
>>> class C:
def __init__(self, size=10):
self.size = size
def getSize(self):
return self.size
def setSize(self, value):
self.size = value
def delSize(self):
del self.size
x = property(getSize, setSize, delSize)
>>> c1 = C()
>>> c1.getSize()
10
>>> c1.x
10
>>> c1.x = 18
>>> c1.x
18
>>> c1.getSize()
18
>>> c1.size
18
>>> del c1.x
>>> c1.size ? ?#x與size相當于相互引用關系,刪除其中一個另一個即不能訪問
AttributeError: 'C' object has no attribute 'size'
20丶魔法方法 magic methods
(1) 魔法方法總是被雙下劃綫包圍,如 __init__
(2) 魔法方法是面向對象的python的一切
(3) 魔法方法的魔力體現在能夠在適當的時候被調用
魔法方法匯總:http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
__init__(self[, ...])
功能:初始化類對象(根據需求決定是否增加屬性參數)
返回值: None
舉例:
>>> class Rectangle: #矩形類,需要長和寬,所以重寫__init__
def __init__(self, x, y):
self.x = x
self.y = y
def getPeri(self): ?#獲得周長
return (self.x + self.y) * 2
def getArea(self): ?#獲得面積
return self.x * self.y
>>> rect = Rectangle(3, 4)
>>> rect.getPeri()
14
>>> rect.getArea()
12
__new__(class[, ...])
功能:創建一個類對象
返回值:返回一個對象
(1) 在__init__方法之前被調用,屬于類創建時第一個被調用的方法
舉例:
>>> class CapStr(str): ?#繼承一個不可改變的類型str
def __new__(cls, string): ?#使用new將類型的功能進行轉換
string = string.upper()
return str.__new__(cls, string) ?#把重寫后的str中的new方法帶傳代餐返回
>>> a = CapStr("I love M.")
>>> a
'I LOVE M.'
__del__(self)
功能:對象將要被銷毀的時候,自動調用,屬于自動垃圾回收方法
注意:del x != x.__del__()
舉例:
>>> class C:
def __init__(self):
print('我是init方法,我被調用了!')
def __del__(self):
print('我是del方法,我被調用了!')
>>> c1 = C()
我是init方法,我被調用了!
>>> c2 = c1 ?#對象的賦值不會調用__init__
>>> c3 = c2
>>> del c3
>>> del c2
>>> del c1 ? #其他的賦值對象del時不會調用__del__ (c2和c3只是c1的一份拷貝)
我是del方法,我被調用了!
算術運算魔法方法
__add__(self, other) 加法:+
__sub__(self, other) 減法:-
__mul__(self, other) 乘法:*
__truediv__(self, other) 真除法:/
__floordiv__(self, other) 整數除法://
__mod__(self, other) 取模算法:%
__divmod__(self, other) divmod()調用時的行為
__pow__(self, other[, modulo]) power()調用或 ** 運算時的行為
__lshift__(self, other) 按位左移:<<
__rshift__(self, other) 按位右移:>>
__and__(self, other) 按位與:&
__xor__(self, other) 按位異或:^
__or__(self, other) 按位或:|
舉例:
>>> class New_int(int):
def __add__(self, other):
return int.__sub__(self, other)
def __sub__(self, other):
return int.__add__(self, other)
>>> a = New_int(3)
>>> b = New_int(5)
>>> a + b
-2
>>> a - b
8
>>> class Try_int(int):
def __add__(self, other):
return int(self) + int(other)
def __sub__(self, other):
return int(self) - int(other)
>>> a = Try_int(3)
>>> b = Try_int(5)
>>> a + b
8
類定制的計時器
(1) 定制一個計時器的類
(2) start和stop方法代表啟動計時和停止計時
(3) 假設計時器對象t1,print(t1)和直接調用t1均顯示結果
(4) 當計時器未啟動或已經停止計時,調用stop方法會給與溫馨的提示
(5) 兩個計時器對象可以進行相加:t1 + t2
需要的資源:
(1) 使用time模塊的localtime方法獲取時間
(2) __str__ 方法 __repr__ 方法可用來打印文字
time 模塊
詳解鏈接:http://bbs.fishc.com/forum.php?mod=viewthread&tid=51326&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
struct_time元組
time.struct_time(tm_year=2017, tm_mon=9, tm_mday=2, tm_hour=12, tm_min=18, tm_sec=55, tm_wday=5, tm_yday=245, tm_isdst=0)
類定制計時器代碼:http://blog.csdn.net/sinat_36184075/article/details/77806778
屬性訪問
__getattribute__(self, name) #定義當該類的屬性被訪問時的行為
__getattr__(self, name) #定義當用戶試圖獲取一個不存在的屬性時的行為
__setattr__(self, name, value) #定義當一個屬性被設置(包括初始化)時的行為
__delattr__(self, name) #定義一個屬性被刪除時的行為
舉例:
>>> class C:
def __getattribute__(self, name):
print('getattribute')
return super().__getattribute__(name)
def __getattr__(self, name):
print('getattr')
def __setattr__(self, name, value):
print('setattr')
super().__setattr__(name, value)
def __delattr__(self, name):
print('delattr')
super().__delattr__(name)
>>> c = C()
>>> c.x
getattribute
getattr
>>> c.x = 1
setattr ?#初始化時自動調用setattr
>>> c.x
getattribute
1
>>> del c.x
delattr
舉例:屬性訪問時的嚴重問題,無限遞歸
class Rectangle: ?#矩形
? ? def __init__(self, width=0, height=0): ?#寬高不相等,長方形
? ? ? ? self.width = width
? ? ? ? self.height = height
? ? def __setattr__(self, name, value):
? ? ? ? if name == 'square': ?#寬高相等,正方形
? ? ? ? ? ? self.width = value
? ? ? ? ? ? self.height = value
? ? ? ? else:
? ? ? ? ? ? #self.name = value ? #會導致類無限遞歸自己
? ? ? ? ? ? super().__setattr__(name, value) ?#解決辦法①:super() 推薦。
? ? ? ? ? ? #self.__dict__[name] = value ? ? ?#解決辦法②:字典
? ? def getArea(self):
? ? ? ? return self.width * self.height
運行:
>>> r1 = Rectangle(4, 5)
>>> r1.getArea()
20
>>> r1.square = 10 ?#正方形
>>> r1.width
10
>>> r1.height
10
>>> r1.getArea()
100
>>> r1.__dict__ ?#以字典的形式查看類中的屬性和值
{'width': 10, 'height': 10}
--------------------------------2017.09.03----------------------------------------
描述符 decriptor
描述符就是將某種特殊類型的類的實例指派給另一個類的屬性。
__get__(self, instance, owner) ?#用于訪問屬性,返回屬性的值
__set__(self, instance, value) ?#將在屬性分配操作中調用,不反悔任何內容
__delete__(self, instance) ? ?#控制刪除操作,不返回任何內容
@self, 描述符類本身的類實例
@instance, 擁有者的類實例
@owner, 擁有者類本身
@value, 所賦的值
舉例:
>>> class MyDecriptor:
def __get__(self, instance, owner):
print('getting: ', self, instance, owner)
def __set__(self, instance, value):
print('setting: ', self, instance, value)
def __delete__(self, instance):
print('deleting: ', self, instance)
>>> class Test:
x = MyDecriptor()
>>> #MyDecriptor是x的描述符類
>>> test = Test() ? #實例化Test()類
>>> test.x
getting: ?<__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28> <class '__main__.Test'>
>>> test
<__main__.Test object at 0x000002164DBB6F28>
>>> test.x = 'X-man'
setting: ?<__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28> X-man
>>> del test.x
deleting: ?<__main__.MyDecriptor object at 0x000002164DC31FD0> <__main__.Test object at 0x000002164DBB6F28>
自定義的描述符
>>> class MyProperty:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, owner):
return self.fget(instance) ?#instance擁有者的實例對象
def __set__(self, instance, value):
self.fset(instance, value)
def __delete__(self, instance):
self.fdel(instance)
>>> class C:
def __init__(self):
self._x = None
def getX(self):
return self._x
def setX(self, value):
self._x = value
def delX(self):
del self._x
x = MyProperty(getX, setX, delX)
>>> c = C()
>>> c.x = 'X-man'
>>> c.x
'X-man' ?#使用x影響_x的值
>>> c._x
'X-man'
>>> del c.x ?#刪除后,c.x和c._x都不存在
練習:溫度轉換
定義一個溫度類,然后定義兩個描述符類用于描述攝氏度和華氏度兩個屬性。
要求兩個屬性會自動進行轉換,也就是說可以給攝氏度這個屬性賦值,打印華氏度是自動轉換后的結果。
代碼:
class Celsius:
? ? def __init__(self, value = 26.0):
? ? ? ? self.value = float(value)
? ? def __get__(self, instance, owner):
? ? ? ? return self.value
? ? def __set__(self, instance, value):
? ? ? ? self.value = float(value)
class Fahrenheit:
? ? def __get__(self, instance, owner): ?#instance就是Temperature(屬性:cel, fah)
? ? ? ? return instance.cel * 1.8 + 32
? ? def __set__(self, instance, value):
? ? ? ? #instance.cel = ('%.1f' % ((float(value) - 32) / 1.8)) ?#控制精度方法1
? ? ? ? instance.cel = round((float(value) - 32) / 1.8, 1) ? ? ?#控制精度方法2
class Temperature:
? ? cel = Celsius() ?#攝氏度
? ? fah = Fahrenheit() ?#華氏度, fah在實例對象中被賦值時調用對應類的__set__
運行:
>>> temp = Temperature()
>>> temp.cel
26.0
>>> temp.cel = 30
>>> temp.fah
86.0
>>> temp.fah = 100
>>> temp.cel
37.8
定制序列(容器)
(1) 如果希望定制的容器不可變,只需要定義魔法方法__len__()和__getitem__()
(2) 如果希望定制的容器可變,需要定義__len__()和__getitem__()和__setitem__()和__delitem__()
魔法方法詳解:
http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
練習:
編寫一個不可改變的自定義列表,要求記錄列表中每個元素被訪問的次數。
class CountList:
? ? def __init__(self, *args): ?#*args, 參數數量可變
? ? ? ? self.values = [x for x in args]
? ? ? ? self.count = {}.fromkeys(range(len(self.values)), 0)
? ? def __len__(self):
? ? ? ? return len(self.values)
? ? def __getitem__(self, key):
? ? ? ? self.count[key] += 1
? ? ? ? return self.values[key]
運行:
>>> c1 = CountList(1, 3, 5, 7, 9)
>>> c2 = CountList(2, 4, 6, 7, 10)
>>> c1[1] ?#c1[1] == 3被訪問1次
3
>>> c2[1]
4
>>> c1[1] + c2[1] ?#c1[1] == 3被訪問2次
7
>>> c1.count
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
>>> c1[1] ?#c1[1] == 3被訪問3次
3
>>> c1.count
{0: 0, 1: 3, 2: 0, 3: 0, 4: 0}
迭代器 iter-next
iter
iter() 內置方法, 功能:返回一個迭代器對象
__iter__() 魔法方法
next
next() 內置方法
__next__() ?魔法方法
for循環迭代器:
>>> links = {'百度':'http://www.baidu.com', \
'谷歌':'http://www.google.com', \
'搜狗':'http://www.sougou.com', \
'騰訊':'http://www.qq.com'}
>>> for each in links:
print("%s -> %s" % (each, links[each]))
谷歌 -> http://www.google.com
搜狗 -> http://www.sougou.com
騰訊 -> http://www.qq.com
百度 -> http://www.baidu.com
iter迭代器:
>>> string = 'yuan.jiang'
>>> it = iter(string)
>>> while True:
try:
each = next(it)
except StopIteration:
break;
print(each, end=' ')
運行:
y u a n . j i a n g?
斐波那契數列迭代器
>>> class Fibs: ?#斐波那契數列
def __init__(self, n=10): ? ?#加一個參數n控制迭代范圍
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self ?#本身就是一個迭代器
def __next__(self):
self.a, self.b = self.b, self.a+self.b
if self.a > self.n:
raise StopIteration
return self.a
>>> fibs = Fibs()
>>> for each in fibs:
print(each, end=' ')
1 1 2 3 5 8
>>> fibs = Fibs(100)
>>> for each in fibs:
print(each, end=' ')
1 1 2 3 5 8 13 21 34 55 89
生成器 yield
(1) 生成器是一種特殊的迭代器,兼容next()內置方法
(2) 生成器模仿了協同程序
協同程序:可以運行的對立函數調用,函數可以暫停或掛起,并再需要的時候從程序離開的地方繼續活著重新開始。
舉例:
>>> def MyGen():
print('生成器被執行!')
yield 1
yield 2
>>> myg = MyGen()
>>> next(myg)
生成器被執行!
1
>>> next(myg)
2
>>> next(myg)
StopIteration
>>> for i in MyGen(): ?#for循環自動檢測迭代器的StopIteration異常
print(i)
生成器被執行!
1
2
>>> def fibs():
a = 0
b = 1
while True:
a, b = b, a+b
yield a
>>> for each in fibs():
if each > 100:
break
print(each, end=' ')
1 1 2 3 5 8 13 21 34 55 89?
列表推導式
>>> a = [i for i in range(100) if not (i % 2) and (i % 3)] ?#列表推導式
>>> a
[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]
>>> b = {i:i % 2 == 0 for i in range(10)} ?#字典推導式(例子:小于10以內的偶數)
>>> b
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}
>>> c = {i for i in [1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 3, 2, 1]} ?#集合推導式(元素不重復)
>>> c
{1, 2, 3, 4, 5, 6, 7, 8}
#沒有字符串推導式,引號內的強制解釋為字符串
>>> e = (i for i in range(10)) ?#沒有元組推導式,()小括號生成的是生成器推導式
>>> e
<generator object <genexpr> at 0x00000261E200A7D8>
>>> next(e)
0
>>> next(e)
1
>>> for each in e:
print(each, end=' ')
2 3 4 5 6 7 8 9?
>>> sum(i for i in range(100) if i % 2)
2500
生成器擴展閱讀:
http://bbs.fishc.com/forum.php?mod=viewthread&tid=56023&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
21丶模塊 module
容器 -> 數據的封裝
函數 -> 語句的封裝
類 ? -> 方法和屬性的封裝
模塊 -> 程序的封裝,其實就是.py的python程序
(1) import導入的.py模塊文件必須放在與python.exe同一目錄下,即可正確導入。
(2) 導入方法有三種:
① import 模塊名
② from 模塊名 import 函數名1, 函數名2, ... ?#不建議這樣用,可能會覆蓋系統函數
③ import 模塊名 as 新名字
舉例:
在python下新建test_module文件夾:C:\python\test_module
C:\python\test_module\TempeatureConversion.py
C:\python\test_module\calc.py
#TempeatureConversion.py
def c2f(cel):
? ? fah = cel * 1.8 + 32
? ? return fah
def f2c(fah):
? ? cel = round((fah - 32) / 1.8, 1)
? ? return cel
#calc.py
import TemperatureConversion as tc
print('32攝氏度 = %.1f華氏度' % tc.c2f(32))
print('99華氏度 = %.1f攝氏度' % tc.f2c(99))
運行calc.py:
=================== RESTART: C:\python\test_module\calc.py ===================
32攝氏度 = 89.6華氏度
99華氏度 = 37.2攝氏度
>>>?
__name__
if __name__ = '__main__': ?#決定是.py文件中的代碼是當前程序運行,還是導入到其他程序中作為模塊使用而運行
作用:限制為自身.py程序運行才執行的代碼區域
搜索路徑 path
(1) 最佳存放模塊的目錄:C:\\python\\lib\\site-packages
>>> import sys
>>> sys.path
['', 'C:\\python\\Lib\\idlelib', 'C:\\python\\python35.zip', 'C:\\python\\DLLs', 'C:\\python\\lib', 'C:\\python', 'C:\\python\\lib\\site-packages']
>>> sys.path.append('C:\\python\\test_module') ?#自定義的模塊目錄可以append進去
>>> sys.path
['', 'C:\\python\\Lib\\idlelib', 'C:\\python\\python35.zip', 'C:\\python\\DLLs', 'C:\\python\\lib', 'C:\\python', 'C:\\python\\lib\\site-packages', 'C:\\python\\test_module']
>>> import TemperatureConversion as temp
>>> temp.c2f(32)
89.6
包 package
(1) python目錄下創建一個文件夾,用于存放相關的模塊,文件夾的名字即包(package)的名字
(2) 在文件夾中創建一個 __init__.py 的模塊文件,內容可以為空
舉例:
C:\python\test_module\calc.py
C:\python\test_module\M1\TemperatureConversion.py ?#M1文件夾名,即為包名
C:\python\test_module\M1\__init__.py ?#告訴python運行時將其解釋為包
#calc.py中修改為:包名.模塊名
import M1.TemperatureConversion as tc
print('32攝氏度 = %.1f華氏度' % tc.c2f(32))
print('99華氏度 = %.1f攝氏度' % tc.f2c(99))
自帶電池:python標準庫
(1) 電池:python-IDLE 幫助文檔 F1
(2) 來自全球開發者貢獻的python模塊:https://pypi.python.org/pypi
#也可以自己寫模塊發布上去。
(3) PEP:python增強建議書,規范與定義python各種加強和延伸功能的技術規格,即參考標準
(4) PEP規范內容歷史:http://www.python.org/dev/peps
(5) IDLE中模塊信息查看:
>>> import timeit
>>> print(timeit.__doc__) ?#幫助文檔
>>> dir(timeit) ?#內置方法
>>> timeit.__all__ ?#__all__屬性是可供外界調用的類或接口函數
>>> timeit.__file__ ?#__file__屬性是顯示模塊源代碼在本地的位置(學習高手的代碼)
>>> help(timeit) ?#幫助文檔
timeit 模塊詳解
地址:http://bbs.fishc.com/thread-55593-1-1.html
22丶python實例:網絡爬蟲
python訪問網絡: urllib (是個包模塊)
URL一般格式:
protocol://hostname[:port]/path/[;parameters][?query]#fragment
URL三部分組成:
(1) 協議:http, https, ftp, file, ed2k...
(2) 域名/IP地址:如http默認端口號80
(3) 資源具體地址:如目錄或文件名
查看幫助文檔后發現urllib包有4個模塊:
urllib.request #for opening and reading URLs?
urllib.error #containing the exceptions raised by urllib.request?
urllib.parse #for parsing URLs?
urllib.robotparser #for parsing robots.txt files?
嘗鮮:
>>> import urllib.request
>>> response = urllib.request.urlopen('http://www.fishc.com')
>>> html = response.read()
>>> print(html)
b'\xef...\r\n</html>\r\n' ?#整個網頁的二進制文件以16進制顯示
>>> html = html.decode('utf-8') ?#按其編碼方式解碼
>>> print(html)
"""
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
</body>
</html>
"""
訪問網頁內容存儲本地
舉例:
import urllib.request as url_req
response = url_req.urlopen('http://placekitten.com/g/1920/1080')
cat_img = response.read()
with open('cat_1920_1080.jpg', 'wb') as f:
? ? f.write(cat_img)
運行:
會生成這個文件:C:\Users\Jan\Desktop\python_study\cat_1920_1080.jpg
實現POST請求 - 自動翻譯機
import urllib.request as url_req
import urllib.parse ? as url_prs
import json ?#json, 輕量級的數據交換格式
while True:
? ? content = input('請輸入需要翻譯的內容<.q退出>:')
? ? if content == '.q':
? ? ? ? break
? ? else:
? ? ? ? #注意url地址<有道翻譯>,按小甲魚視頻中的可能不對,需到網上查別人的
? ? ? ? url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=http://www.youdao.com/'
? ? ? ? data = {} ? #字典類型
? ? ? ? data['type'] = 'AUTO'
? ? ? ? data['i'] = content
? ? ? ? data['doctype'] = 'json'
? ? ? ? data['xmlVersion'] = '1.8'
? ? ? ? data['keyfrom'] = 'fanyi.web'
? ? ? ? data['ue'] = 'UTF-8'
? ? ? ? data['action'] = 'FY_BY_CLICKBUTTON'
? ? ? ? data['typoResult'] = 'true'
? ? ? ? data = url_prs.urlencode(data).encode('utf-8')
? ? ? ? response = url_req.urlopen(url, data)
? ? ? ? html = response.read().decode('utf-8')
? ? ? ? target = json.loads(html)
? ? ? ? print('翻譯結果:%s' % (target['translateResult'][0][0]['tgt']))
#缺陷:能夠被識別為代碼訪問,而非瀏覽器,即非人類訪問
運行:
========= RESTART: C:\Users\Jan\Desktop\python_study\translation.py =========
請輸入需要翻譯的內容<.q退出>:生存,還是毀滅,這是一個問題
翻譯結果:To survive, or not to be, this is a problem
請輸入需要翻譯的內容<.q退出>:To be or not to be, it's a question.
翻譯結果:生存還是毀滅,這是一個問題。
請輸入需要翻譯的內容<.q退出>:.q
>>>?
修改header
(1) 通過Request的headers參數修改,字典形式
(2) 通過Request.add_header()方法修改
追加header模擬瀏覽器訪問:
import urllib.request as url_req
import urllib.parse ? as url_prs
import json ?#json, 輕量級的數據交換格式
while True:
? ? content = input('請輸入需要翻譯的內容<.q退出>:')
? ? if content == '.q':
? ? ? ? break
? ? else:
? ? ? ? #注意url地址,視頻中的可能不對需到網上查
? ? ? ? url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=http://www.youdao.com/'
? ? ? ? #header方法1:創建字典,請求中傳參
? ? ? ? '''
? ? ? ? head = {} ?#模擬瀏覽器訪問 Request Headers
? ? ? ? head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
? ? ? ? '''
? ? ? ? data = {} ?#From data
? ? ? ? data['type'] = 'AUTO'
? ? ? ? data['i'] = content
? ? ? ? data['doctype'] = 'json'
? ? ? ? data['xmlVersion'] = '1.8'
? ? ? ? data['keyfrom'] = 'fanyi.web'
? ? ? ? data['ue'] = 'UTF-8'
? ? ? ? data['action'] = 'FY_BY_CLICKBUTTON'
? ? ? ? data['typoResult'] = 'true'
? ? ? ? data = url_prs.urlencode(data).encode('utf-8')
? ? ? ? '''req = url_req.Request(url, data, head) ?#調用請求的方法:data, head '''
? ? ? ? #header方法2:請求中追加header
? ? ? ? req = url_req.Request(url, data)
? ? ? ? req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36')
? ? ? ? response = url_req.urlopen(req)
? ? ? ? html = response.read().decode('utf-8')
? ? ? ? target = json.loads(html)
? ? ? ? print('翻譯結果:%s' % (target['translateResult'][0][0]['tgt']))
運行:
========= RESTART: C:\Users\Jan\Desktop\python_study\translation.py =========
請輸入需要翻譯的內容<.q退出>:生存,還是毀滅,這是一個問題
翻譯結果:To survive, or not to be, this is a problem
請輸入需要翻譯的內容<.q退出>:To be or not to be, it's a question.
翻譯結果:生存還是毀滅,這是一個問題。
請輸入需要翻譯的內容<.q退出>:.q
>>>?
代理
作用:讓爬蟲偽裝瀏覽器請求,讓http服務器不會認為是非人類訪問。
步驟:
(1) 參數是一個字典{'類型':'代理ip:端口號'}
proxy_support = urllib.request.ProxyHandler({})
(2) 定制、創建一個opener
opener = urllib.request.build_opener(proxy_support)
(3) 安裝opener
urllib.request.install_opener(opener)
(4) 調用opener
opener.open(url)
#或:urllib.request.urlopen(url)
代碼:
import urllib.request as url_req
import random
url = 'http://www.whatismyip.com.tw' ?#這個網站訪問它會顯示自己的ip地址
#待完善:抓取代理ip網站上的ip和端口,存入iplist
iplist = ['115.197.136.78:8118', '118.250.50.69:80', '183.133.81.57:8118', ?'113.77.240.236:9797', '139.129.166.68:3128'] ?#使用random隨機取ip
#網上查的免費代理ip網站:http://www.xicidaili.com/
proxy_support = url_req.ProxyHandler({'http':random.choice(iplist)})
opener = url_req.build_opener(proxy_support)
#headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
opener.addheaders = [('User-Agent', 'Chrome/55.0.2883.87')]
url_req.install_opener(opener)
#req = url_req.Request(url, headers=headers)
#response = url_req.urlopen(req)
response = url_req.urlopen(url)
html = response.read().decode('utf-8')
print(html)
補充:
Beautiful Soup 是用Python寫的一個HTML/XML的解析器,使用安裝python-IDLE時附帶的pip命令,直接在windows下執行:
C:\python> pip install bs4
#一鍵安裝搞定,python中測試能否導入成功
>>> from bs4 import BeautifulSoup
>>> #成功導入,失敗會報異常。
采集代理ip
import urllib.request as url_req
from bs4 import BeautifulSoup ?#此庫需要安裝:win-cmd執行"pip install bs4"即可
import random
import pprint as ppr
#這個網站訪問它會顯示自己的ip地址
display_ip_url = 'http://www.whatismyip.com.tw' ? #'http://ip.chinaz.com/getip.aspx'
#代理ip網站, http協議類型
proxy_ip_url = 'http://www.xicidaili.com/wt/'
header = {}
header['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
def getProxyIp(): ?#獲取代理ip
? ? proxyip_list = []
? ? for i in range(1, 2):
? ? ? ? try:
? ? ? ? ? ? url = proxy_ip_url + str(i) ?#抓取前2頁
? ? ? ? ? ? req = url_req.Request(url, headers=header)
? ? ? ? ? ? res = url_req.urlopen(req).read()
? ? ? ? ? ? soup = BeautifulSoup(res, "html.parser") ?#BeautifulSoup(markup, “html.parser”) html解析器
? ? ? ? ? ? ips = soup.findAll('tr') ?#findAll()搜索解析器解析出來的html文檔樹
? ? ? ? ? ? for x in range(1, len(ips)):
? ? ? ? ? ? ? ? ip = ips[x]
? ? ? ? ? ? ? ? tds = ip.findAll('td') ?#ip和端口都在tr標簽中的td標簽中
? ? ? ? ? ? ? ? ip_tmp = tds[1].contents[0] + ':' + tds[2].contents[0]
? ? ? ? ? ? ? ? proxyip_list.append(ip_tmp) ?#追加到列表
? ? ? ? except:
? ? ? ? ? ? continue
? ? return proxyip_list
iplist = getProxyIp()
#print(iplist) ? #for test
ppr.pprint(iplist) ?#以更規范的格式顯示輸出結果
#第一步:ProxyHandler傳參
ip_port = random.choice(iplist)
proxy_support = url_req.ProxyHandler({'http':ip_port}) ?#從列表中隨機選擇代理ip和端口項
print('ip:port ? ?' + ip_port)
#第二步:opener創建
opener = url_req.build_opener(proxy_support)
#第三步:opener安裝
opener.addheaders = [('User-Agent', 'Chrome/55.0.2883.87')]
url_req.install_opener(opener)
#第四步:opener調用
#response = url_req.urlopen(display_ip_url)
response = opener.open(display_ip_url) ?
html = response.read().decode('utf-8')
print(html)
運行:
======== RESTART: C:\Users\Jan\Desktop\python_study\proxy_support.py ========
<!DOCTYPE HTML>
<html>
? <head>
? ...
? </head>
? <body>
? <h1>IP位址</h1>
? <span data-ip='183.56.177.130'><b style='font-size: 1.5em;'>183.56.177.130</b> ?</span>
? <span data-ip-country='CN'><i>CN</i></span>
? <h1>真實IP</h1>
? <span data-ip-real='113.110.143.94'><b style='font-size: 1.5em;'>113.110.143.94</b></span>
? <span data-ip-real-country='CN'><i>CN</i></span>
? <script type="application/json" id="ip-json">
{
"ip": "183.56.177.130",
"ip-country": "CN",
"ip-real": "113.110.143.94",
"ip-real-country": "CN"
}
? </script>
? ...
? </body>
</html>
--------------------------------2017.09.04----------------------------------------
urllib.request 返回響應后的內置方法
import urllib.request as url_req
req = url_req.Request('http://url')
res = url_req.urlopen(req) #打開一個鏈接,參數可以是一個字符串或者Request對象
res.geturl() #返回鏈接的字符串,即urlopen的字符串參數
res.info() #返回http響應數據包的頭headers, 輸出:print(res.info())
res.getcode() #返回http響應的狀態碼
舉例:
=============== RESTART: C:/Users/Jan/Desktop/download_cat.py ===============
>>> res.geturl()
'http://placekitten.com/g/500/600'
>>> res.info()
<http.client.HTTPMessage object at 0x0000022E09C006D8>
>>> res.headers
<http.client.HTTPMessage object at 0x0000022E09C006D8>
>>> print(res.info())
Date: Mon, 04 Sep 2017 13:11:21 GMT
Content-Type: image/jpeg
Content-Length: 26590
Connection: close
Set-Cookie: __cfduid=d8354310653b8846db674de048175187b1504530681; expires=Tue, 04-Sep-18 13:11:21 GMT; path=/; domain=.placekitten.com; HttpOnly
Accept-Ranges: bytes
X-Powered-By: PleskLin
Access-Control-Allow-Origin: *
Cache-Control: public
Expires: Thu, 31 Dec 2020 20:00:00 GMT
Server: cloudflare-nginx
CF-RAY: 399131b5435b6d4e-SJC
>>> res.getcode()
200
python爬蟲下載妹子圖
代碼:#代理ip不太穩定,免費代理很多時好時壞
import urllib.request
import os
import random
import pprint as ppr
from bs4 import BeautifulSoup
header = {}
header_key = 'User-Agent'
header_value = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
header[header_key] = header_value
def get_proxy_ip(): ?#獲取代理ip
? ? proxyip_list = []
? ? proxy_ip_url = 'http://www.xicidaili.com/wt/'
? ? for i in range(1, 2):
? ? ? ? try:
? ? ? ? ? ? url = proxy_ip_url + str(i)
? ? ? ? ? ? req = urllib.request.Request(url, headers=header)
? ? ? ? ? ? res = urllib.request.urlopen(req).read()
? ? ? ? ? ? soup = BeautifulSoup(res, "html.parser")
? ? ? ? ? ? ips = soup.findAll('tr')
? ? ? ? ? ? for x in range(1, len(ips)):
? ? ? ? ? ? ? ? ip = ips[x]
? ? ? ? ? ? ? ? tds = ip.findAll('td')
? ? ? ? ? ? ? ? ip_tmp = tds[1].contents[0] + ':' + tds[2].contents[0]
? ? ? ? ? ? ? ? proxyip_list.append(ip_tmp)
? ? ? ? except:
? ? ? ? ? ? continue
? ? return proxyip_list
#打開url接口函數
def url_open(url):
? ? req = urllib.request.Request(url)
? ? req.add_header(header_key, header_value)
? ? '''
? ? #使用代理模擬真人訪問而不是代碼訪問
? ? iplist = get_proxy_ip()
? ? #ppr.pprint(iplist) ?#for test
? ? ip_port = random.choice(iplist)
? ? proxy_support = urllib.request.ProxyHandler({'http':ip_port})
? ? print('ip:port ? ?' + ip_port) ?#for test
? ? opener = urllib.request.build_opener(proxy_support)
? ? opener.addheaders = [('User-Agent', 'Chrome/55.0.2883.87')]
? ? urllib.request.install_opener(opener)
? ? '''
? ? res = urllib.request.urlopen(url)
? ? html = res.read()
? ? print(url)
? ? return html
def get_page(url):
? ? html = url_open(url).decode('utf-8')
? ? a = html.find('current-comment-page') + 23
? ? b = html.find(']', a) ?#從a位置開始找到一個]符號
? ? print (html[a:b]) ?#for test
? ? return html[a:b]
def find_imgs(url):
? ? html = url_open(url).decode('utf-8')
? ? img_addrs = []
? ? a = html.find('img src=') ?#找到 img src= 的位置
? ? while a != -1:
? ? ? ? b = html.find('.jpg', a, a+255) ? #找到從a位置開始,以 .jpg 結尾的地方
? ? ? ? if b != -1: ?#find找不到時返回-1
? ? ? ? ? ? img_addrs.append('http:' + html[a+9:b+4]) ?#圖片鏈接地址追加到列表中, 9=len('img src="'), 4=len('.jpg')
? ? ? ? else:
? ? ? ? ? ? b = a + 9
? ? ? ??
? ? ? ? a = html.find('img src=', b) ? ? ?#下一次循環所找的位置就是從b開始
? ? #for each in img_addrs:
? ? # ? ?print(each)
? ? return img_addrs
def save_imgs(folder, img_addrs):
? ? for each in img_addrs:
? ? ? ? filename = each.split('/')[-1] ?#split以/分割字符串,-1取最后一個元素
? ? ? ? with open(filename, 'wb') as f:
? ? ? ? ? ? img = url_open(each)
? ? ? ? ? ? f.write(img)
def download_mm(folder='mm_dir', pages=25):
? ? if os.path.exists(folder):
? ? ? ? os.chdir(folder)
? ? else:
? ? ? ? os.mkdir(folder)
? ? ? ? os.chdir(folder)
? ? url = 'http://jandan.net/ooxx/' ?#實際圖源來源于新浪服務器
? ? page_num = int(get_page(url)) ? ?#函數get_page()
? ? for i in range(pages):
? ? ? ? page_num -= i
? ? ? ? page_url = url + 'page-' + str(page_num) + '#comments'
? ? ? ? img_addrs = find_imgs(page_url) ?#函數find_imgs()
? ? ? ? save_imgs(folder, img_addrs)
if __name__ == '__main__':
? ? download_mm()
--------------------------------2017.09.05----------------------------------------
正則表達式
"我知道,可以使用正則表達式解決現在遇到的難題。"于是,現在他就有兩個問題了。
>>> import re
>>> re.search(r'Hello', 'I love you, Hello!~') ?#search()方法用于在字符串中搜索正則表達式模式第一次出現的位置
<_sre.SRE_Match object; span=(12, 17), match='Hello'> ?#第12-16個字符位置
>>> re.search(r'lo', 'hello')
<_sre.SRE_Match object; span=(3, 5), match='lo'>
>>> 'hello'.find('lo')
3
#.點號:匹配除了換行符的任何字符
>>> re.search(r'.', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(0, 1), match='I'>
#匹配點號本身,使用\反斜杠轉義即可
>>> re.search(r'\.', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(17, 18), match='.'>
#\d表示匹配一個0~9的數字
>>> re.search(r'\d', 'I love 123, baidu.com!~')
<_sre.SRE_Match object; span=(7, 8), match='1'>
>>> re.search(r'\d\d\d', 'I love 123, baidu.com!~')
<_sre.SRE_Match object; span=(7, 10), match='123'>
>>> re.search(r'\d\d\d.\d\d\d.\d\d\d.\d\d\d', '192.168.111.123:8080')
<_sre.SRE_Match object; span=(0, 15), match='192.168.111.123'>
>>> re.search(r'\d\d\d.\d\d\d.\d\d\d.\d\d\d', '192.168.1.1') #無法匹配,位數不同
#使用[]創建一個字符類
>>> re.search(r'[aeiou]', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(3, 4), match='o'>
>>> re.search(r'[aeiouAEIOU]', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(0, 1), match='I'>
#-短杠:表示匹配的范圍
>>> re.search(r'[a-z]', 'I love you, baidu.com!~')
<_sre.SRE_Match object; span=(2, 3), match='l'>
>>> re.search(r'[0-9]', 'I love 123, baidu.com!~')
<_sre.SRE_Match object; span=(7, 8), match='1'>
#{}大括號:來限定匹配的次數
>>> re.search(r'ab{3}c', 'zabbbcz')
<_sre.SRE_Match object; span=(1, 6), match='abbbc'>
#{}3,10代表3到10次重復次數,不能有空格出現
>>> re.search(r'ab{3, 10}c', 'zabbbbbcz')
>>> re.search(r'ab{3,10}c', 'zabbbbbcz')
<_sre.SRE_Match object; span=(1, 8), match='abbbbbc'>
>>> re.search(r'[0-2][0-5][0-5]', '188') ?#錯誤示范
>>> re.search(r'[0-255]', '188') ?#0,1,2,5其中任何一個,匹配
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.search(r'[01]\d\d|2[0-4]\d|25[0-5]', '188') ?#0-255正則表達式
<_sre.SRE_Match object; span=(0, 3), match='188'>
#ip地址正則表達式
>>> re.search(r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])', '192.168.1.1')
<_sre.SRE_Match object; span=(0, 11), match='192.168.1.1'>
>>> re.search(r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])', '255.255.255.0')
<_sre.SRE_Match object; span=(0, 13), match='255.255.255.0'>
#此ip表達式的一點bug:
>>> re.search(r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])', '11192.168.41.8888')
<_sre.SRE_Match object; span=(2, 15), match='192.168.41.88'>
#ip地址匹配的正則表達式【嚴謹版】
import re
ptnIP = re.compile(r'(?<![\d.])' # 前導 無 數字和小數點
? ? ? ? ? ? ? ? ? ?r'(?:(?:'
? ? ? ? ? ? ? ? ? ?r'[01]?\d?\d' # ? 0 ~ 199
? ? ? ? ? ? ? ? ? ?r'|2[0-4]\d' ?# 200 ~ 249
? ? ? ? ? ? ? ? ? ?r'|25[0-5])' ?# 250 ~ 255
? ? ? ? ? ? ? ? ? ?r'\.){3}' ? ? # 3組 xxx.
? ? ? ? ? ? ? ? ? ?r'(?:'
? ? ? ? ? ? ? ? ? ?r'[01]?\d?\d'
? ? ? ? ? ? ? ? ? ?r'|2[0-4]\d'
? ? ? ? ? ? ? ? ? ?r'|25[0-5])'
? ? ? ? ? ? ? ? ? ?r'(?![\d.])' ?# 后續 無 數字和小數點
? ? ? ? ? ? ? ? ? )
test_IP = (
? ? ? ? '0.0.0.0'
? ? ? ? ';1.22.333.444' ? ? ? ? #不合法
? ? ? ? ';2.0.0.256' ? ? ? ? ? ?#不合法
? ? ? ? ';3.22.33.23333333' ? ? #不合法
? ? ? ? ';4.2.3.4.5' ? ? ? ? ? ?#不合法
? ? ? ? ';5.111.222.99'
? ? ? ? ';6.0.0.0'
? ? ? ? ';7.234.234.234'
? ? ? ? ';255.255.255.255'
? ? ? ? ';234.234.234.234'
? ? ? ? ';1192.168.41.888' ? ? ?#不合法
? ? ? ? )
match = ptnIP.findall(test_IP)
print(match)
運行:
========== RESTART: C:\Users\Jan\Desktop\python_study\ip_regular.py ==========
['0.0.0.0', '5.111.222.99', '6.0.0.0', '7.234.234.234', '255.255.255.255', '234.234.234.234'] ?#輸出均為合法ip
--------------------------------2017.09.07----------------------------------------
Python3 正則表達式特殊符號及用法(詳細列表)
http://blog.csdn.net/riba2534/article/details/54288552
正則表達式舉例:
import urllib.request
import re
header = {}
header_key = 'User-Agent'
header_value = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
header[header_key] = header_value
def open_url(url):
? ? req = urllib.request.Request(url)
? ? req.add_header(header_key, header_value)
? ? page = urllib.request.urlopen(req)
? ? html = page.read().decode('utf-8')
? ? return html
def get_img(html):
? ? p = r'<img class="BDE_Image" src="([^"]+\.jpg)' ?# 正則表達式匹配貼吧圖片鏈接
? ? imglist = re.findall(p, html) ?# findall中的p包含子組()的話,會單獨返回子組
? ? # test start
? ? for each in imglist:
? ? ? ? print(each)
? ? # test end
? ? for each in imglist:
? ? ? ? filename = each.split("/")[-1]
? ? ? ? urllib.request.urlretrieve(each, filename, None)
if __name__ == '__main__':
? ? url = 'https://tieba.baidu.com/p/5310571187' ?# 下載百度貼吧圖片示例
? ? get_img(open_url(url))
運行:
https://imgsa.baidu.com/forum/w%3D580/sign=0b340d2849a7d933bfa8e47b9d4ad194/f1f8e3dde71190ef7241a5e3c51b9d16fcfa60a4.jpg
https://imgsa.baidu.com/forum/w%3D580/sign=6ff2514ff0f2b211e42e8546fa816511/fe4fbf014a90f6030c47ab7b3212b31bb151ed60.jpg
https://imgsa.baidu.com/forum/w%3D580/sign=7f8aadd5f9d3572c66e29cd4ba136352/b9dc748b4710b912bda70cc2c8fdfc03934522f1.jpg
優化采集代理ip:
import urllib.request
import re
header = {}
header_key = 'User-Agent'
header_value = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
header[header_key] = header_value
def open_url(url):
? ? req = urllib.request.Request(url)
? ? req.add_header(header_key, header_value)
? ? page = urllib.request.urlopen(req)
? ? html = page.read().decode('utf-8')
? ? return html
def get_ip(html):
? ? ptnIP = (r'(?<![\d.])' # 前導 無 數字和小數點
? ? ? ? ? ? ?r'(?:(?:'
? ? ? ? ? ? ?r'[01]?\d?\d' # ? 0 ~ 199
? ? ? ? ? ? ?r'|2[0-4]\d' ?# 200 ~ 249
? ? ? ? ? ? ?r'|25[0-5])' ?# 250 ~ 255
? ? ? ? ? ? ?r'\.){3}' ? ? # 3組 xxx.
? ? ? ? ? ? ?r'(?:'
? ? ? ? ? ? ?r'[01]?\d?\d'
? ? ? ? ? ? ?r'|2[0-4]\d'
? ? ? ? ? ? ?r'|25[0-5])'
? ? ? ? ? ? ?r'(?![\d.])') # 后續 無 數字和小數點
? ? iplist = re.findall(ptnIP, html) ?# findall中的p包含子組()的話,會單獨返回子組
? ? # test start
? ? for each in iplist:
? ? ? ? print(each)
? ? # test end
if __name__ == '__main__':
? ? url = 'http://www.xicidaili.com/wt/' ?# 下載代理ip
? ? get_ip(open_url(url))
異常處理
URLError 舉例:
>>> import urllib.request
>>> import urllib.error
>>> req = urllib.request.Request('http://www.ooxx-hello.com') ?#打開一個不存在的鏈接
>>> try:
urllib.request.urlopen(req)
except urllib.error.URLError as e:
print(e.reason)
[Errno 11001] getaddrinfo failed ?#錯誤信息
HTTPError 舉例:
>>> import urllib.request
>>> import urllib.error
>>> req = urllib.request.Request('http://www.fishC.com/ooxx.html')
>>> try:
urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
print(e.code)
print(e.read())
404
b'<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested URL /ooxx.html was not found on this server.</p>\n<hr>\n<address>Apache Server at www.fishc.com Port 80</address>\n</body></html>\n'
處理異常的寫法:
from urllib.request import Request, urlopen
from urllib.error import URLError
req = Request('http://someurl/')
try:
response = urlopen(req)
except URLError as e:
if hasattr(e, 'reason'):
print('We failed to reach a server.')
print('Reason: ', e.reason)
elif hasattr(e, 'code'):
print('The server couldn\'t fulfill the request.')
print('Error code: ', e.code)
else:
#everything is fine.
--------------------------------2017.09.08----------------------------------------
Scrapy爬蟲框架
① Scrapy的安裝與環境搭建
Scrapy對應python2.7的版本。(安裝過程中如遇任何問題均可百度搜索一下,這是程序員必須學會的快速解決問題的辦法)
1. 安裝python2.7(32位版本)
安裝包:python-2.7.6-win32.msi
設置環境變量:win-運行-cmd
> C:\Python27\python.exe C:\Python27\tools\Scripts\win_add2path.py
重啟windows系統,驗證安裝是否成功:
> python --version
#如果顯示是3.多的版本,請參考python2/3版本切換任性切換設置:http://blog.csdn.net/sinat_36184075/article/details/77872708
2. 安裝pywin32(32位版本)
安裝包:pywin32-215.win32-py2.7.exe
3. 安裝python2.7的pip程序
安裝程序:get-pip.py
安裝方法:win-cmd> python C:\python\Scrapy\get-pip.py
先把pip的路徑添加到windows的環境變量中。
重啟windows系統,驗證安裝是否成功:
> pip --version
#如果沒有顯示版本信息,請參考pip2/3任性切換設置:http://blog.csdn.net/sinat_36184075/article/details/77872708
4. 安裝lxml
安裝環境包:VCForPython27.msi
> pip2 install lxml
#如果pip2的路徑有添加到windows中的話,安裝可以成功。如果不成功,使用下面安裝包安裝
安裝包:lxml-3.2.3.win32-py2.7.exe
5. 安裝OpenSSL
> pip2 install pyOpenSSL
#如果pip2的路徑有添加到windows中的話,安裝可以成功。如果不成功,使用下面安裝包安裝
安裝包:egenix-pyopenssl-0.13.7.win32-py2.7.msi
6. 安裝Scrapy
> pip2 install service_identity
> pip2 install Scrapy
驗證是否安裝成功:
> Scrapy
#如果提示找不到命令的話,可能需要一個工具環境支持:Twisted-15.0.0.win32-py2.7.msi
安裝完Twisted后再次嘗試驗證即可。
② Scrapy框架爬蟲程序初探
一個為了爬取網站數據,提取結構性數據而編寫的應用框架。最初是為了頁面抓取所設計的,也可以應用在獲取API所訪問的數據上,或者說通用的網絡爬蟲上。
使用Scrapy抓取一個網站一共需要四個步驟:
1. 創建一個Scrapy項目;
2. 定義Item容器;
3. 編寫爬蟲;
4. 存儲內容。
---Scrapy框架(官網)圖示---
實驗網站對象:www.dmoz.org
1. 創建一個Scrapy項目:crawler
C:\Users\Jan\Desktop\python_study>Scrapy startproject crawler
#crawler是我們的項目名稱
在\python_study\crawler\文件夾中即是我們的爬蟲框架。
Item是保存爬取到的數據的容器,其使用方法和python字典類似,并且提供了額外保護機制來避免拼寫錯誤導致的未定義字段錯誤。
2. 定義Item容器:
#crawler\crawler\items.py
import scrapy
class CrawlerItem(scrapy.Item):
? ? # define the fields for your item here like:
? ? # name = scrapy.Field()
? ? title = scrapy.Field()
? ? link = scrapy.Field()
? ? desc = scrapy.Field()
3. 編寫爬蟲:
編寫爬蟲類Spider,Spider是用戶編寫用于從網站上爬取數據的類。其包含了一個用于下載的初始化URL,然后是如何跟進網頁中的鏈接以及如何分析頁面中的內容,還有提取生成item的方法。
#crawler\crawler\spiders\crawler_spider.py 新建文件
import scrapy
class CrawlerSpider(scrapy.Spider):
? ? name = 'csdn' ?#爬蟲名字,調用的時候使用
? ? allowed_domains = ['csdn.net']
? ? start_urls = ['http://geek.csdn.net/AI']
? ? def parse(self, response):
? ? ? ? filename = response.url.split('/')[-2]
? ? ? ? with open(filename, 'wb') as f:
? ? ? ? ? ? f.write(response.body)
3.1 爬
win-cmd:
C:\Users\Jan\Desktop\python_study>cd crawler
C:\Users\Jan\Desktop\python_study\crawler>scrapy crawl csdn ?#csdn爬蟲類中的name
2017-09-08 21:56:28 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: crawler)
...
2017-09-08 21:56:30 [scrapy.core.engine] INFO: Spider opened
2017-09-08 21:56:30 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-09-08 21:56:30 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-09-08 21:56:30 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://geek.csdn.net/robots.txt> (referer: None) ?#Here: robots.txt
2017-09-08 21:56:30 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://geek.csdn.net/AI> (referer: None) ?#Here: 我們的目標爬取鏈接
2017-09-08 21:56:31 [scrapy.core.engine] INFO: Closing spider (finished)
...
2017-09-08 21:56:31 [scrapy.core.engine] INFO: Spider closed (finished)
#爬取的內容存儲位置(爬取網站的源碼文件):
C:\Users\Jan\Desktop\python_study\crawler\ 目錄下 geek.csdn.net 的NET文件。
3.2 取
在Scrapy中使用的是一種基于XPath和CSS的表達式機制:Scrapy Selectors(選擇器)
Selector是一個選擇器,有4個基本方法:
xpath() 傳入xpath表達式,返回該表達式所對應的所有節點的selector list列表。
css() 傳入CSS表達式,返回該表達式所對應的所有節點的selector list列表。
extract() 序列化該節點為unicode字符串并返回list。
re() 根據傳入的正則表達式對數據進行提取,返回unicode字符串list列表。
win-cmd進入項目根目錄后執行:scrapy shell "http://target_url/"
C:\Users\Jan\Desktop\python_study\crawler>scrapy shell "http://geek.csdn.net/AI"
2017-09-08 22:05:48 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: crawler)
...
2017-09-08 22:05:50 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-09-08 22:05:50 [scrapy.core.engine] INFO: Spider opened
2017-09-08 22:05:50 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://geek.csdn.net/robots.txt> (referer: None)
2017-09-08 22:05:50 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://geek.csdn.net/AI> (referer: None)
...
>>> response.body #輸出網頁的源碼信息
>>> response.headers ?#輸出網頁的頭部信息
{'Date': ['Fri, 08 Sep 2017 14:06:31 GMT'], 'Content-Type': ['text/html; charset=utf-8'], 'Server': ['openresty'], 'Vary': ['Accept-Encoding', 'Accept-Encoding']}
XPath是一門在網頁中查找特定信息的語言,所以用XPath來篩選數據,要比使用正則表達式容易些。
/html/head/title 選擇HTML文檔中<head>標簽內的<title>元素
/html/head/title/text() 選擇上面提到的<title>元素的文字
//td 選擇所有的<td>元素
//div[@class="mine"] 選擇所有具有 class="mine" 屬性的div元素
response.xpath() = response.selector.xpath() ?#已經映射。可以直接使用.xpath()
>>> response.xpath('//title')
[<Selector xpath='//title' data=u'<title>CSDN\u6781\u5ba2\u5934\u6761-\u63a8\u8350\u6bcf\u65e5\u6700\u65b0\u6700\u70edIT\u8d44\u8baf</title>'>] ?#\u的那些是中文字符,編碼方式決定顯示
>>> response.xpath('//title/text()').extract() ?#截圖title內容
[u'CSDN\u6781\u5ba2\u5934\u6761-\u63a8\u8350\u6bcf\u65e5\u6700\u65b0\u6700\u70edIT\u8d44\u8baf']
>>> sel.xpath('//span/a') ?#輸出所有<span><a>標簽的內容全部輸出
2017-09-08 22:36:08 [py.warnings] WARNING: <string>:1: ScrapyDeprecationWarning: "sel" shortcut is deprecated. Use "response.xpath()", "response.css()" or "response.selector" instead
>>> sel.xpath('//span/a/text()').extract() ?#獲取所有<span><a>標簽中的字符串,即標題
>>> sel.xpath('//span/a/@href').extract() ?#獲取<span><a>中的連接地址
>>> sites = sel.xpath('//div/div/div/dl/dd/span/a/text()').extract() ?#按照標簽包裹的層級<body>下開始找到包裹標題的<a>標簽寫入xpath中
>>> for title in sites: ?#使用for循環打印可以自動將Unicode轉換為對應中文編碼顯示
... ? ? print(title)
自己動手做聊天機器人 四十二-(重量級長文)從理論到實踐開發自己的聊天機器人
微軟攜手 Facebook 推出開源項目 打造共享神經網絡模型
Taylor Swift vs 人工智能:作詞誰更強?
推薦13個機器學習框架
...
>>> sites = sel.xpath('//div/div/div[@class="directory-url"]/dl/dd/span/a/text()').extract()
#其中[@class="directory-url"]的功能是:過濾掉對應樣式類的內容,此處僅做演示
#crawler\crawler\spiders\crawler_spider.py 修改代碼
import scrapy
class CrawlerSpider(scrapy.Spider):
? ? name = 'csdn'
? ? allowed_domains = ['csdn.net']
? ? start_urls = ['http://geek.csdn.net/AI']
? ? def parse(self, response):
? ? ? ? sel = scrapy.selector.Selector(response)
? ? ? ? sites = sel.xpath('//div/div/div/dl/dd/span')
? ? ? ? for site in sites:
? ? ? ? ? ? title = site.xpath('a/text()').extract()
? ? ? ? ? ? link ?= site.xpath('a/@href').extract()
? ? ? ? ? ? desc ?= site.xpath('text()').extract()
? ? ? ? ? ? print(title, link, desc)
win-cmd:
C:\Users\Jan\Desktop\python_study\crawler>scrapy crawl csdn
#運行就可以將print中的內容在爬取時一并顯示出來(輸出內容略)
4. 存儲內容
最常見的導出為json格式。
中文亂碼問題:http://bbs.fishc.com/thread-85672-1-1.html
#crawler\crawler\spiders\crawler_spider.py ?構造items的列表對象
import scrapy
from crawler.items import CrawlerItem
class CrawlerSpider(scrapy.Spider):
? ? name = 'csdn'
? ? allowed_domains = ['csdn.net']
? ? start_urls = ['http://geek.csdn.net/AI']
? ? def parse(self, response):
? ? ? ? sel = scrapy.selector.Selector(response)
? ? ? ? items = []
? ? ? ? sites = sel.xpath('//div/div/div/dl/dd/span')
? ? ? ? for site in sites:
? ? ? ? ? ? item = CrawlerItem() ?#實例化一個item類(類似于字典)
? ? ? ? ? ? item['title'] = site.xpath('a/text()').extract()
? ? ? ? ? ? item['link'] ?= site.xpath('a/@href').extract()
? ? ? ? ? ? item['desc'] ?= site.xpath('text()').extract()
? ? ? ? ? ? print(item['title'], item['link'], item['desc'])
? ? ? ? ? ? items.append(item)
? ? ? ? return items
#crawler\crawler\pipelines.py ?設置抓取內容存儲的文件名以及校正中文亂碼
import json
import codecs
store_filename = 'items.json' ? ?#item.json指的是要保存的json格式文件的名稱
class CrawlerPipeline(object):
? ? def __init__(self):
? ? ? ? self.file = codecs.open(store_filename, 'wb', encoding='utf-8') ?#中文編碼格式一般都是'utf-8'
? ? def process_item(self, item, spider):
? ? ? ? line = json.dumps(dict(item), ensure_ascii=False) + '\n' ?#這一句會將你每次返回的字典抓取出來,“ensure_ascii=False”這一句話很重要,如果是True的話就是我們保存的\u4e2d\u56fd這種格式了
? ? ? ? self.file.write(line) ?#寫入到文件中
? ? ? ? return item
#crawler\crawler\setting.py ?使pipelines.py生效,取消注釋ITEM_PIPELINES
ITEM_PIPELINES = {
? ? 'crawler.pipelines.CrawlerPipeline': 300, ?#300是正常值,不變。
}
win-cmd運行scrapy,即可自動在\crawler\目錄下生成items.json文件,并且中文顯示正常:
C:\Users\Jan\Desktop\python_study\crawler>scrapy crawl csdn
C:\Users\Jan\Desktop\python_study\crawler\items.json ?#中文正常。
{"title": ["自己動手做聊天機器人 四十二-(重量級長文)從理論到實踐開發自己的聊天機器人"], "link": ["http://www.shareditor.com/blogshow?blogId=136&hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io"], "desc": ["\n ? ? ? ? ? ? ? ? ? ? ? ? ? ?", "\n ? ? ? ? ? ? ? ? ? ? ? ?"]}
{"title": ["微軟攜手 Facebook 推出開源項目 打造共享神經網絡模型"], "link": ["http://tech.163.com/17/0908/08/CTQ1403R00097U80.html"], "desc": ["\n ? ? ? ? ? ? ? ? ? ? ? ? ? ?", "\n ? ? ? ? ? ? ? ? ? ? ? ?"]}
{"title": ["Taylor Swift vs 人工智能:作詞誰更強?"], "link": ["http://dataquestion.com/taylor-vs-ai"], "desc": ["\n ? ? ? ? ? ? ? ? ? ? ? ? ? ?", "\n ? ? ? ? ? ? ? ? ? ? ? ?"]}
...
--------------------------------2017.09.09----------------------------------------
23丶GUI界面的終極選擇 Tkinter
Tkinter是python的默認GUI模塊庫。
示例1:主窗口及標題
import tkinter as tk
app = tk.Tk() ?#根窗口的實例(root窗口)
app.title('Tkinter root window') ?#根窗口標題
theLabel = tk.Label(app, text='我的第2個窗口程序!') ?#label組件及文字內容
theLabel.pack() ?#pack()用于自動調節組件的尺寸
app.mainloop() ?#窗口的主事件循環,必須的。
示例2:按鈕
import tkinter as tk
class APP:
? ? def __init__(self, master): ?#root 傳參賦值給master
? ? ? ? frame = tk.Frame(master) ?#frame 組件
? ? ? ? frame.pack(side=tk.LEFT, padx=10, pady=10)
? ? ? ? self.hi_there = tk.Button(frame, text='打招呼', bg='black', fg='white', command=self.say_hi) ?#Button按鈕, command中調用定義的方法
? ? ? ? self.hi_there.pack()
? ? def say_hi(self):
? ? ? ? print('臥槽,居然打了個招呼!~')
root = tk.Tk()
app = APP(root)
root.mainloop()
示例3:圖片
from tkinter import *
root = Tk()
textLabel = Label(root,
? ? ? ? ? ? ? ? ? text='請重試!\n您的操作不被允許!', ?#文字支持換行
? ? ? ? ? ? ? ? ? justify=LEFT, ?#左對齊
? ? ? ? ? ? ? ? ? padx=10, ?#左邊距10px
? ? ? ? ? ? ? ? ? pady=10) ?#右邊距10px?
textLabel.pack(side=LEFT)
#顯示圖片
photo = PhotoImage(file='tk_image.png')
imageLabel = Label(root, image=photo)
imageLabel.pack(side=RIGHT)
mainloop()
示例4:背景
from tkinter import *
root = Tk()
photo = PhotoImage(file='tk4_bg.png')
theLabel = Label(root,
? ? ? ? ? ? ? ? ?text='生存還是毀滅\n這是一個問題',
? ? ? ? ? ? ? ? ?justify=LEFT,
? ? ? ? ? ? ? ? ?image=photo,
? ? ? ? ? ? ? ? ?compound=CENTER,
? ? ? ? ? ? ? ? ?font=('華文隸書', 20),
? ? ? ? ? ? ? ? ?fg='blue')
theLabel.pack()
mainloop()
示例5:按鈕交互
from tkinter import *
def callback():
? ? var.set('吹吧你,我才不信呢!')
root = Tk()
frame1 = Frame(root)
frame2 = Frame(root)
var = StringVar()
var.set('請重試!\n您的操作不被允許!')
textLabel = Label(frame1,
? ? ? ? ? ? ? ? ? textvariable=var,
? ? ? ? ? ? ? ? ? justify=LEFT) ?#左對齊
textLabel.pack(side=LEFT)
#顯示圖片
photo = PhotoImage(file='tk_image.png')
imageLabel = Label(root, image=photo)
imageLabel.pack(side=RIGHT)
theButton = Button(frame2, text='我是超級管理員', command=callback)
theButton.pack()
frame1.pack(padx=10, pady=10)
frame2.pack(padx=10, pady=10)
mainloop()
示例6:選項按鈕
from tkinter import *
root = Tk()
v = IntVar()
c = Checkbutton(root, text='測試一下', variable=v) ?#v用來存放選中狀態
c.pack()
l = Label(root, textvariable=v)
l.pack() ?#未選中顯示為0,選中顯示1
mainloop()
示例7:多個方框選項
from tkinter import *
root = Tk()
GIRLS = ['西施', '貂蟬', '王昭君', '楊玉環']
v = ?[]
for girl in GIRLS:
? ? v.append(IntVar())
? ? b = Checkbutton(root, text=girl, variable=v[-1])
? ? b.pack(anchor=W) ?#設置對齊方位,東E南S西W北N
mainloop()
示例8:多個圓點選項 Radiobutton
from tkinter import *
root = Tk()
v = IntVar()
Radiobutton(root, text='one', variable=v, value=1).pack(anchor=W)
Radiobutton(root, text='two', variable=v, value=2).pack(anchor=W)
Radiobutton(root, text='three', variable=v, value=3).pack(anchor=W)
Radiobutton(root, text='four', variable=v, value=4).pack(anchor=W)
mainloop()
示例9:內陷填充按鈕選項 Radiobutton indicatoron
from tkinter import *
root = Tk()
LANGS = [
? ? ('C', 1),
? ? ('C++', 2),
? ? ('shell', 3),
? ? ('python', 4)]
v = IntVar()
v.set(1)
for lang, num in LANGS: ?#對應列表中包含元組同時執行多個循環
? ? b = Radiobutton(root, text=lang, variable=v, value=num, indicatoron=False)
? ? b.pack(fill=X)
mainloop()
示例10:附帶標題的圓點選項 LabelFrame
from tkinter import *
root = Tk()
group = LabelFrame(root, text='最好的開發語言是?', padx=5, pady=5)
group.pack(padx=10, pady=10)
LANGS = [
? ? ('C', 1),
? ? ('C++', 2),
? ? ('shell', 3),
? ? ('python', 4)]
v = IntVar()
v.set(1)
for lang, num in LANGS: ?#對應列表中包含元組同時執行多個循環
? ? b = Radiobutton(group, text=lang, variable=v, value=num)
? ? b.pack(anchor=W)
mainloop()
示例11:輸入框 Entry
from tkinter import *
root = Tk()
e = Entry(root)
e.pack(padx=20, pady=20)
e.delete(0, END)
e.insert(0, '默認文本...')
mainloop()
示例12:按鈕和輸入框交互
from tkinter import *
root = Tk()
root.title('輸入框與按鈕程序')
Label(root, text='作品:').grid(row=0, column=0)
Label(root, text='作者:').grid(row=1, column=0)
e1 = Entry(root)
e2 = Entry(root)
e1.grid(row=0, column=1, padx=10, pady=5)
e2.grid(row=1, column=1, padx=10, pady=5)
def show(): ?#當輸入內容時點擊獲取信息會打印
? ? print('作品:《%s》' % e1.get())
? ? print('作者:《%s》' % e2.get())
Button(root, text='獲取信息', width=10, command=show) \
? ? ? ? ? ? ?.grid(row=3, column=0, sticky=W, padx=10, pady=5)
Button(root, text='點擊退出', width=10, command=root.quit) \
? ? ? ? ? ? ?.grid(row=3, column=1, sticky=E, padx=10, pady=5)
#退出按鈕必須是雙擊打開.py文件才可以,而不是在IDLE下調試運行時
mainloop()
示例12:登陸框程序
from tkinter import *
root = Tk()
root.title('登陸程序')
Label(root, text='賬號:').grid(row=0, column=0)
Label(root, text='密碼:').grid(row=1, column=0)
v1 = StringVar()
v2 = StringVar()
e1 = Entry(root, textvariable=v1)
e2 = Entry(root, textvariable=v2, show='*')
e1.grid(row=0, column=1, padx=10, pady=5)
e2.grid(row=1, column=1, padx=10, pady=5)
def show():
? ? print('賬號:%s' % e1.get())
? ? print('密碼:%s' % e2.get())
Button(root, text='芝麻開門', width=10, command=show) \
? ? ? ? ? ? ?.grid(row=3, column=0, sticky=W, padx=10, pady=5)
Button(root, text='點擊退出', width=10, command=root.quit) \
? ? ? ? ? ? ?.grid(row=3, column=1, sticky=E, padx=10, pady=5)
#退出按鈕必須是雙擊打開.py文件才可以,而不是在IDLE下調試運行時
mainloop()
示例13:輸入對錯驗證程序
from tkinter import *
root = Tk()
root.title('輸入對錯驗證')
def test():
? ? if e1.get() == '張三':
? ? ? ? print('正確!')
? ? ? ? return True
? ? else:
? ? ? ? print('錯誤!')
? ? ? ? e1.delete(0, END)
? ? ? ? return False
v = StringVar()
#focusout指定在當前輸入框失去焦點時,代表輸入完,會去調用test校驗<tab>鍵可測試
e1 = Entry(root, textvariable=v, validate='focusout', validatecommand=test)
e2 = Entry(root)
e1.pack(padx=10, pady=10)
e2.pack(padx=10, pady=10)
mainloop()
示例13:簡單計算器程序
from tkinter import *
root = Tk()
root.title('計算器程序')
frame = Frame(root)
frame.pack(padx=10, pady=10)
v1 = StringVar()
v2 = StringVar()
v3 = StringVar()
def test(content):
? ? return content.isdigit()
testCMD = frame.register(test)
#focusout指定在當前輸入框失去焦點時,代表輸入完,會去調用test校驗<tab>鍵可測試
e1 = Entry(frame, width=10, textvariable=v1, validate='key', \
? ? ? ? ? ?validatecommand=(testCMD, '%P')).grid(row=0, column=0) ?#width的單位是字符數
Label(frame, text='+').grid(row=0, column=1)
e2 = Entry(frame, width=10, textvariable=v2, validate='key', \
? ? ? ? ? ?validatecommand=(testCMD, '%P')).grid(row=0, column=2)
Label(frame, text='=').grid(row=0, column=3)
e3 = Entry(frame, width=10, textvariable=v3, state='readonly').grid(row=0, column=4)
def calc():
? ? result = int(v1.get()) + int(v2.get())
? ? v3.set(str(result))
Button(frame, text='計算結果', command=calc).grid(row=1, column=2, pady=5)
mainloop()
示例14:按鈕刪除列表中的選項
from tkinter import *
master= Tk()
theLB = Listbox(master, selectmode=SINGLE, height=15) ?#SINGLE單選,MULTIPLE多選,height設置顯示項數
theLB.pack()
for item in ['筆', '墨', '紙', '硯']:
? ? theLB.insert(END, item) ?#END表示最后一個
for item in range(11):
? ? theLB.insert(END, item)
? ??
theButton = Button(master, text='刪除', \
? ? ? ? ? ? ? ? ? ?command=lambda x=theLB:x.delete(ACTIVE) ) #ACTIVE表示當前選中的值
theButton.pack()
mainloop()
示例15:為列表組件添加滾動條
安裝垂直滾動條步驟:
1) 設置該組件的yscrollbarcommand選項為Scrollbar組件的set方法;
2) 設置Scrollbar組件的command選項為該組件的yview()方法。
from tkinter import *
root = Tk()
root.title('滾動條程序')
sb = Scrollbar(root)
sb.pack(side=RIGHT, fill=Y)
lb = Listbox(root, yscrollcommand=sb.set)
for i in range(1000):
? ? lb.insert(END, i)
lb.pack(side=LEFT, fill=BOTH)
#讓滾動條與選項互通互連
sb.config(command=lb.yview)
mainloop()
示例16:滑塊滾動條 Scale
from tkinter import *
root = Tk()
root.title('滑塊程序')
s1 = Scale(root, from_=0, to=100, tickinterval=5, resolution=5, length=200) ?#默認是垂直, tickinterval精度刻度, length單位是像素
s1.pack()
s2 = Scale(root, from_=0, to=100, tickinterval=5, orient=HORIZONTAL, length=400)
s2.pack()
def show():
? ? print(s1.get(), s2.get())
#獲取滑塊的當前位置,點擊后才有效
Button(root, text='音量:', command=show).pack()
mainloop()
示例17:文本組件 Text ?(插入按鈕)
from tkinter import *
root = Tk()
root.title('Text')
text = Text(root, width=30, height=20)
text.pack()
#窗口中的文本可編輯
text.insert(INSERT, '這里是顯示的文本信息內容。\n') ?#INSERT表示輸入光標插入的位置
text.insert(END, '對比一下效果。')
def show():
? ? print('提交中...') ?#此行內容顯示在IDLE中
#插入一個Button組件
b1 = Button(text, text='提交', command=show)
text.window_create(INSERT, window=b1) ?#將b1插入
mainloop()
示例18:文本組件 Text ?(插入圖片)
from tkinter import *
root = Tk()
root.title('Text')
text = Text(root, width=100, height=30)
text.pack()
photo = PhotoImage(file="tk_image.png")
def show_img():
? ? text.image_create(END, image=photo)
#插入一個圖片
b1 = Button(text, text='插入圖片', command=show_img)
text.window_create(INSERT, window=b1) ?#將b1插入
mainloop()
示例19:文本組件 Text ?(Indexes:索引定位)
from tkinter import *
root = Tk()
root.title('Text')
text = Text(root, width=30, height=10)
text.pack()
text.insert(INSERT, 'I love baidu.com!')
text.tag_add('tag1', '1.7', '1.12', '1.14') ?#1.7~1.12 baidu ? 1.14 o
text.tag_add('tag2', '1.7', '1.12', '1.14')
text.tag_config('tag1', background='blue', foreground='yellow')
text.tag_config('tag2', foreground='red') ?#文字會以red為準
mainloop()
示例20:文本組件中可點擊連接
from tkinter import *
import webbrowser as wb
root = Tk()
root.title('GUI link show')
text = Text(root, width=30, height=5)
text.pack()
text.insert(INSERT, 'I love baidu.com!')
text.tag_add('link', '1.7', '1.16')
text.tag_config('link', foreground='blue', underline=True)
def show_arrow_cursor(event):
? ? text.config(cursor='arrow')
def show_xterm_cursor(event):
? ? text.config(cursor='xterm')
def click(event):
? ? wb.open('http://www.baidu.com')
#綁定事件
text.tag_bind('link', '<Enter>', show_arrow_cursor) ?#<Enter>鼠標進入
text.tag_bind('link', '<Leave>', show_xterm_cursor) ?#<Enter>鼠標離開
text.tag_bind('link', '<Button-1>', click) ?#<Enter>鼠標點擊
mainloop()
示例21:文本組件之MD5
from tkinter import *
import hashlib ?#用于獲取文件的MD5值,檢查內容是否有修改
root = Tk()
root.title('link click')
text = Text(root, width=50, height=10)
text.pack()
text.insert(INSERT, 'I love www.baidu.com')
contents = text.get('1.0', END)
def getSig(contents):
? ? m = hashlib.md5(contents.encode())
? ? return m.digest()
sig = getSig(contents)
def check():
? ? contents = text.get('1.0', END)
? ? if sig != getSig(contents):
? ? ? ? print('內容有修改,是否保存?')
? ? else:
? ? ? ? print('無任何修改!')
Button(root, text='檢查', command=check).pack()
mainloop()
示例22:文本組件之全文搜索
from tkinter import *
root = Tk()
root.title('link click')
text = Text(root, width=50, height=10)
text.pack()
text.insert(INSERT, 'I love www.baidu.com')
def getIndex(text, index):
? ? return tuple(map(int, str.split(text.index(index), '.')))
start = '1.0' ?#開頭的位置,第1行的第0個下標位置
while True:
? ? pos = text.search('o', start, stopindex=END) ?#查找文本中字符o的位置
? ? if not pos:
? ? ? ? break
? ? print('找到啦,位置是:', getIndex(text, pos))
? ? start = pos + '+1c' ?#'+1c'指向下一個字符
mainloop()
示例23:文本組件之撤銷操作
from tkinter import *
root = Tk()
root.title('link click')
text = Text(root, width=50, height=10, undo=True) ?#undo模式開啟
text.pack()
text.insert(INSERT, 'I love www.baidu.com')
def show():
? ? text.edit_undo()
Button(root, text='撤銷', command=show).pack() ?#多次撤銷會刪除文本組件內的內容
mainloop()
示例24:繪制組件 Canvas
from tkinter import *
root = Tk()
root.title('Canvas')
w = Canvas(root, width=500, height=300) ?#background='black' 改變背景色
w.pack()
#黃色的矩形
w.create_rectangle(50, 50, 450, 250, fill='yellow') ?#參數:左邊距, 上邊距, 寬, 高
#紅色的橫線
w.create_line(0, 300//2, 500, 300//2, fill='red')
#藍色的豎虛線
w.create_line(500//2, 0, 500//2, 300, fill='blue', dash=(4, 4)) ?#dash 虛線
mainloop()
示例25:繪制組件 Canvas (修改和刪除圖形)
from tkinter import *
root = Tk()
root.title('Canvas')
w = Canvas(root, width=500, height=300) ?#background='black' 改變背景色
w.pack()
rect1 = w.create_rectangle(50, 50, 450, 250, fill='yellow') ?#參數:左邊距, 上邊距, 寬, 高
line1 = w.create_line(0, 300//2, 500, 300//2, fill='red')
line2 = w.create_line(500//2, 0, 500//2, 300, fill='blue', dash=(4, 4)) ?#dash 虛線
w.coords(line1, 0, 25, 500, 25) ?#移動位置
w.itemconfig(rect1, fill='red')
w.delete(line2)
Button(root, text='刪除全部', command=(lambda x=ALL:w.delete(x))).pack()
mainloop()
示例26:繪制組件 Canvas (圖形正中心)
from tkinter import *
root = Tk()
root.title('Canvas')
w = Canvas(root, width=600, height=300)
w.pack()
line1 = w.create_line(0, 0, 600, 300, fill='green', width=3)
line1 = w.create_line(600, 0, 0, 300, fill='green', width=3)
rect1 = w.create_rectangle(60, 30, 540, 270, fill='green')
rect2 = w.create_rectangle(120, 60, 480, 240, fill='yellow')
w.create_text(300, 150, text='Hello, python!')
mainloop()
示例27:繪制組件 Canvas (橢圓和圓形)
from tkinter import *
root = Tk()
root.title('Canvas')
w = Canvas(root, width=600, height=300)
w.pack()
w.create_rectangle(60, 30, 540, 270, dash=(4, 4))
w.create_oval(60, 30, 540, 270, fill='pink') ?#橢圓是通過限定矩形的方式畫出來,圓形通過正方形
#w.create_oval(60, 30, 300, 270, fill='pink') ?#正方形對應正圓(60-300=30-270)
w.create_text(300, 150, text='wow~')
mainloop()
示例28:繪制組件 Canvas (五角星)
from tkinter import *
import math as m ?#用到sin和cos數學函數
root = Tk()
root.title('Canvas')
w = Canvas(root, width=600, height=300, background='red')
w.pack()
center_x = 300
center_y = 150
r = 150
points = [
? ? #左上點
? ? center_x - int(r * m.sin(2 * m.pi / 5)),
? ? center_y - int(r * m.cos(2 * m.pi / 5)),
? ? #右上點
? ? center_x + int(r * m.sin(2 * m.pi / 5)),
? ? center_y - int(r * m.cos(2 * m.pi / 5)),
? ? #左下點
? ? center_x - int(r * m.sin(m.pi / 5)),
? ? center_y + int(r * m.cos(m.pi / 5)),
? ? #頂點
? ? center_x,
? ? center_y - r,
? ? #右下點
? ? center_x + int(r * m.sin(m.pi / 5)),
? ? center_y + int(r * m.cos(m.pi / 5)),
? ? ]
w.create_polygon(points, outline='yellow', fill='yellow') ?#polygon多邊形
mainloop()
示例29:繪制組件 Canvas (自定義畫板)
#繪制一個極小的圓來代表一個點(tkinter本身不支持畫點)
from tkinter import *
root = Tk()
root.title('Canvas draw tool')
w = Canvas(root, width=400, height=200, background='white')
w.pack()
def paint(event):
? ? x1, y1 = (event.x - 1), (event.y - 1)
? ? x2, y2 = (event.x + 1), (event.y + 1)
? ? w.create_oval(x1, y1, x2, y2, fill='red')
w.bind('<B1-Motion>', paint) ?#<B1-Motion>綁定鼠標左鍵事件
Label(root, text='按住鼠標左鍵并移動,開始繪制吧!~~').pack(side=BOTTOM)
mainloop()
示例30:菜單組件 Menu (主菜單/下拉菜單/右鍵菜單/單多選菜單/按鈕菜單/選項菜單(列表))
from tkinter import *
root = Tk()
root.title('Main Menu Show')
def callback():
? ? print('你好~')
menubar = Menu(root)
#注冊菜單:文件(下拉菜單)
filemenu = Menu(menubar, tearoff=False) ?#來自主菜單,tearoff參數可讓菜單窗口分離
filemenu.add_command(label='新建', command=callback)
filemenu.add_command(label='打開...', command=callback)
filemenu.add_separator() ?#分割線
filemenu.add_command(label='保存', command=callback)
filemenu.add_separator() ?#分割線
filemenu.add_command(label='退出', command=root.quit)
menubar.add_cascade(label='文件(W)', menu=filemenu)
#主菜單:編輯(下拉菜單)
editmenu = Menu(menubar, tearoff=False) ?#來自主菜單
editmenu.add_command(label='撤銷', command=callback)
editmenu.add_command(label='重做', command=callback)
editmenu.add_separator() ?#分割線
editmenu.add_command(label='剪切', command=callback)
editmenu.add_command(label='復制', command=callback)
editmenu.add_command(label='粘貼', command=callback)
editmenu.add_separator() ?#分割線
editmenu.add_command(label='全選', command=callback)
editmenu.add_separator() ?#分割線
editmenu.add_command(label='查找...', command=callback)
menubar.add_cascade(label='編輯(B)', menu=editmenu)
#主菜單:多選√ checkbutton(下拉菜單)
openVar = IntVar()
saveVar = IntVar()
quitVar = IntVar()
optionmenu = Menu(menubar, tearoff=False)
optionmenu.add_checkbutton(label='多選項1', command=callback, variable=openVar)
optionmenu.add_checkbutton(label='多選項2', command=callback, variable=saveVar)
optionmenu.add_checkbutton(label='多選項3', command=callback, variable=quitVar)
menubar.add_cascade(label='選項(C)', menu=optionmenu)
#主菜單:單選√ radiobutton(下拉菜單)
otherVar = IntVar()
othermenu = Menu(menubar, tearoff=False)
othermenu.add_radiobutton(label='單選項1', command=callback, variable=otherVar, value=1)
othermenu.add_radiobutton(label='單選項2', command=callback, variable=otherVar, value=2)
othermenu.add_radiobutton(label='單選項3', command=callback, variable=otherVar, value=3)
menubar.add_cascade(label='其他(C)', menu=othermenu)
#內部菜單:按鈕菜單 Menubutton
mb = Menubutton(root, text='按鈕菜單...', relief=RAISED)
mb.pack()
openVar = IntVar()
saveVar = IntVar()
quitVar = IntVar()
optionmenu = Menu(mb, tearoff=False)
optionmenu.add_checkbutton(label='test', command=callback, variable=openVar)
optionmenu.add_checkbutton(label='test', command=callback, variable=saveVar)
optionmenu.add_checkbutton(label='test', command=callback, variable=quitVar)
mb.config(menu=optionmenu)
#內部菜單:選項菜單 OptionMenu
variable = StringVar()
variable.set('one') ?#默認顯示one
w = OptionMenu(root, variable, 'one', 'two', 'three')
w.pack()
#將列表添加到選項菜單 OptionMenu
OPTIONS = [
? ? '表項1',
? ? '對比2',
? ? '選項3',
? ? '其他4',
? ? '退出5'
? ? ]
var = StringVar()
var.set(OPTIONS[0])
o = OptionMenu(root, var, *OPTIONS) ?#*星號解包可變參數列表為逐個元素
o.pack()
#主菜單:幫助
helpmenu = Menu(menubar, tearoff=False)
helpmenu.add_separator() ?#分割線
helpmenu.add_command(label='關于...', command=callback)
helpmenu.add_separator() ?#分割線
menubar.add_cascade(label='幫助(F1)', menu=helpmenu)
#彈出菜單(暫用編輯菜單作為右鍵)
frame = Frame(root, width=512, height=512)
frame.pack()
def popup(event):
? ? editmenu.post(event.x_root, event.y_root)
frame.bind('<Button-3>', popup) ?#Button-3為鼠標右鍵,1為左鍵,2為中鍵
root.config(menu=menubar) ?#menu參數會將菜單設置添加到root根窗口
mainloop()
示例31:事件綁定 bind (鼠標/按鍵/按鍵組合)
from tkinter import *
root = Tk()
root.title('Event bind')
frame = Frame(root, width=200, height=200)
#鼠標響應事件
def callback1(event): ?#event形參獲取事件描述,必備參數
? ? print('點擊位置:', event.x, event.y)
frame.bind('<Button-1>', callback1) ?#Button表示鼠標點擊事件, 12345分別代表左中右鍵上滾下滾
frame.pack()
#鍵盤響應事件
def callback2(event):
? ? print(event.keysym) ?#打印信息在IDLE, keysym指鍵盤所有按鍵
frame.bind('<Key>', callback2)
frame.focus_set()
frame.pack()
#鼠標即時響應事件
def callback3(event):
? ? print('點擊位置:', event.x, event.y)
frame.bind('<Motion>', callback3) ?#鼠標在窗口內只要有移動就一直輸出位置
frame.pack()
#事件序列(按鍵組合),語法:<modifier-type-detail> 如
#點擊鼠標左鍵:<Button-1> ?ButtonRelease更安全,移除組件釋放點擊時不去觸發
#點擊H字母按鍵:<KeyPress-H>
#同時點擊Ctrl+Shift+H:<Control-Shift-KeyPress-H>
mainloop()
示例32:消息組件 Message | 輸入組件 Spinbox
from tkinter import *
root = Tk()
root.title('Module')
#消息組件:Message
m1 = Message(root, text='這是一個消息:', width=100)
m1.pack()
m2 = Message(root, text='這是一\n則駭人聽聞的長長長長長長長消息!', width=100)
m2.pack()
#輸入組件:Spinbox ?(可指定輸入范圍)
s1 = Spinbox(root, from_=0, to=5)
s1.pack()
s2 = Spinbox(root, values=('zero', 'one', 'two', 'three', 'four', 'five'))
s2.pack()
mainloop()
示例33:窗口布局管理器 PanedWindow
from tkinter import *
root = Tk()
root.title('Module')
#二窗格
'''
p = PanedWindow(orient=VERTICAL)
p.pack(fill=BOTH, expand=1)
top = Label(p, text='top pane')
p.add(top)
bottom = Label(p, text='bottom pane')
p.add(bottom)
'''
#三窗格,同時顯示隱藏布局線(showhandle=True, sashrelief=SUNKEN)
p = PanedWindow(showhandle=True, sashrelief=SUNKEN)
p.pack(fill=BOTH, expand=1)
left = Label(p, text='left pane')
p.add(left)
q = PanedWindow(orient=VERTICAL, showhandle=True, sashrelief=SUNKEN)
p.add(q)
top = Label(q, text='top pane')
q.add(top)
bottom = Label(q, text='bottom pane')
q.add(bottom)
mainloop()
示例34:容器組件 Toplevel (創建頂級窗口,即彈出窗口)
from tkinter import *
root = Tk()
root.title('Toplevel')
def create():
? ? top = Toplevel()
? ? #top.attributes('-alpha', 0.5) 設置彈出的頂級窗口透明度:50%
? ? top.title('Toplevel demo...')
? ? msg = Message(top, text='I love python...')
? ? msg.pack()
Button(root, text='創建頂級窗口', command=create).pack() ?#點擊出現頂級窗口
mainloop()
示例35:幾何管理類,包pack(),網格grid(),位置place()
#pack() ?注意pack和grid不要混合使用
from tkinter import *
root = Tk()
root.title('pack')
#Listbox完全填充測試
listbox = Listbox(root)
listbox.pack(fill=BOTH, expand=True) ?#fill=BOTH將窗口填滿
for i in range(10):
? ? listbox.insert(END, str(i))
#Label縱向填充
Label(root, text='red', bg='red', fg='white').pack(fill=X)
Label(root, text='green', bg='green', fg='black').pack(fill=X)
Label(root, text='blue', bg='blue', fg='white').pack(fill=X)
#Label橫向填充
Label(root, text='red', bg='red', fg='white').pack(side=LEFT)
Label(root, text='green', bg='green', fg='black').pack(side=LEFT)
Label(root, text='blue', bg='blue', fg='white').pack(side=LEFT)
mainloop()
#grid() ?注意pack和grid不要混合使用
from tkinter import *
root = Tk()
root.title('grid')
#兩個sticky=W實現第一列左對齊
Label(root, text='用戶名').grid(row=0, sticky=W)
Label(root, text='密碼').grid(row=1, sticky=W)
#rowspan=2可以讓圖片橫跨2行
photo = PhotoImage(file='tk_image.png')
Label(root, image=photo).grid(row=0, column=2, rowspan=2, padx=5, pady=5)
Entry(root).grid(row=0, column=1)
Entry(root, show='*').grid(row=1, column=1)
def callback():
? ? print('登陸中...')
#columnspan=3可以讓按鈕橫跨3列
Button(text='提交', width=10, command=callback).grid(row=2, columnspan=3, pady=5)
mainloop()
#place() ? 可以實現一些pack和grid實現不了的布局
from tkinter import *
root = Tk()
root.title('place')
#place位置布局測試
'''
photo = PhotoImage(file='tk_image.png')
Label(root, image=photo).pack() ?#按鈕就會出現在圖片的組件上,實現組件疊加顯示
def callback():
? ? print('正中靶心!!!')
#relx,rely相對父組件root的位置,0.5正中間,1最右邊,0最左邊,anchor=CENTER居中顯示
Button(root, text='射擊', command=callback).place(relx=0.5, rely=0.5, anchor=CENTER)
'''
Label(root, bg='red').place(relx=0.5, rely=0.5, relheight=0.75, relwidth=0.75, anchor=CENTER)
Label(root, bg='yellow').place(relx=0.5, rely=0.5, relheight=0.5, relwidth=0.5, anchor=CENTER)
Label(root, bg='blue').place(relx=0.5, rely=0.5, relheight=0.25, relwidth=0.25, anchor=CENTER)
mainloop()
示例35:對話框 (警告 showinfo | 消息 messagebox | 文件 filedialog | 顏色 colorchooser)
from tkinter import *
from tkinter import messagebox ? ?#messagebox()需要單獨導入
from tkinter import filedialog ? ?#filedialog()需要單獨導入
from tkinter import colorchooser ?#colorchooser()需要單獨導入
from tkinter.messagebox import * ?#用戶使用showinfo()
#警告對話框
showinfo(title='test', message='警告')
#消息對話框
result = messagebox.askokcancel('demo', '發射核彈?') ?#返回值是True或False
print(result) ?#根據用戶按下了確定還是取消做進一步的操作
#文件對話框
root = Tk()
def callback1():
? ? filename = filedialog.askopenfilename(defaultextension='.py') ?#指定文件后綴
? ? print(filename) ?#返回的是文件的完整路徑
Button(root, text='打開文件', command=callback1).pack()
#顏色選擇對話框
def callback2():
? ? color_data = colorchooser.askcolor() ?#調用windows的顏色選擇器
? ? print(color_data) ?#選擇紅色打印:((255.99609375, 0.0, 0.0), '#ff0000')
Button(root, text='選擇顏色', command=callback2).pack()
mainloop()
總結
以上是生活随笔為你收集整理的【python】速查手册(基础笔记) - 人生苦短,我用python的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jedis 设置key的超时时间
- 下一篇: 获取python版本