前言(認識Python)
既然學習 Python,那麼至少得了解下這門語言,知道 Python 程式碼執行過程吧。Python 的歷史有興趣的百度百科下就有,這個不多說了。
1、我們先來了解下什麼是解釋型語言和編譯型語言?
計算機是不能夠識別高階語言的,所以當我們執行一個高階語言程式的時候,就需要一個“翻譯機”來從事把高階語言轉變成計算機能讀懂的機器語言的過程。這個過程分成兩類,第一種是編譯,第二種是解釋。
編譯型語言在程式執行之前,先會通過編譯器對程式執行一個編譯的過程,把程式轉變成機器語言。執行時就不需要翻譯,而直接執行就可以了。最典型的例子就是 C 語言。
解釋型語言就沒有這個編譯的過程,而是在程式執行的時候,通過直譯器對程式逐行作出解釋,然後直接執行,最典型的例子是 Ruby。
通過以上的例子,我們可以來總結一下解釋型語言和編譯型語言的優缺點,因為編譯型語言在程式執行之前就已經對程式做出了“翻譯”,所以在執行時就少掉了“翻譯”的過程,所以效率比較高。但是我們也不能一概而論,一些解釋型語言也可以通過直譯器的優化來在對程式做出翻譯時對整個程式做出優化,從而在效率上超過編譯型語言。
此外,隨著 Java 等基於虛擬機器的語言的興起,我們又不能把語言純粹地分成解釋型和編譯型這兩種。用 Java 來舉例,Java 首先是通過編譯器編譯成位元組碼檔案,然後在執行時通過直譯器給解釋成機器檔案。所以我們說 Java 是一種先編譯後解釋的語言。再換成 C#,C# 首先是通過編譯器將 C# 檔案編譯成 IL 檔案,然後在通過 CLR 將 IL 檔案編譯成機器檔案。所以我們說 C# 是一門純編譯語言,但是 C# 是一門需要二次編譯的語言。同理也可等效運用到基於 .NET 平臺上的其他語言。
2、那麼 Python 到底是什麼?
其實 Python 和 Java、C# 一樣,也是一門基於虛擬機器的語言,我們先來從表面上簡單地瞭解一下 Python 程式的執行過程。
當我們在命令列中輸入
python hello.py
時,其實是啟用了 Python 的“直譯器”,告訴“直譯器”:你要開始工作了。可是在“解釋”之前,其實執行的第一項工作和 Java 一樣,是編譯。熟悉 Java 的讀者可以想一下我們在命令列中如何執行一個 Java 的程式:
javac hello.java java hello 複製程式碼
只是我們在用 Eclipse 之類的 IDE 時,將這兩部給融合成了一部而已。其實 Python 也一樣,當我們執行
python hello.py
時,它也一樣執行了這麼一個過程,所以我們應該這樣來描述 Python,Python 是一門先編譯後解釋的語言。
3、簡述 Python 的執行過程
在說這個問題之前,我們先來說兩個概念,PyCodeObject 和 pyc 檔案。
我們在硬碟上看到的 pyc 自然不必多說,而其實 PyCodeObject 則是 Python 編譯器真正編譯成的結果。我們先簡單知道就可以了,繼續向下看。
當 Python 程式執行時,編譯的結果則是儲存在位於記憶體中的 PyCodeObject 中,當 Python 程式執行結束時,Python 直譯器則將 PyCodeObject 寫回到 pyc 檔案中。
當 Python 程式第二次執行時,首先程式會在硬碟中尋找 pyc 檔案,如果找到,則直接載入,否則就重複上面的過程。
所以我們應該這樣來定位 PyCodeObject 和 pyc 檔案,我們說 pyc 檔案其實是 PyCodeObject 的一種持久化儲存方式。
更詳細內容參考:說說Python程式的執行過程
最後:
-
“人生苦短,我用Python”
-
Python 的設計哲學是“優雅”、“明確”、“簡單”。
一、變數和字串
首先:Python 每個語句結束可以不寫分號 ;
, 如 print(`hello`)
列印 hello
1.1 變數
有過程式設計基礎的話,變數就不用多說了。
變數的命名法:
- 駝峰式命名法
- 帕斯卡命名法
1.2 字串
1、基本介紹
單引號 ` `
或者雙引號 " "
都可以,再或者 ``` ```
三個引號,其中三個引號被用於過於長段的文字或者是說明,只要是三引號不完你就可以隨意換行寫下文字。
①字串直接能相加,如:
str1 = `hi`
str2 = `hello`
print(str1 + str2)
複製程式碼
執行結果:
hi jaybo
複製程式碼
②字串相乘,如:
string = `bang!`
total = string * 3
複製程式碼
列印 total 結果:
bang!bang!bang!
複製程式碼
2、字串的分片與索引
字串可以通過 string[x]
的方式進行索引、分片。
字串的分片實際可以看作是從字串中找出來你要擷取的東西,複製出來一小段你要的長度,儲存在另一個地方,而不會對字串這個原始檔改動。分片獲得的每個字串可以看作是原字串的一個副本。
先看下面這段程式碼:
name = `My name is Mike`
print(name[0])
`M`
print(name[-4])
`M`
print(name[11:14]) # from 11th to 14th, 14th one is excluded
`Mik`
print(name[11:15]) # from 11th to 15th, 15th one is excluded
`Mike`
print(name[5:])
`me is Mike`
print(name[:5])
`My na`
複製程式碼
如果感到困惑話,可以對照如下表格理解和分析:
:
兩邊分別代表著字串的分割從哪裡開始,併到哪裡結束。以
name[11:14]
為例,擷取的編號從第11個字元開始,到位置為14但不包含第14個字元結束。而像name[5:]
這樣的寫法代表著從編號為5的字元到結束的字串分片。相反,name[:5]
則代表著從編號為0的字元開始到編號為5但包含第5個字元分片。可能容易搞混,可以想象成第一種是從5到最後面,程式設計師懶得數有多少個所以就省略地寫,第二種是從最前面到5,同樣懶得寫0,所以就寫成了[:5]
。
3、字串的方法
-
replace 方法:第一個參數列示被替代部分,第二個參數列示替代成怎樣的字串。
-
字串填空,如:
city = input("write the name of city:"") url = "http://apistore.baidu.com/mri.../weather?citypiny={}.format(city) 複製程式碼
4、問題
問題1:
num = 1
string = `1`
print(num + string)
複製程式碼
上面程式碼將出錯?
解釋:整數型不能和字串直接相加。可以先把該字串轉為整數型,再相加,即 int(string)
num = 1
string = `1`
print(num + int(string))
複製程式碼
二、函式
舉些你可能已經使用過的函式例子:
判斷資料型別:type(str)
字串型別資料轉為整數型:int(str)
...
複製程式碼
通過觀察規律不難發現,Python 中所謂的使用函式就是把你要處理的物件放到一個名字後面的括號就可以了。簡單的來說,函式就是這麼使用,可以往裡面塞東西得到處理結果。這樣的函式在 Python 中還有這些:
以 Python3.5 版本為例,一個有 68 個這樣的函式,它們被稱為內建函式。這裡內建的是指這些函式為安裝好了 Python 就可以使用。
2.1 函式格式
定義函式的格式:
其中,def
和 return
為關鍵字。
注意: 函式縮排後面的語句被稱為是語句塊,縮排是為了表名語句的邏輯與從屬關係。縮排這個問題不能忽視,否則會導致程式碼無法成功執行,這裡需要特別注意。
2.2 函式引數
①位置引數,舉例,看程式碼:
def trapezoid_area(base_up, base_down, height):
return 1/2 * (base_up + base_down) * height
複製程式碼
接下來我們開始呼叫該函式:
trapezoid_area(1,2,3)
複製程式碼
不難看出,填入的引數1,2,3分別對應著引數 base_up,base_down 和 height。這種傳入引數的方式被稱作為位置引數。
②關鍵詞引數:在函式呼叫的時候,將每個引數名稱後面賦予一個我們想要傳入的值,如呼叫 fun1 函式時候:fun1(a=1, b=2, c=3)
。
看下圖:
- 第一行的函式引數按照反序傳入,因為是關鍵詞引數,所以並不影響函式正常運作;
- 第二行的函式引數反序傳入,但是到了第三個卻變成了位置函式,遺憾的是這種方式是錯誤的語法,因為如果按照位置來傳入,最後一個應該是引數 height 的位置。但是前面 height 已經按照名稱傳入了值3,所以是衝突的。
- 第三行的函式引數正序傳入,前兩個是以關鍵字的方式傳入,最後一個以位置引數傳入,但是位置引數不能再關鍵詞引數後面,所以是錯誤的。
- 第四行的函式引數正序傳入,前兩個是以位置的方式傳入,最後一個以關鍵字引數傳入,這個函式是可以正常執行的。
③不定長引數
有時我們在設計函式介面的時候,可會需要可變長的引數。也就是說,我們事先無法確定傳入的引數個數。
Python 提供了一種元組的方式來接受沒有直接定義的引數。這種方式在引數前邊加星號 *
。如果在函式呼叫時沒有指定引數,它就是一個空元組。我們也可以不向函式傳遞未命名的變數。例如:
def print_user_info( name , age , sex = `男` , * hobby):
# 列印使用者資訊
print(`暱稱:{}`.format(name) , end = ` `)
print(`年齡:{}`.format(age) , end = ` `)
print(`性別:{}`.format(sex) ,end = ` ` )
print(`愛好:{}`.format(hobby))
return;
# 呼叫 print_user_info 函式
print_user_info( `小明` , 25, `男`, `打籃球`,`打羽毛球`,`跑步`)
複製程式碼
輸出的結果:
暱稱:小明 年齡:25 性別:男 愛好:(`打籃球`, `打羽毛球`, `跑步`)
複製程式碼
通過輸出的結果可以知道,* hobby
是可變引數,且 hobby 其實就是一個 tuple (元祖)。
可變長引數也支援關鍵引數,沒有被定義的關鍵引數會被放到一個字典裡。這種方式即是在引數前邊加 **
,更改上面的示例如下:
def print_user_info( name , age , sex = `男` , ** hobby ):
# 列印使用者資訊
print(`暱稱:{}`.format(name) , end = ` `)
print(`年齡:{}`.format(age) , end = ` `)
print(`性別:{}`.format(sex) ,end = ` ` )
print(`愛好:{}`.format(hobby))
return;
# 呼叫 print_user_info 函式
print_user_info( name = `小明` , age = 25 , sex = `男`, hobby = (`打籃球`,`打羽毛球`,`跑步`))
複製程式碼
輸出的結果:
暱稱:小明 年齡:24 性別:男 愛好:{`hobby`: (`打籃球`, `打羽毛球`, `跑步`)}
複製程式碼
通過對比上面的例子和這個例子,可以知道,* hobby
是可變引數,且 hobby 其實就是一個 tuple (元祖),** hobby
是關鍵字引數,且 hobby 就是一個 dict (字典)。
④ 只接受關鍵字引數
關鍵字引數使用起來簡單,不容易引數出錯,那麼有些時候,我們定義的函式希望某些引數強制使用關鍵字引數傳遞,這時候該怎麼辦呢?將強制關鍵字引數放到某個*
引數或者單個*
後面就能達到這種效果,比如:
def print_user_info( name , *, age, sex = `男` ):
# 列印使用者資訊
print(`暱稱:{}`.format(name) , end = ` `)
print(`年齡:{}`.format(age) , end = ` `)
print(`性別:{}`.format(sex))
return;
# 呼叫 print_user_info 函式
print_user_info( name = `小明` ,age = 25 , sex = `男` )
# 這種寫法會報錯,因為 age ,sex 這兩個引數強制使用關鍵字引數
#print_user_info( `小明` , 25 , `男` )
print_user_info(`小明`,age=`22`,sex=`男`)
複製程式碼
通過例子可以看,如果 age
, sex
不適用關鍵字引數是會報錯的。
2.3 匿名函式
有沒有想過定義一個很短的回撥函式,但又不想用 def
的形式去寫一個那麼長的函式,那麼有沒有快捷方式呢?
——答案是有的。
Python 使用 lambda 來建立匿名函式,也就是不再使用 def
語句這樣標準的形式定義一個函式。
匿名函式主要有以下特點:
- lambda 只是一個表示式,函式體比
def
簡單很多。 - lambda 的主體是一個表示式,而不是一個程式碼塊。僅僅能在 lambda 表示式中封裝有限的邏輯進去。
- lambda 函式擁有自己的名稱空間,且不能訪問自有引數列表之外或全域性名稱空間裡的引數。
基本語法:lambda [arg1 [,arg2,.....argn]]:expression
示例:
sum = lambda num1 , num2 : num1 + num2;
print( sum( 1 , 2 ) )
複製程式碼
輸出的結果: 3
注意:儘管 lambda 表示式允許你定義簡單函式,但是它的使用是有限制的。 你只能指定單個表示式,它的值就是最後的返回值。也就是說不能包含其他的語言特性了, 包括多個語句、條件表示式、迭代以及異常處理等等。
匿名函式中,有一個特別需要注意的問題,比如,把上面的例子改一下:
num2 = 100
sum1 = lambda num1 : num1 + num2 ;
num2 = 10000
sum2 = lambda num1 : num1 + num2 ;
print( sum1( 1 ) )
print( sum2( 1 ) )
複製程式碼
你會認為輸出什麼呢?第一個輸出是 101,第二個是 10001,結果不是的,輸出的結果是這樣:
10001
10001
複製程式碼
這主要在於 lambda 表示式中的 num2 是一個自由變數,在執行時繫結值,而不是定義時就繫結,這跟函式的預設值引數定義是不同的。所以建議還是遇到這種情況還是使用第一種解法。
三、迴圈與判斷
3.1 布林表示式和判斷
Python 中的布林型別值:True
和 Flase
其中,注意這兩個都是首字母大寫。
但凡能夠產生一個布林值的表示式為布林表示式:
1 > 2 # False
1 < 2 <3 # True
42 != `42` # True
`Name` == `name` # False
`M` in `Magic` # True
number = 12
number is 12 # True
複製程式碼
注1:不同型別的物件不能使用
<
、>
、<=
、=>
進行比較,卻可以使用==
和!=
。注2:浮點型別和整數型別雖然是不同型別,但不影響比較運算。還有,不等於
!=
可以寫作<>
。
話說,布林型別可以比較嗎?如:True > Flase
,回答是可以的,Ture
和 Flase
對於計算機就像是 1 和 0 一樣,所以結果是真,即True
。
3.2 條件控制
定義格式:
用一句話該結構作用:如果…條件是成立的,就做…;反之,就做…
所謂條件成立,指的是返回值為
True
的布林表示式。
3.3 迴圈
①for 迴圈
把 for 迴圈所的事情概括成一句話就是:於…其中的每一個元素,做…事情。
列印九九乘法表:
for i in range(1, 10):
for j in range(1, i+1):
print(`{}x{}={} `.format(i, j, i*j), end=``)
print()
複製程式碼
執行結果:
1x1=1
2x1=2 2x2=4
3x1=3 3x2=6 3x3=9
4x1=4 4x2=8 4x3=12 4x4=16
5x1=5 5x2=10 5x3=15 5x4=20 5x5=25
6x1=6 6x2=12 6x3=18 6x4=24 6x5=30 6x6=36
7x1=7 7x2=14 7x3=21 7x4=28 7x5=35 7x6=42 7x7=49
8x1=8 8x2=16 8x3=24 8x4=32 8x5=40 8x6=48 8x7=56 8x8=64
9x1=9 9x2=18 9x3=27 9x4=36 9x5=45 9x6=54 9x7=63 9x8=72 9x9=81
複製程式碼
②while 迴圈
總結:只要…條件一成立,就一直做…
在迴圈過程中,可以使用 break
跳過迴圈,使用 continue
跳過該次迴圈。
在 Python 的 while 迴圈中,可以使用 else 語句,while … else 在迴圈條件為 false 時執行 else 語句塊。如:
count = 0
while count < 3:
print (count)
count = count + 1
else:
print (count)
複製程式碼
執行結果:
0
1
2
3
複製程式碼
有 while … else 語句,當然也有 for … else 語句,for 中的語句和普通的沒有區別,else 中的語句會在迴圈正常執行完(即 for 不是通過 break 跳出而中斷的)的情況下執行,while … else 也是一樣。如:
for num in range(10,20): # 迭代 10 到 20 之間的數字
for i in range(2,num): # 根據因子迭代
if num%i == 0: # 確定第一個因子
j=num/i # 計算第二個因子
print (`%d 是一個合數` % num)
break # 跳出當前迴圈
else: # 迴圈的 else 部分
print (`%d 是一個質數` % num)
複製程式碼
執行結果:
10 是一個合數
11 是一個質數
12 是一個合數
13 是一個質數
14 是一個合數
15 是一個合數
16 是一個合數
17 是一個質數
18 是一個合數
19 是一個質數
複製程式碼
四、資料結構
Python 有四種資料結構,分別是:列表、字典、元組、集合。我們先從整體上認識一下這四種資料結構:
list = [val1,val2,val3,val4] #列表
dict = {key1:val1,key2:val2} #字典
tuple = (val1,val2,val3,val4) #元組
set = {val1,val2,val3,val4} #集合
複製程式碼
4.1 列表(List)
-
列表中的每個元素都是可變的;
-
列表中的元素是有序的,也就是說每個元素都有一個位置;
-
列表中可以容納 Python 中的任何物件。如下:
all_in_list = [ 1, #整數 1.0, #浮點數 `a word`, #字串 print(1), #函式 True, #布林值 [1,2], #列表中套列表 (1,2), #元祖 {`key`:`value`} #字典 ] 複製程式碼
另外,對於資料的操作,最常見的為增刪改查。在此就省略了,網上找下相應函式練習下即可。
4.2 字典(Dict)
-
字典中資料必須是以鍵值對的形式出現的;
-
邏輯上講,鍵是不能重複的;
-
字典中的鍵(key)是不可變的,也就是無法修改的,而值(value)是可變的,可修改的,可以是任何物件。
下面是個例子:
NASDAQ_code = { `BIDU`:`Baidu`, `SINA`:`Sina`, `YOKU`:`Youku` } 複製程式碼
一個字典中鍵與值並不能脫離對方而存在,如果你寫成了 {`BIDU`:}
會引發一個語法錯誤:invalid syntax
。
如果試著將一個可變(mutable)的元素作為 key 來構建字典,比如列表:key_test = {[]:`a Test`}
,則會報一個錯:unhashable type:`list`
。
同時字典中的鍵值不會重複,即便你這麼做,相同的鍵值也只能出現一次:a = {`key`:123,`key`:123}
。
增刪改查操作,在此省略了。
備註:
- 列表中用來新增多個元素的方法為
extend
,在字典中新增多個元素的方法為update()
- 字典是不能切片的,即這樣的寫法是錯誤的:
chart[1:4]
4.3 元組(Tuple)
元組可以理解為一個穩固版的列表,因為元組是不可以修改的,因此在列表中的存在的方法均不可以使用在元組上,但是元組是可以被檢視索引的,方式和列表一樣。
letters = (`a, `b`, `c`, `d`)
letters[0]
複製程式碼
相關的操作找程式碼練習下即可。
4.4 集合(Set)
集合則更接近數學上集合的概念。每一個集合中是的元素是無序的、不重複的任意物件,我們可以通過集合去判斷資料的從屬關係,有時還可以通過集合把資料結構中重複的元素減掉。
集合不能被切片也不能被索引,除了做集合運算之外,集合元素可以被新增還有刪除:
a_set = {1,2,3,4}
a_set.add(5)
a_set.discard(5)
複製程式碼
4.5 資料結構的一些技巧
4.5.1 多重迴圈
如下:
程式碼演示:
for a, b in zip(num, str):
print(b, `is`, a)
複製程式碼
4.5.2 推導式
列表推導式的用法很好理解,可以簡單地看成兩部分。如下圖:
紅色虛線後面的是我們熟悉的 for 迴圈的表示式,而虛線前面的可以認為是我們想要放在列表中的元素。
程式碼演示:
a = []
for i in range(1, 11):
a.append(i)
複製程式碼
可以換成列表解析的方式來寫:
b = [i for i in range(1, 11)]
複製程式碼
列表解析式不僅方便,並且在執行效率上要遠遠勝過前者。
五、類的理解
5.1 類的介紹
類的定義:
class CocaCola:
formula = [`caffeine`,`sugar`,`water`,`soda`]
複製程式碼
使用 class
來定義一個類,就如同建立函式時使用的 def
定義一個函式一樣簡單。如上你可以看到定義了名為 CocaCola 的類,接著在縮排的地方有一個裝載著列表的變數的 formula
,這個在類裡面定義的變數就是類的變數,而類的變數有一個專有的術語,我們稱之為類的屬性。
類的屬性:
- 類變數
- 方法
①類的例項化:
coke_for_me = CocaCola()
coke_for_you = CocaCola()
複製程式碼
②類變數屬性的引用:CocaCola.formula
、coke_for_me.formula
類方法的使用:
class CocaCola:
formula = [`caffeine`,`sugar`,`water`,`soda`]
def drink(self):
print(`Energy!`)
coke = CocaCola()
coke.drink()
複製程式碼
結果:
Energy!
複製程式碼
5.2 self
我想很多人會有關注到這個奇怪的地方——似乎沒有派上任何用場的self
引數。我們來說明下原理,其實很簡單,我們修改下上面的程式碼:
class CocaCola:
formula = [`caffeine`,`sugar`,`water`,`soda`]
def drink(coke): # 把self改為coke
print(`Energy!`)
coke = CocaCola()
coke.drink()
複製程式碼
結果:
Energy!
複製程式碼
怎麼樣,有些頭緒了吧!這個引數其實就是被建立的例項本身。也就是將一個個物件作為引數放入函式括號內,再進一步說,一旦一個類被例項化,那麼我們其實可以使用和與我們使用函式相似的方式:
coke = CocaCola
coke.drink() == CocaCola.drink(coke) #左右兩邊的寫法完全一致
複製程式碼
被例項化的物件會被編譯器默默地傳入後面方法的括號中,作為第一個引數。上面兩個方法是一樣的,但我們更多地會寫成前面那種形式。其實self
這個引數名稱是可以隨意修改的(編譯器並不會因此而報錯)。
和函式一樣,類的方法也能有屬於自己的引數,如下:
class CocaCola:
formula = [`caffeine`,`sugar`,`water`,`soda`]
def drink(self,how_much):
if how_much == `a sip`:
print(`Cool~`)
elif how_much == `whole bottle’:
print(`Headache!`)
ice_coke = CocaCola()
ice_coke.drink(`a sip`)
複製程式碼
結果:
Cool~
複製程式碼
5.3 魔術方法
Python 的類中存在一些方法,被稱為「魔術方法」,_init_()
就是其中之一。
class CocaCola():
formula = [`caffeine`,`sugar`,`water`,`soda`]
def __init__(self):
self.local_logo = `可口可樂`
def drink(self):
print(`Energy!`)
coke = CocaCola()
print(coke.local_logo)
複製程式碼
作用:在建立例項之前,它做了很多事情。說直白點,意味著即使你在建立例項的時候不去引用 init_()
方法,其中的語句也會先被自動的執行。這給類的使用提供了極大的靈活性。
class CocaCola:
formula = [`caffeine`,`sugar`,`water`,`soda`]
def __init__(self,logo_name):
self.local_logo = logo_name
def drink(self):
print(`Energy!`)
coke = CocaCola(`ݢݗݢԔ`)
coke.local_logo
>>> 可口可樂
複製程式碼
有過物件導向程式設計經驗很好理解了,也就是很多物件導向語言中的「建構函式」。
5.4 類的繼承
如下程式碼:
class CaffeineFree(CocaCola):
caffeine = 0
ingredients = [
`High Fructose Corn Syrup`,
`Carbonated Water`,
`Phosphoric Acid`,
`Natural Flavors`,
`Caramel Color`,
]
coke_a = CaffeineFree(`Cocacola-FREE`)
coke_a.drink()
複製程式碼
表示 CaffeineFree 繼承了 CocaCola 類。
類中的變數和方法可以被子類繼承,但如需有特殊的改動也可以進行覆蓋。
Q1:類屬性如果被重新賦值,是否會影響到類屬性的引用?
class TestA():
attr = 1
obj_a = TestA()
TestA.attr = 24
print(obj_a.attr)
>>> 結果:24
複製程式碼
A1:會影響。
Q2:例項屬性如果被重新賦值,是否會影響到類屬性的引用?
class TestA:
attr = 1
obj_a = TestA()
obj_b = TestA()
obj_a.attr = 42
print(obj_b.attr)
>>> 結果:1
複製程式碼
A2:不會影響。
Q3:類屬性例項屬性具有相同的名稱,那麼.
後面引用的將會是什麼?
class TestA():
attr =1
def __init__(self):
self.attr = 24
obj_a = TestA()
print(obj_a.attr)
>>> 結果:24
複製程式碼
A3:類屬性賦值後的值。
總結:如圖所示,Python 中屬性的引用機制是自外而內的,當你建立了一個例項之後,準備開始引用屬性,這時候編譯器會先搜尋該例項是否擁有該屬性,如果有,則引用;如果沒有,將搜尋這個例項所屬的類是否有這個屬性,如果有,則引用,沒有那就只能報錯了。
六、使用第三方庫
6.1 安裝自己的庫
我們一般使用 pip
來進行第三方庫的安裝,那麼自己的庫要怎麼安裝呢?當然可以把自己的庫提交到 pip
上,但是還要新增一定量的程式碼和必要的檔案才行,在這裡我們使用一個更簡單的方法:
- 找到你的 Python 安裝目錄,找到下面的
site-packages
資料夾; - 記住你的檔名,因為它將作為引用時的名稱,然後將你寫的 py 檔案放進去。
這個資料夾應該有你所安裝的所有第三方庫。如果你並不清楚你的安裝路徑,可以嘗試使用如下方式搞清楚它究竟在哪裡:
import sys
print(sys.path)
複製程式碼
列印出來的會是一個列表,列表中的第四個將是你的庫安裝路徑所在,因此你也可以直接這麼做:
import sys
print(sys.path[3])
複製程式碼
6.2 安裝第三方庫
令人驚歎的第三方庫
如果用手機來比喻程式語言,那麼 Python 是一款智慧機。正如含量的手機應用出現在 iOS、Android 平臺上,同樣有各種各樣的第三方庫為 Python 開發者提供了極大的便利。
當你想要搭建網站時,可以選擇功能全面的 Django、輕量的 Flask 等 web 框架;當你想寫一個小遊戲的時候,可以使用 PyGame 框架;當你想做一個 爬蟲時,可以使用 Scrapy 框架;當你想做資料統計分析時,可以使用 Pandas 資料框架……這麼多豐富的資源可以幫助我們高效快捷地做到想做的事,就不需要再重複造輪子了。
那麼如何根據自己的需求找到相應的庫呢?可以到 awesome-python.com 這個網站上按照分類去尋找,上面收錄了比較全的第三方庫。比如想要找爬出方面的庫時,檢視 Web Crawling 這個分類,就能看到相應的第三方庫的網站與簡介,可以進入庫的網站檢視更詳細的介紹,並確認這個庫支援的是 Python 2 還是 Python 3,不過絕大多數常用庫已經都支援了這兩者。另外,你也可以直接通過搜尋引擎尋找。
安裝第三方庫方式:
①最簡單的方式:在 PyCharm 中安裝
- 在 PyCharm 的選單中選擇:File –> Default Setting
- 搜尋 project interpreter,選擇當前 python 版本,點選“+”新增庫
- 輸入庫的名稱,勾選,並點選 Install Package
在安裝成功後, PyCharm 會有成功提示。也可以在 project interpreter 這個介面中檢視安裝了哪些庫,點“-”號就可以解除安裝不再需要的庫。
②最直接的方式:在終端/命令列中安裝
PyPI(Python Package Index)是 Python 官方的第三方庫的倉庫,PyPI 推薦使用 pip
包管理器來下載第三方庫。
-
安裝 pip
在 Python 3.4 之後,安裝好 Python 環境就可以直接支援 pip,你可以在終端/命令列裡輸入這句檢查一下:
pip --version
(前提電腦 path 路徑已經配置好了),如果顯示 pip 版本,就說明 pip 已經成功安裝了;如果發現沒有安裝,則根據不同系統如下方式安裝: -
使用 pip 安裝庫
在安裝好了 pip 之後,以後安裝庫,只需要在命令列裡面輸入:
pip3 install PackageName
(注:如果你想要安裝到 Python 2 中,需要把pip3
換成pip
)。補充:pip
和pip3
都在Python36Scripts
目錄下,如果同時裝有 python2 和 python3,pip 預設給python2
用,pip3
指定給 python3 用。如果只裝有 python3,則pip
和pip3
是等價的。如果你安裝了 Python 2 和 3 兩種版本,可能會遇到安裝目錄的問題,可以換成:
python3 -m pip install PackageName
(注:如果你想安裝到 Python2 中,需要把 Python3 換成 Python)如果遇到許可權問題,可以輸入:
sudo pip install PackageName
安裝成功之後會提示:
Successfully insyalled PackageName
一些常用的 pip 指令:
# pip 使用格式:pip <command> [options] package_name pip install package_name==1.9.2 # 安裝指定版本的包 pip install --upgrade package_name # 更新指定的包 pip uninstall package_name # 解除安裝指定的包 pip show package_name # 檢視所安裝包的詳細資訊 pip list # 檢視所有安裝的包 pip --help # 檢視幫助 複製程式碼
補充:如果下載很慢,可以考慮更改 pip 下載源。國內映象有:
# 國內常用的映象
http://pypi.douban.com/simple/ # 豆瓣
http://mirrors.aliyun.com/pypi/simple/ # 阿里
https://pypi.tuna.tsinghua.edu.cn/simple # 清華
http://pypi.mirrors.ustc.edu.cn/simple/ # 中國科學技術大學
http://pypi.hustunique.com/simple/ # 華中理工大學
複製程式碼
更改方法:
-
臨時使用,新增
-i
或--index
引數:pip install -i http://pypi.douban.com/simple/ flask
-
Linux下永久生效的配置方法
cd $HOME mkdir .pip cd .pip sudo vim pip.conf # 在裡面新增,trusted-host 選項為了避免麻煩是必須的,否則使用的時候會提示不受信任 [global] index-url=https://pypi.tuna.tsinghua.edu.cn/simple [install] trusted-host=pypi.tuna.tsinghua.edu.cn disable-pip-version-check=true timeout = 6000 複製程式碼
-
Windows 下永久生效的配置方法
# a、進入如下目錄(沒有此目錄或檔案就自己建立下) C:UsersusernameAppDataLocalpip 或 C:Usersusernamepip # b、建立 “pip.ini” 檔案(注意:以UTF-8 無BOM格式編碼),新增如下內容 [global] index-url=https://pypi.tuna.tsinghua.edu.cn/simple [install] trusted-host=pypi.tuna.tsinghua.edu.cn disable-pip-version-check=true timeout = 6000 複製程式碼
③最原始的方式:手動安裝
進入 pypi.python.org,搜尋你要安裝的庫的名字,這時候有 3 種可能:
-
第一種是
exe
檔案,這種最方便,下載滿足你的電腦系統和 Python 環境的對應的exe
,再一路點選 next 就可以安裝。 -
第二種是
.whl
類檔案,好處在於可以自動安裝依賴的包。- 到命令列輸入
pip3 install whell
等待執行完成,不能報錯(Python 2 中要換成 pip) - 從資源管理器中確認你下載的
.whl
類檔案的路徑,然後在命令列繼續輸入:cd C:download
,此處需要改為你的路徑,路徑的含義是檔案所在的資料夾,不包含這個檔名字本身,然後再命令列繼續輸入:pip3 install xxx.whl
,xxx.whl
是你下載的檔案的完整檔名。
- 到命令列輸入
-
第三種是原始碼,大概都是
zip
、tar.zip
、tar.bz2
格式的壓縮包,這個方法要求使用者已經安裝了這個包所依賴的其他包。例如 pandas 依賴於 numpy,你如果不安裝 numpy,這個方法是無法成功安裝 pandas 的。- 解壓包,進入解壓好的資料夾,通常會看見一個
setup.py
的檔案,從資源管理器中確認你下載的檔案的路徑,開啟命令列,輸入:cd C:download
此處需要改為你的路徑,路徑的含義是檔案所在的資料夾,不包含這個檔名字本身 - 然後在命令列中繼續輸入:
python3 setup.py install
這個命令,就能把這個第三方庫安裝到系統裡,也就是你的 Python路徑,windows 大概是在C:Python3.5Libsite-packages
。
注:想要卸庫的時候,找到 Python 路徑,進入 site-packages 資料夾,在裡面刪掉庫檔案就可以了。
- 解壓包,進入解壓好的資料夾,通常會看見一個
本文內容大部分來源: