學習筆記:《零基礎入門學習Python》(小甲蟲)
學習筆記:《零基礎入門學習Python》(小甲蟲)
0前言
Python3不完全相容Python2的語法。
Python官方網址:https://www.python.org/
] #號起到註釋的作用。
Spyder(Scientific PYthon Development EnviRonment)是一個強大的互動式 Python 語言開發環境,提供高階的程式碼編輯、互動測試、除錯等特性,支援包括 Windows、Linux 和 OS X 系統。
Spyder檢視Python內建函式(BIF,Built-in Functions)列表:
import builtins
print(dir(builtins))
1成為高手前必須知道的一些基礎知識
1.1變數
變數不需要先宣告;
在使用變數前,需要對其先賦值;
變數名可以包括字母、數字、下劃線,但不能以數字開頭;
區分大小寫;
1.2字串
雙引號或單引號內的東西:"Python I love you" 或 ‘Python I love you’。
如果字串中需要出現單引號或雙引號,此時需要使用轉義符號(\)對出現的引號進行轉義:
>>>'Let \'s go'
"Let's go"
如果字串中需要多個轉義時,使用轉義符號會使程式碼變得混亂,此時可以使用原始字串,在字串前邊加一個英文字母r即可:
>>>string =r 'C:\now'
string
'C:\\now'
print(string)
C:\now
注意:無論是否原始字串,都不能以反斜槓作為結尾(放在末尾表示該字串還沒有結束,換行繼續的意思);
如果希望得到一個跨越多行的字串,只需要使用三種引號字串("""內容""")就可以;
注意:程式設計中使用的標點符號都是英文的。
1.3資料型別
(1)整型
整數,Python3的整型已經與長整型進行了無縫結合,長度不受限制,如果說非要有個限制,那隻限於計算機的虛擬記憶體總數。所以用Python3很容易進行大數運算。
(2)浮點型
小數,Python區分整型和浮點型的唯一方式,就是看有沒有小數點。
浮點型採用E記法,即科學計數法,表示特別大或特別小的數:
>>>a = 0.000000000025
>>>a
2.5e - 11(大E和小e都可以)。
(3)布林型別
實際上是特殊的整型,True相當於1,False相當於0。
(4)型別轉換
int()將一個字串或浮點數轉換為一個整數:
>>>a = '520'
>>>b = int(a)
>>>a,b
('520', 520)
>>>c = 5.99
>>>d = int(c)
>>>c, d
(5.99, 5) #注意:浮點數轉為整數,Python採取截斷處理,將小數點後資料直接砍掉
(5)獲得關於型別的訊息
type()告訴變數的型別:
>>>type('520')
str
isinstance()確定變數的型別是否與給定的一致,有2個引數,第1個是待確定型別的資料,第2個是指定一個數據型別,一致返回True,不一致返回False:
>>>a = '520'
>>>isinstance(a, str)
True
1.4常用操作符
1. 算術操作符
+ - × / 加減乘除:
>>> a = 10
>>> b = a / 8
1.25 #返回一個浮點型的精確數值
// floor除法:
>>> a = 10
>>> b = a // 8
>>> 1 #返回比商小的最大整型
% 取餘:
** 冪:
>>> 10 ** 2
100
2. 比較操作符
< <= > >= == !=
3. 邏輯操作符
and or not
4. 優先順序
冪運算 > 正負號 > 算術操作符 > 比較操作符 > 邏輯操作符
注意:冪運算操作符比其左側的一元操作符優先順序高,比其右側的一元操作符運算級低。
>>> -3 ** 2
-9
>>> 3 ** -2
0.1111111111111111
2分支和迴圈
2.1if ......else....
if 條件:
內容
elif 條件:
內容
elif 條件:
內容
else:
內容
2.2條件表示式(三元操作符)
使用此類表示式,你可以使用一條語句來完成以下的條件判斷和賦值操作:
if x<y:
small = x
else:
small = y;
三元操作符語法:
a = x if 條件 else y
表示當條件為True時,a賦值為x,否則賦值為y。
所以上面的例子可以改寫為:small = x if x<y else y
2.3斷言(assert)
assert關鍵字稱為“斷言”,當關鍵字後面的條件為假時,程式自動崩潰並丟擲AssertionError的異常。
>>>assert 3>4
Traceback (most recent call last):
File "<ipython-input-18-020d57da1a31>", line 1, in <module>
assert 3>4
AssertionError
當我們在測試程式時就很好用,因為與其讓錯誤的條件導致程式今後莫名其妙地崩潰,不如在錯誤條件出現的一瞬間實現“自我毀滅”。一般來說,可以用它在程式中置入檢查點,當需要確保程式中的某個條件一定為真才能讓程式正常工作時,assert就非常有用。
2.4while迴圈語句
while 條件:
迴圈體
2.5for迴圈語句
Python的for迴圈跟C語言相比更加智慧和強大,主要表現在它會自動呼叫迭代器的next()方法,會自動捕獲StopIteration異常並結束迴圈:
>>>favourite = "FishC"
>>>for each in favourite:
print(each, end=' ')
FishC
for迴圈常與range()函式搭配。
range(start , stop, step):
(1)range(5):將第一個引數預設設定為0,生成從0到5的數字(包含0但不包含5:0,1,2,3,4)
(2)range(2,9):2,3,4,5,6,7,8
(3)range(1,10,2):1,3,5,7,9
2.6break語句和continue語句
break語句的作用是終止當前迴圈,跳出迴圈體;
coninue語句是終止本輪迴圈並開始下一輪迴圈。
3列表:一個打了激素的陣列
3.1建立列表
建立列表和建立普通變數一樣,用中括號括起一堆資料就可以了,資料之間用逗號隔開,這樣一個普通的列表就建立成功:
>>>number = [1,2,3,4,5]
我們說列表是打了激素的陣列,它可以建立一個魚龍混雜的列表:
>>>mix = [1, "小甲魚", 3.14, [1,2,3]]
該列表有整型、字串、浮點型資料,甚至還可以包含另一個列表。
如果不知道要往列表裡新增什麼資料時,可以建立一個空列表:>>>empty = []。
3.2向列表新增元素
(1)append():向列表末尾新增單個元素
>>>number = [1,2,3,4,5]
>>>number.append(6)
>>>print(number)
[1,2,3,4,5,6]
(2)extend():向列表末尾新增多個元素
>>>number = [1,2,3,4,5]
>>>number.extend([7,8])
>>>print(number)
[1,2,3,4,5,7,8]
(3)insert():在列表的任意位置插入單個元素
>>>number = [1,2,3,4,5]
>>>number.insert(0,0) #注意列表的下標從0開始
>>>print(number)
[0,1,2,3,4,5]
3.3從列表中獲取元素
跟陣列一樣,可以通過元素的索引值從列表中獲取單個元素,注意列表的索引值是從0開始:
>>>name = ["wangyi","liuer","lisan","zhaosi"]
>>>print(name[0])
>>>print(name[1])
wangyi
liuer
元素位置互調:
>>>name[1],name[3] = name[3],name[1]
>>>print(name)
['wangyi', 'zhaosi', 'lisan', 'liuer']
對於複合列表:
>>>mix = [1, "xiaojiayu", 3.14, [1,2,3]]
>>>print(mix[3][0])
1
3.4從列表刪除元素
(1)remove():你並不需要這個元素在列表中的具體位置,只需要知道該元素存在列表中就可以了。如果要刪除的東西根本不在列表中,程式就會報錯:
>>>name = ["wangyi","liuer","lisan","zhaosi"]
>>>name.remove("liuer")
>>>print(name)
['wangyi', 'lisan', 'zhaosi']
(2)del():remove()方法並不能指定刪除某個位置的元素,這時就要用del實現:
>>>name = ["wangyi","liuer","lisan","zhaosi"]
>>>del name[1]
>>>print(name)
['wangyi', 'lisan', 'zhaosi']
刪除整個列表:>>>del name
(3)pop():“彈出”元素
>>>name = ["wangyi","liuer","lisan","zhaosi"]
>>>name.pop()
>>>name.pop()
>>>print(name)
['wangyi', 'liuer']
pop()預設彈出列表中最後一個元素。但可以加上索引值,彈出對應的元素:
>>>name = ["wangyi","liuer","lisan","zhaosi"]
>>>name.pop(2)
>>>print(name)
['wangyi', 'liuer', 'zhaosi']
3.5列表分片(slice)
利用索引值,每次可以從列表中獲取一個元素,如果需要一次性獲取多個元素,有沒有辦法實現?利用列表分片可以實現:
>>>name = ["wangyi","liuer","lisan","zhaosi"]
>>>print(name[0:2])
['wangyi', 'liuer']
即用一個冒號隔開兩個索引值,左邊是開始位置,右邊是結束位置,注意,結束位置上的元素是不包含的。
利用列表分片,得到一個原來列表的拷貝,原來的列表並沒有改變。
列表分片簡寫:
>>>name = ["wangyi","liuer","lisan","zhaosi"]
>>>print(name[:2])
>>>print(name[1:])
>>>print(name[:])
['wangyi', 'liuer']
['liuer', 'lisan', 'zhaosi']
['wangyi', 'liuer', 'lisan', 'zhaosi']
列表分片的進階玩法:
分片操作實際上可以接收第三個引數,其代表步長,預設為1。若步長改為2:
>>>list = [1,2,3,4,5,6,7,8,9]
>>>print(list[0:9:2])
[1, 3, 5, 7, 9]
若改為-1:
>>>list = [1,2,3,4,5,6,7,8,9]
>>>print(list[::-1]) #相當於複製一個反轉的列表
[9, 8, 7, 6, 5, 4, 3, 2, 1]
3.6列表運算
(1)比較大小
>>>list1 = [123, 456]
>>>list2 = [234, 123]
>>>print(list1 > list2)
>>>list3 = ['abc']
>>>list4 = ['bcd']
>>>print(list3 > list4)
False
False
當列表包含多個元素時,預設是從第一個元素比較,只要有一個PK贏了,就算整個列表贏了。字串比較也是同樣(字串比較的時第一個字元對應的ASCII碼值的大小)。
(2)拼接
用加號+拼接:
>>>list1 = [123, 456]
>>>list2 = [234, 123]
>>>list3 = list1 + list2
>>>print(list3)
[123, 456, 234, 123]
(3)複製自身
用乘號*複製自身若干次:
>>>list1 = [123, 456]
>>>print(list1 * 3)
[123, 456, 123, 456, 123, 456]
3.7列表的小夥伴們
>>>dir(list)
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__gt__',
'__hash__',
'__iadd__',
'__imul__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__reversed__',
'__rmul__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']
其中,extend,insert等方法已介紹,在此再補充幾個常用的方法:
(1)count():計算它的引數在列表中出現的次數
>>>list1 = [1,1,2,3,4]
>>>print(list1.count(1))
2
(2)index():返回它的引數在列表中出現的位置
>>>list1 = [1,1,2,3,4]
>>>print(list1.index(1))
0
可以看到,返回的時第一個目標1在list1中的位置,怎麼查詢第二個1的位置呢?
>>>list1 = [1,1,2,3,4]
>>>start = list1.index(1) + 1
>>>stop = len(list1)
>>>print(list1.index(1,start,stop))
1
(3)reverse():將列表翻轉
>>>list1 = [1,1,2,3,4]
>>>list1.reverse()
>>>print(list1)
[4, 3, 2, 1, 1]
(4)sort():對列表成員排序,預設從小到大排序
>>>list1 = [8,9,3,5,2,6,10,1,0]
>>>list1.sort()
>>>print(list1)
>>>list1.sort(reverse=True)
>>>print(list1)
[0, 1, 2, 3, 5, 6, 8, 9, 10]
[10, 9, 8, 6, 5, 3, 2, 1, 0]
4元組:戴上了枷鎖的列表
元組和列表最大的區別就是你可以任意修改列表中的元素,可以任意插入或刪除一個元素,而對元組是不行的,元組是不可改變的(像字串一樣)。
4.1建立和訪問一個元組
>>>tuple1 = (1,2,3,4,5,6,7,8)
>>>print(tuple1)
>>>print(tuple1[1])
>>>print(tuple1[5:])
(1, 2, 3, 4, 5, 6, 7, 8)
2
(6, 7, 8)
也使用分片的方式來複制一個元組:
>>>tuple1 = (1,2,3,4,5,6,7,8)
>>>tuple2 = tuple1(:)
建立一個空元組:
>>>temp = ()
建立的元組中僅有一個元素:
>>>temp = (1,) #逗號不能省略
4.2更新和刪除元組
直接在同一個元組上更新是不可行的,但可以通過拷貝現有的元組片段構造一個新的元組的方式解決:
>>>tuple1 = (1,2,4)
>>>tuple1 = tuple1[:2] + (3,) + tuple1[2:]
>>>print(tuple1)
(1, 2, 3, 4)
可以用del去刪除整個元組,但很少使用,因為Python的回收機制會在這個元組不再被使用時自動刪除。
5字串
在C語言中,字元和字串是兩個不同的概念。但是Python並沒有字元這個型別,在Python看來所謂字元,就是長度為1的字串。訪問字串其中一個字元:
>>>str1 = "I love fishc.com"
>>>print(str1[5])
>>>print(str1[:6])
e
I love
5.1字串內建方法
可以通過>>> dir(str)來檢視。下面介紹幾個常用的方法:
(1)casefold():將字串所有字元變為小寫
>>>str1 = "FishC"
>>>print(str1.casefold())
fishc
(2)count():查詢sub子字串出現的次數
>>>str1 = "AbcABCabCabcABCabc"
>>>print(str1.count('ab',0,15))
2
(3)find()和index():查詢某個字串在該字串中的位置
>>>str1 = "I love fishc.com"
>>>print(str1.find("fishc"))
>>>print(str1.find("good"))
>>>print(str1.index("fishc"))
>>>print(str1.index("good"))
7
-1
7
Traceback (most recent call last):
File "<ipython-input-65-d5f76c5e96d6>", line 1, in <module>
runfile('/home/liuyu/.config/spyder-py3/temp.py', wdir='/home/liuyu/.config/spyder-py3')
File "/home/liuyu/anaconda3/lib/python3.7/site-packages/spyder_kernels/customize/spydercustomize.py", line 668, in runfile
execfile(filename, namespace)
File "/home/liuyu/anaconda3/lib/python3.7/site-packages/spyder_kernels/customize/spydercustomize.py", line 108, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "/home/liuyu/.config/spyder-py3/temp.py", line 12, in <module>
print(str1.index("good"))
ValueError: substring not found
(4)join():以字串作為分隔符,插入到sub字串中所有的字元之間
>>>print('x'.join("Test"))
>>>print('_'.join("FishC"))
Txexsxt
F_i_s_h_C
程式設計師喜歡用join()來連線字串,因為當使用連線符號+去拼接大量的字串時是非常低效率的,因為涉及記憶體複製和垃圾回收操作。所以對於大量的字串拼接來說,使用join()方法的效率要高一些。
>>>print(' '.join(['I','love','fishc.com']))
I love fishc.com
5.2字串格式化
format():待補充
6序列
列表、元組和字串之間有很多共同點:
(1)都可以通過索引得到每一個元素
(2)預設索引值總是從0開始(當然靈活的Python還支援負數索引)
(3)可以通過分片的方法得到一個範圍內的元素的集合
(4)有很多共同的操作符(重複操作符、拼接操作符、成員關係操作符)
我們把它統稱為序列。
下面介紹一些關於序列的常用BIF(內建方法):
(1)list([iterable])
(2)tuple([iterable])
(3)str(obj)
(4)len(sub)
(5)max()
(6)min()
(7)sum()
(8)sorted()
(9)reversed()
(10)enumerate(iterable)
(11)zip()
7函式
7.1建立和呼叫函式
在Python中建立一個函式用def關鍵字,呼叫時直接寫出函式名加上小括號部分即可:
>>>def myFirstFuction():
print("這是我建立的第一個函式!")
>>>myFirstFuction()
這是我建立的第一個函式
7.2函式的引數
引數使得函式可以實現個性化,多個引數用逗號隔開:
>>>def myFirstFuction(name):
print(name + "是美女")
>>>myFirstFuction("我")
>>>myFirstFuction("你")
>>>def add(num1, num2):
print(num1 + num2)
>>>add(1,2)
我是美女
你是美女
3
(1)形參和實參
形參:函式建立和定義過程中小括號裡的引數。
實參:函式在被呼叫時傳遞進來的引數。
(2)關鍵字引數
普通的引數叫位置引數,通常在呼叫一個函式時,粗心的程式設計師很容易會搞亂位置引數的順序。有了關鍵字引數,就可以解決該問題:
>>>def saySomething(name, world):
print(name + '->' + world )
>>>saySomething("小甲魚", "讓程式設計改變世界")
>>>saySomething(world="讓程式設計改變世界", name="小甲魚")
小甲魚->讓程式設計改變世界
小甲魚->讓程式設計改變世界
關鍵詞引數其實就是在傳入實參時指定形參的變數名。
(3)預設引數
在定義時賦予了預設值的引數:
>>>def saySomething(name = "小甲魚", world = "讓程式設計改變世界"):
print(name + '->' + world )
>>>saySomething()
小甲魚->讓程式設計改變世界
(4)收集引數/可變引數
發明該機制的原因是函式的作者有時也不知道這個函式到底需要多少個引數,這時,僅需要在引數前邊加上星號(*)即可:
>>>def test(*params):
print("有%d個引數" % len(params))
print("第二個引數是:", params[1])
>>>test('F','i','s','h','C')
有5個引數
第二個引數是: i
如果在收集引數後還需要指定其它引數,在呼叫函式時就應該使用關鍵引數來指定:
>>>def test2(*params, extra):
print("收集引數是:",params)
print("位置引數是:",extra)
>>>test2(1,2,3,4,5,6,7,extra=8)
收集引數是: (1, 2, 3, 4, 5, 6, 7)
位置引數是: 8
(5)函式返回值
函式需要返回值時,只需要使用關鍵字return,後面跟著指定要返回的值:
>>>def add(num1, num2):
return num1+num2
>>>print(add(1, 2))
3
7.3內嵌函式和閉包
略
7.4lamda表示式
Python允許使用lamda關鍵字來建立匿名函式。
語法:基本語法是冒號(:)左邊放原函式的引數,可以有多個引數,用逗號(,)隔開即可。lambda語句實際上是返回一個函式物件,如果要對它進行使用,只需要進行簡單的賦值操作即可。
# 普通函式
>>>def add(x,y):
return x+y
>>>print(add(3,4))
# lambda表示式
>>>g = lambda x,y:x+y
>>>print(g(3,4))
7
7
7.5介紹兩個BIF:filter()和map()
略
7.6遞迴
略
8字典:當索引不好用時
字典包括:鍵(key)和值(value)。另外,字典在有些地方稱為雜湊(hash),有些地方稱為關係陣列。字典的踐必須獨一無二,而值可以取任何資料型別,但必須是不可變的(如字串、數和元組)。
8.1建立和訪問字典
使用dict函式建立:
dict0 = dict() # 傳一個空字典
print('dict0:', dict0)
dict1 = dict({'three': 3, 'four': 4}) # 傳一個字典
print('dict1:', dict1)
dict2 = dict(five=5, six=6) # 傳關鍵字
print('dict2:', dict2)
dict3 = dict([('seven', 7), ('eight', 8)]) # 傳一個包含一個或多個元祖的列表
print('dict3:', dict3)
dict5 = dict(zip(['eleven', 'twelve'], [11, 12])) # 傳一個zip()函式
print('dict5:', dict5)
dict0: {}
dict1: {'four': 4, 'three': 3}
dict2: {'five': 5, 'six': 6}
dict3: {'seven': 7, 'eight': 8}
dict5: {'twelve': 12, 'eleven': 11}
8.2各種內建方法
字典是Python中唯一的對映型別,字典不是序列。如果在序列中試圖為一個不存在的位置賦值時,會報錯;但是如果在字典中,會自動建立相應的鍵並新增對應的值進去。
(1)fromkeys()
用於建立並返回一個新字典。
(2)keys()、values()、items()
keys()用於返回字典中的鍵,values()用於返回字典中所有的值,items()返回字典中所有的鍵值對:
>>>dict1 = {}
>>>dict1 = dict1.fromkeys(range(32), "贊")
>>>print(dict1.keys())
>>>print(dict1.values())
>>>print(dict1.items())
dict_keys([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])
dict_values(['贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊', '贊'])
dict_items([(0, '贊'), (1, '贊'), (2, '贊'), (3, '贊'), (4, '贊'), (5, '贊'), (6, '贊'), (7, '贊'), (8, '贊'), (9, '贊'), (10, '贊'), (11, '贊'), (12, '贊'), (13, '贊'), (14, '贊'), (15, '贊'), (16, '贊'), (17, '贊'), (18, '贊'), (19, '贊'), (20, '贊'), (21, '贊'), (22, '贊'), (23, '贊'), (24, '贊'), (25, '贊'), (26, '贊'), (27, '贊'), (28, '贊'), (29, '贊'), (30, '贊'), (31, '贊')])
(3)get()
提供了更寬鬆的方式去訪問字典項,當鍵不存在時,get()方法並不會報錯,只是默默返回一個none,表示啥也沒找到:
>>>dict1 = {}
>>>dict1 = dict1.fromkeys(range(32), "贊")
>>>print(dict1.get(31))
>>>print(dict1.get(32))
贊
None
如果希望找不到資料時返回指定的值,那麼可以在第二個引數設定對應的預設返回值:
>>>dict1 = {}
>>>dict1 = dict1.fromkeys(range(32), "贊")
>>>print(dict1.get(31))
>>>print(dict1.get(32,"木有"))
贊
木有
如果需要清空一個字典,則使用clear()方法:
>>>dict1 = {}
>>>dict1 = dict1.fromkeys(range(32), "贊")
>>>dict1.clear()
>>>print(dict1)
{}
有的人可能會使用變數名賦值為一個空字典的方法來清空字典,這樣做存在一定的弊端。
(4)setdefault()
和get()方法類似,但是它在字典中找不到相應的鍵時會自動新增:
>>>a = {1:"one", 2:"two", 3:"three", 4:"four"}
>>>print(a.setdefault(3))
>>>a.setdefault(5)
>>>print(a)
three
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: None}
(5)copy()
複製字典:
>>>a = {1:"one", 2:"two", 3:"three"}
>>>b = a.copy()
>>>print(a)
>>>print(b)
>>>print(id(a))
>>>print(id(b))
{1: 'one', 2: 'two', 3: 'three'}
{1: 'one', 2: 'two', 3: 'three'}
1752517929864
1752517929936
(6)pop()和popitem()
pop()是給定鍵彈出對應的值,而popitem()彈出一個項:
>>>a = {1:"one", 2:"two", 3:"three", 4:"four"}
>>>a.pop(2)
>>>print(a)
>>>a.popitem()
>>>print(a)
{1: 'one', 3: 'three', 4: 'four'}
{1: 'one', 3: 'three'}
(7) update()
更新字典:
>>>a = {1:"one", 2:"two", 3:"three", 4:"five"}
>>>a.update({4:"four"})
>>>print(a)
{1: 'one', 2: 'two', 3: 'three', 4: 'four'}
9 集合:在我的世界裡,你就是唯一
集合和字典長得很像:
>>>num1 = {}
>>>print(type(num1))
>>>num2 = {1,2,3,4,5}
>>>print(type(num2))
<class 'dict'>
<class 'set'>
在Python3中,如果用大括號括起一堆數字但沒有體現對映關係,那麼認為是集合。
集合起的作用:唯一。
>>>num = {1,2,3,4,5,4,3,2,1}
>>>print(num)
{1, 2, 3, 4, 5}
集合會自動幫我們將重複的資料清理掉。注意:集合無序,即你不能試圖去索引集合中的某一個元素:
>>>num = {1,2,3,4,5}
>>>print(num[2])
Traceback (most recent call last):
File "D:/Project/untitled1/test.py", line 2, in <module>
print(num[2])
TypeError: 'set' object does not support indexing
9.1 建立集合
法1:直接將一堆元素用大括號({})括起來。
法2:使用set()。
>>>set1 = {1,2,3,2}
>>>set2 = set([1,2,3,2])
>>>print(set1 == set2)
True
若要求去除列表[1,2,3,4,5,5,3,1,0]中重複的元素,可以這樣寫:
>>>list1 = [1,2,3,4,5,5,3,1,0]
>>>list1 = list(set(list1))
>>>print(list1)
[0, 1, 2, 3, 4, 5]
注意:由於集合無序,這樣轉換之後不能保證原來的list的順序。
9.2 訪問集合
由於集合中元素無序,所以不能向序列那樣用下標來訪問,但是可以使用迭代將集合中的資料一個個讀取出來。
>>>set1 = {1,2,3,4,5,4,3,2,1,0}
>>>for each in set1:
>>> print(each, end=' ')
0 1 2 3 4 5
使用add()方法可以為集合新增元素,使用remove()方法可以刪除集合中已知的元素:
>>>set1 = {1,2,3,4,5,4,3,2,1,0}
>>>print(set1)
>>>set1.add(6)
>>>print(set1)
>>>set1.remove(0)
>>>print(set1)
{0, 1, 2, 3, 4, 5}
{0, 1, 2, 3, 4, 5, 6}
{1, 2, 3, 4, 5, 6}
9.3 不可變集合
有時希望集合中元素具有穩定性,即像元組一樣不能隨意增加或刪除集合中的元素,那麼我們可以定義不可變集合,使用frozenset()函式:
>>>set1 = frozenset({1,2,3,4,5,4,3,2,1,0})
>>>set1.add(6)
Traceback (most recent call last):
File "D:/Project/untitled1/test.py", line 3, in <module>
set1.add(6)
AttributeError: 'frozenset' object has no attribute 'add'
10 類和物件
10.1 物件=屬性+方法
如果將“烏龜”寫成程式碼,將會是:
class Turtle:
# Python中的類名約定以大寫字母開頭,函式名用小寫字母開頭,更容易區分
# 特徵的描述稱為屬性,在程式碼層面來看其實就是變數
color = 'green'
weight = 10
legs = 4
mouth = '大嘴'
#方法其實就是函式,通過呼叫這些函式來完成某些工作
def climb(self):
print("我正在很努力地向前爬...")
def run(self):
print("我正在飛快地向前跑...")
def sleep(self):
print("困了,睡了,晚安!")
以上程式碼定義了物件的特徵(屬性)和行為(方法),但還不是一個完整物件,將定義的這些稱為類(Class)。需要用類建立一個真正的物件,這個物件叫作這個類的一個例項(Instance),也叫例項物件(Instance Objects)。
建立一個物件:
>>>tt = Turtle()
呼叫物件裡的方法:
>>>tt.climb()
>>>tt.run()
我正在很努力地向前爬...
我正在飛快地向前跑...
10.2 self是什麼
Python的self其實就是C++的this指標。
由同一個類可以生成無數物件,當一個物件的方法被呼叫時,物件會將自身的引用作為第一個引數傳給該方法,那麼Python就知道需要操作哪個物件的方法了:
>>>class Ball:
def setName(self,name):
self.name = name
def myName(self):
print("我叫%s" %self.name)
>>>a = Ball()
>>>a.setName("小虎隊")
>>>b = Ball()
>>>b.setName("TFBoys")
>>>a.myName()
>>>b.myName()
我叫小虎隊
我叫TFBoys
10.3 __init__()構造方法
類似於C++中的建構函式,只要例項化一個物件,該方法就會在物件被建立時自動呼叫。
>>>class Potato:
def __init__(self, name):
self.name = name
def myName(self):
print("我叫%s" %self.name)
>>>p = Potato("土豆")
>>>p.myName()
我叫土豆
10.4 公有和私有
一般面向物件的程式語言都會區分公有和私有的資料型別,像C++用關鍵字public和private,但在Python中並無類似關鍵字來修飾。預設Python的物件屬性和方法都是公開的,可以直接通過點操作符(.)進行訪問。
為實現類似私有變數的特徵,Python內部採用一種叫name mangling(名字改編)的技術,只要在變數名或函式名前加上“__”兩個下劃線,則變數或函式就會成為私有的:
>>>class Person:
__name = "小甲魚"
>>>p = Person()
>>>p.__name
Traceback (most recent call last):
File "D:/Project/untitled1/test.py", line 4, in <module>
p.__name
AttributeError: 'Person' object has no attribute '__name'
這樣在外部將變數名隱藏,理論上如果要訪問,就需要從內部進行:
>>>class Person:
def __init__(self, name):
self.__name = name
def getName(self):
return self.__name
>>>p = Person("小甲魚")
>>>print(p.getName())
小甲魚
注意:Python目前的私有機制其實是偽私有,在外部你使用“_類名__變數名”即可訪問雙下橫線開頭的私有變量了:
>>>class Person:
def __init__(self, name):
self.__name = name
def getName(self):
return self.__name
>>>p = Person("小甲魚")
>>>print(p._Person__name)
小甲魚
10.5 繼承
對魚類細分:金魚(Goldfish)、鯉魚(Carp)、三文魚(Salmon)和鯊魚(Shark)。
繼承:
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 Carp(Fish):
pass
class Salmon(Fish):
pass
#上面幾個都是食物,食物不需要有個性,所以直接繼承Fsih類的全部屬性和方法即可
#下面定義鯊魚類,這個是吃貨,除了繼承Fish類的屬性和方法,還要新增一個吃的方法
class Shark(Fish):
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry == True:
print("我要吃")
self.hungry = False
else:
print("我太撐")
fish = Fish()
fish.move()
goldfish = Goldfish()
goldfish.move()
goldfish.move()
goldfish.move()
shark = Shark()
shark.eat()
shark.eat()
shark.move()
-----------------------------------------------------------------------------------------
我的位置是: 0 7
我的位置是: 2 6
我的位置是: 1 6
我的位置是: 0 6
我要吃
我太撐
shark.move()
File "D:/Project/untitled1/test.py", line 10, in move
self.x -= 1
AttributeError: 'Shark' object has no attribute 'x'
繼承語法:
class 類名 (被繼承的類)
被繼承的類稱為基類、父類或超類;繼承者稱為子類,一個子類可以繼承它的父類的任何屬性和方法。
奇怪!同樣是繼承於Fish類,為什麼金魚(goldfish)可以移動,而鯊魚(shark)一移動就報錯呢?
因為Shark物件沒有x屬性。原因:在Shark類中,重寫了魔法方法__init__,但新的__init__方法裡邊沒有初始化鯊魚的x座標和y座標,因此呼叫move方法會報錯。解決此問題的兩個方法:
(1)呼叫未繫結的父類方法
class Shark(Fish):
def __init__(self):
Fish.__init__(self)
self.hungry = True
def eat(self):
if self.hungry == True:
print("我要吃")
self.hungry = False
else:
print("我太撐")
(2)使用super函式
class Shark(Fish):
def __init__(self):
super().__init__()
self.hungry = True
def eat(self):
if self.hungry == True:
print("我要吃")
self.hungry = False
else:
print("我太撐")
不需要明確給出任何基類的名字,super會自動找出所有基類以及對應的方法。這也意味著如果需要改變類繼承關係,只要改變class語句裡的父類即可,不必在大量程式碼中去修改所有被繼承的方法。
10.6 多重繼承
class 類名 (父類1, 父類2, 父類3,……)
多重繼承易造成程式碼混亂,儘量避免使用。
10.7 組合
學習了繼承和多重繼承的概念,但聽到大牛們說不到必要時不使用多重繼承。哎呀,這可讓大家煩死了,就像上回我們有了烏龜類、魚類,現在要求定義一個類,叫水池,水池裡要有烏龜和魚。用多重繼承就顯得很奇怪,因為水池和烏龜,魚是不同物種,那要怎樣才能把它們組合成一個水池的類呢?
在Python裡很簡單,直接把需要的類放進去例項化就可以了,這叫組合:
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):
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條!
10.8 一些相關的BIF
下面介紹與類和物件相關的一些BIF(內建函式)。
(1)issubclass(class, classinfo)
* 如果class是classinfo的一個子類,則返回True,否則返回False;
* classinfo可以是類物件組成的元組,只要class是其中任何一個候選類的子類,則返回True;
* 一個類被認為是其自身的子類;
* 在其他情況下,會丟擲一個TypeError異常。
(2)isinstance(object, classinfo)
* 如果object是classinfo的例項物件,則返回True,否則返回False;
* 如果object是classinfo子類的一個例項,也返回True;
* 如果第一個引數不是物件,永遠返回False;
* classinfo可以是類物件組成的元組,只要object是其中任何一個候選物件的例項,則返回True;
* 如果第2個引數不是類或由類物件組成的元組,會丟擲TypeError異常。
(3)
hasattr(object, name):測試一個物件裡是否有指定的屬性;
getattr(object, name [, default]):返回物件指定的屬性值,若指定的屬性值不存在,則返回default的值;若未設定default,則丟擲ArttributeError異常;
setattr(object, name, value):設定物件中制定屬性的值,若指定屬性值不存在,則會新建屬性並賦值。
delattr(object, name):刪除物件中指定的屬性,若屬性不存在,則丟擲ArttributeError異常。
class C:
def __init__(self, x=0):
self.x = x
c1 = C()
print(hasattr(c1, 'x')) #注意,屬性名要用引號括起來
print(getattr(c1, 'x'))
setattr(c1, 'y', 'FishC')
print(getattr(c1, 'y'))
delattr(c1,'y')
True
0
FishC
11 模組
11.1 模組就是程式
容器:例如列表、元組、字串、字典等,這些是對資料的封裝;
函式:對語句的封裝;
類:對方法和屬性的封裝,也就是對函式和資料的封裝;
模組:就是程式。平時寫的任何程式碼,儲存的每一個.py結尾的檔案,都是一個獨立的模組。
11.2 名稱空間
在Python中,每個模組都會維護一個獨立的名稱空間,我們應該將模組名加上,才能夠使用模組中的函式。
11.3 匯入模組
下面介紹幾種匯入模組的方法:
(1)import模組名
在呼叫模組中函式時,需要加上模組的名稱空間:
# p13_1.py
def c2f(cel):
fah = cel*1.8+32
return fah
def f2c(fah):
cel = (fash-32)/1.8
return cel
# 再寫一個檔案匯入剛才的模組
#p13_2.py
import p13_1
print("32攝氏度=%.2f華氏度" %p13_1.c2f(32))
print("99華氏度=%.2f攝氏度" %p13_1.f2c(99))
(2)from 模組名 import 函式名
該法會直接將模組的名稱空間覆蓋進來,所以呼叫時不需加上名稱空間:
# p13_1.py
def c2f(cel):
fah = cel*1.8+32
return fah
def f2c(fah):
cel = (fash-32)/1.8
return cel
#p13_3.py
from p13_1 import c2f,f2c
print("32攝氏度=%.2f華氏度" %c2f(32))
print("99華氏度=%.2f攝氏度" %f2c(99))
還可以使用萬用字元星號(*)來匯入模組中所有的名稱空間,但是強烈要求不要使用該法,因為這樣會使得名稱空間的優勢蕩然無存,一不小心還會陷入名字混亂的局面:
from p13_1 import *
(3)import 模組名 as 新名字
推薦該法。給匯入的名稱空間替換一個新名字:
# p13_1.py
def c2f(cel):
fah = cel*1.8+32
return fah
def f2c(fah):
cel = (fash-32)/1.8
return cel
#p13_4.py
import p13_1 as tc
print("32攝氏度=%.2f華氏度" %tc.c2f(32))
print("99華氏度=%.2f攝氏度" %tc.f2c(99))
11.4 __name__ = '__main__'
# 1.py
def c2f(cel):
fah = cel*1.8+32
return fah
def f2c(fah):
cel = (fash-32)/1.8
return cel
def test():
print("測試,0攝氏度=%.2f華氏度" % c2f(0))
print("測試,0華氏度=%.2f攝氏度" % f2c(0))
if __name__ == '__main__' #確保只有單獨執行1.py時才會執行test()函式
test()
11.5 搜尋路徑
Python模組的匯入需要一個路徑搜尋的過程。而這個搜尋路徑,就是一組目錄,可以通過sys模組中的path變數顯示出來:
>>>import sys
>>>print(sys.path)
['D:\\Project\\untitled1', 'D:\\Project\\untitled1', 'D:\\Anaconda\\envs\\GameServer\\python36.zip', 'D:\\Anaconda\\envs\\GameServer\\DLLs', 'D:\\Anaconda\\envs\\GameServer\\lib', 'D:\\Anaconda\\envs\\GameServer', 'D:\\Anaconda\\envs\\GameServer\\lib\\site-packages']
site=packages目錄是最佳的目錄選擇。
將自定義模組所在的位置新增到搜尋路徑中:
sys.path.append("路徑")
11.6 包
在實際的開發中,一個大型系統有成千上萬的Python模組,單單用模組定義功能顯然不夠,如果都放在一起顯然不好管理並且有命名衝突的可能,因此出現了包。就是將模組分門別類存放於不同資料夾中,然後把 各個資料夾的位置告訴Python。
建立一個包的操作:
(1)建立一個資料夾,用於存放相關的模組,資料夾名字即包的名字;
(2)在資料夾中建立一個__init__.py的模組檔案,內容可為空;
(3)將相關模組放入資料夾。
接下來就是在程式中匯入包的模組(包名.模組名):
# 1.py
def c2f(cel):
fah = cel*1.8+32
return fah
def f2c(fah):
cel = (fash-32)/1.8
return cel
# 2.py
#將1.py放在資料夾M中
import M.1 as tc
print("32攝氏度=%.2f華氏度" %tc.c2f(32))
print("99華氏度=%.2f攝氏度" %tc.f2c(99))