python3 學習筆記
Python3 Study Notes
本人很少寫python
程式碼, 一般都是用go
的, 去年時用python
寫過一些收集系統資訊的工具, 當時是邊看手冊邊寫的. 如今又要用python
來寫一個生成xlsx
的工具, 就又需要檢視手冊了, 至於為什麼不用go
寫? 那是因為go
的庫不相容永中. 在這裡不得不說, 雖然go
很火, 但是一些庫還是不如python
多, 不如python
相容性好.
為了避免以後再出這種事情, 這次就好好的瞭解下python
, 將它的用法按照自己對語言的理解分塊記錄下來. 要使用某種語言, 個人認為需要了解這些方面:
- 編碼風格
- 變數的型別, 宣告及使用方式
- 輸入/輸出
- 控制語句的寫法
- 錯誤處理的用法
-
函式的用法, 還有語言支援的一些特性,
python
中就有裝飾器,lambda
語句等 - 對於面嚮物件語言還需要了解類的宣告, 繼承, 多型等的用法
還有一些就是此語言的一些特性,python
就還需要了解以下特性:
- 模組的使用
下文就將按照這些內容來一一記錄.
編碼風格
-
變數名, 方法名和模組名建議小寫, 單詞以
_
分割, 類名建議駝峰命名風格, 首字母大寫, 私有類可用一個_
開頭. -
每行結尾儘量不要新增
;
, 多行程式碼也不要寫在一行 -
python
是以縮排來控制程式碼段的, 所以縮減建議使用 4 個空格 -
編碼儘量使用
utf-8
,python
預設使用ASCII
, 所以要在檔案的開頭新增# -*- coding: UTF-8 -*-
或者#coding=utf-8
來指定 -
python
有獨一無二的註釋方式: 文件字串, 所以註釋儘量用文件字串("""xxxx"""
) -
如果一個類不從其他類繼承, 就顯示的從
object
類繼承 -
使用
with
語句來管理檔案, 如open
或close
-
新增
TODO
時, 儘量在其後緊跟()
, 在裡面寫明作者名或email
等其他標識資訊, 然後緊跟一個:
後面接著寫要做的事情 - 每個匯入模組都佔一行, 不要一行匯入多個模組
-
儘量定義一個
main
函式, 將主程式放入其中, 並在 "if <span class="underline"><span class="underline">name</span></span>= '__main__':" 成立時執行 =main
, 這樣被當作模組匯入時就不會執行主程式
變數
Python
是動態語言, 變數的型別不固定, 根據值的型別而決定, 所以不用顯示的宣告變數, 用的時候直接賦值即可,如下:
a = 1; // 此時是整型 print(a); a = 'hello'; // 此時又為字串型別
通常變數名全部大寫的為常量
,空值
用None
表示.
以_xxx
或__xxx
命名的函式或變數是私有變數, 不能被其他模組直接引用
基礎型別
這裡將整型, 浮點型, 布林和字串看作是基本型別, 整型和浮點型的使用就不再介紹了, 布林的值只能為True/False
, 而字串的常見操作如下:
-
使用
"""
或'''
可以嵌入長字串 -
字串可以通過下標來索引,
len
函式獲取長度 -
使用
+
進行拼接操作 - 字串物件還內建了很多方法提供了一些常見功能, 具體請查閱手冊
另外它們之間的相互轉換是通過int(arg), float(arg), str(arg)
這些內建的方法來處理的.
列表
列表中可以包含不同型別的資料, 如:
list = ["eggs", 1, 67.12];
通過list(seq)
可以將一個序列轉換為列表.
array模組提供了固定型別的資料, 可以指定要轉換的型別, 具體請查閱手冊.
列表通過下標索引,len
函式獲取大小.
列表物件常用的方法如下:
- append(item): 附加元素
- insert(idx, item): 插入元素
- pop(idx): 刪除指定位置的元素, 引數為空則刪除最後一個元素
列表遍歷:
for <variable> in <array>: // do // 帶下標 for idx, name in enumerate(<array>): // do // 列表中多個元素 for x, y in [(1, 1), (2, 4), (3, 9)]: // do // 用 zip 同時遍歷多個數組 a = [1, 2]; b = [5, 6]; for av, bv in zip(a, b): // do av=1, bv=5 // 生成 [x * x for x in range(1, 11) if x % 2 == 0]
元組
元組(tuple) 是一個不可修改的列表, 元組中每個元素的指向是不可更改的, 但指向裡的內容是可以更改的, 如元組中包含一個數組:
t = ('1', 1, ["A", "B"]); t[2][0] = "X"; t[2][1] = "Y";
字典
語法:
dict = {'<key>':<value>}
常用的物件方法:
-
get(key, value):
獲取指定
key
的值, 如果不存在則返回value
, 如果value
未指定則返回None
-
pop(key):
刪除指定的
key
使用字典需要注意以下幾點:
key key
集合
集合與字典類似, 是一組key
的集合, 但不儲存value
, 沒有重複的key
.
要建立一個集合, 需要傳入一個數組, 重複的元素會被自動過濾.
遍歷:
for <key> in <dict>: // do // 帶下標 for idx, name in dict.items(): // do
s = set([1, 2, 3 ,3]); // s: {1,2,3}
常用的物件方法:
-
add(key):
新增
key
-
remove(key):
刪除
key
global 關鍵字
global
關鍵字用於宣告變數的作用域, 用法如下:
# 全域性變數 a = 1 def test(): # 若下面這行註釋掉, 則下面的 a 是區域性變數, 'Global' 處的輸出還是全域性變數 1 # 若下面這行取消註釋, 則下面的 a 是全域性變數, 'Gloabl' 出的輸出是 5 # global a a = 5 print("In test:", a) # Global print("Global:", a)
輸出,global a
註釋掉時:
In test: 5 Global: 1
輸出,global a
取消註釋時:
In test: 5 Global: 5
更多
上面的只是基礎,想要更好的使用變數,還需要了解以下內容:
-
型別物件的方法
python
中每種型別都是物件, 都提供了一些內建方法, 如字串型別的replace()
等 -
變數的記憶體分配
變數只是值的引用, 具體的記憶體分配是在值的這一邊, 有些型別的值是不可變的, 這些是需要深入瞭解的
-
結構體
python
中沒有結構體, 可以使用下列方式實現:-
使用
struct
模組來實現, 需要了解與c
中型別的格式對照, 建立時需要指定結構體的成員型別 -
使用類來實現, 在類的建構函式
__init__
中定義結構體成員
-
使用
輸入/輸出
輸入
使用raw_input(prompt)
可以接受控制檯的輸入
輸出
使用print()
可以列印內容到控制檯, 格式化輸出:
n = 1; s = "Joy"; print("The %d student's name is %s" % (n, s));
也可以使用format
來格式化, 它會用傳入的引數依次替換字串內的佔位符 {0}、{1}…… :
// {3:.1f} 表示保留一位小數 s = "The {0} student's name is {1}, score: {3:.1f}".format(1, "Joy", 87.75); print(s);
控制語句
控制語句中可以使用break, continue, pass
關鍵字,break
與continue
的作用與其他語言中的一樣,pass
則是一個空語句, 不做任何事情, 一般是為了保持結構的完整性, 常被用來佔位, 表明之後會實現.
注意:python
中沒有goto
和switch
.
IF
語法:
if <condition>: elif <condition>: else:
FOR
for <variable> in <array>: // do else:
else
可選
WHILE
while <condition>: // do else:
else
可選
錯誤處理
語法:
try: // do except <error type> as e: // do except <error type> as e: else: // no error finally: // do
如果finally
存在, 則無論有沒有異常都會執行,else
則在except
都沒進入時才執行.
函式
語法:
def func(arg1, arg2=value, arg3=value): // do return ret1, ret2 # 不定長引數 def func(arg1, *vartuple): "列印所有引數" print(arg1) for var in vartuple: print(var) return
定義函式時可以給引數指定預設值, 這樣在呼叫時就可以不傳入這些引數, 沒有預設值的引數是必須要傳入的.
定義預設引數要牢記一點:預設引數必須指向不變物件(數, 字串, 元組)!
引數前加了*
的變數會存放所有未命名的變數.
__name__
是函式物件的一個屬性, 可以拿到此函式的名稱
Lambda
使用關鍵字lambda
, 就可以建立短小的匿名函式, 如:
# 語法 lambda [arg1 [,arg2,.....argn]]:expression sum = lambda arg1, arg2: arg1 + arg2 print(sum(10, 10) # 20 print(sum(10, 20) # 30
特點:
-
lambda
只是一個表示式, 函式體比def
簡單的多, 近能封裝有限的邏輯進去 -
lambda
函式擁有自己的名稱空間, 並且不能訪問自有引數之外或全域性命名的引數 -
lambda
函式雖然間短, 但不等同於行內函數
裝飾器
當需要增強某個函式的功能時, 但有不希望修改函式, 此時可以使用裝飾器. 如新增日誌功能:
def log(func): def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper @log def test(): print("Test")
通過@
語法就給函式test
添加了日誌功能
模組
模組就是一個python
檔案, 使用import
匯入模組, 呼叫模組中的方法時就必須以<module>.<func>
來呼叫.
from <module> import <func1>,<func2>...
語句是從模組中匯入指定的函式,from <module> import *
則將模組中的所有方法都匯入
匯入一個模組時的路徑搜尋順序如下:
- 先從當前目錄查詢是否有此模組
-
如果當前目錄沒有, 就從
PYTHONPATH
定義的目錄下查詢 -
如果都找不到, 就檢視預設路徑,
linux
下一般是/usr/lib/python
搜尋路徑定義在sys.path
中, 可以用append
函式來新增指定目錄, 如專案中模組不再同一個目錄就可以新增path
來匯入
包
python
中的包就是一個分層次的目錄, 定義了一個由模組及子包組成的環境.
包簡單來說就是一個目錄, 目錄中必須包含一個__init__.py
, 該檔案可以為空, 目的使用來標識這個目錄是一個包, 一個簡單的例子如下:
如存在目錄package_test
, 此目錄下有__init__.py, foo1.py, foo2.py
等檔案
foo1.py
檔案:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- def foo1(): print("Foo1 test")
foo2.py
檔案:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- def foo2(): print("Foo2 test")
呼叫:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from package_test.foo1 import foo1 from package_test.foo2 import foo2 if __name__ == "__main__": foo1() foo2()
類
python
是一門面向物件語言, 所以建立類和物件是很容易的, 先簡單介紹下面向物件的一些基本特徵:
+
類的建立
python
中類建立的語法如下:
# 建立一個類 class Human: # 類變數 var1 = 0 # 公有成員 _var2 = 0 # 受保護成員 __var3 = 0 # 私有成員 # 建構函式, 裡面可以定義例項變數, 這些變數在例項化之後才能使用 def __init__(self, arg1, arg2...): self.arg1 = arg1 self._arg2 = arg2 self.__arg3 = arg3 # 類方法 def foo(self): print("Var1:", var1) print("Arg1:", self.arg1) # 例項化 h = Human(arg1, arg2...) # 方法呼叫 h.foo() # 類的銷燬 del h
類的例項化是通過呼叫建構函式完成的,__init__
函式中定義了例項化時需要的引數.
類中以一個_
開頭命令的變數或方法叫做受保護成員, 以二個_
開頭命名的叫做私有成員, 以__
開頭並以__
結尾的為系統定義的, 一般是內建的成員.
使用del
則可銷燬一個類例項.
類內建了以下屬性:
- __dict__: 類的資料屬性組成的字典
- __doc__: 類的文件
- __name__: 類名
- __module__: 類定義所在的模組名
- __bases__: 類繼承的所有父類的元組
類的繼承
語法如下:
class SubName(Parent1, Parent2...): pass
一個子類可以繼承多個父類, 使用isintance(obj, type)
可以判斷一個物件的型別, 使用issubclass(sub, parent)
可以判斷是否為另一個類的子類.
方法重寫
如果父類的方法不能滿足子類的需求, 子類就可重寫此方法, 在使用子類物件呼叫此方法時會呼叫重寫後的方法.
運算子過載也是方法的重寫, 只不過是對一些內建方法進行重寫.
下面列出一些基本的內建方法:
- __init__(self, [, args…]): 建構函式, 使用者例項化物件
- __del__(self): 解構函式, 用於刪除物件
- __repr__(self): 轉化為供直譯器讀取的形式
- __str__(self): 用於將值轉化為適於人閱讀的形式
- __cmp__(self, obj): 物件比較
- __add__(self, obj): '+' 物件相加
- __sub__(self, obj): '-' 物件相減
- __eq__(self, obj): '==' 物件是否相等
- __gt__(self, obj): '>' 物件是否小於
- __lt__(self, obj): '<' 物件是否小於
- __iadd__(self, obj): '+=' 物件相加
更多的內建方法請查閱手冊
以上就介紹完了python
的基礎知識, 按照上面的內容就能夠寫出python
程式了, 當然前提是你不是一個小白, 至少熟悉一門程式語言.
但python
還有很多高階知識則需要你自行使用學習了, 如檔案操作, 程序和執行緒, 網路程式設計, 圖形程式設計等等. 本文的目的只是讓你明白python
程式應該怎麼寫, 怎麼把你用其他語言寫的程式轉換成python
語言的, 更多高階的特性只能靠你自己學習嘗試.