前言
學一門語言貴在堅持用它,不用就淡忘了,而記錄下一篇文章也有助于日后快速回憶。全文分為兩大部分,分別是Python基礎語法和面向對象。
第一部分%20Python基礎語法
1.%20認識Python
1.1%20Python%20簡介
Python%20的創始人為吉多·范羅蘇姆(Guido%20van%20Rossum)。
Python%20的設計目標:
一門簡單直觀的語言并與主要競爭者一樣強大 開源,以便任何人都可以為它做貢獻%20代碼像純英語那樣容易理解 適用于短期開發的日常任務
Python%20的設計哲學:
優雅、明確、簡單
Python%20開發者的哲學是:用一種方法,最好是只有一種方法來做一件事
Python%20是完全面向對象的語言,在%20Python%20中一切皆對象。
可擴展性:如果需要一段關鍵代碼運行得更快或者希望某些算法不公開,可以把這部分程序用%20C%20或%20C++%20編寫,然后在%20Python%20程序中使用它們。
1.2.%20第一個Python程序
執行%20Python%20程序的三種方式:解釋器、交互式運行、IDE運行
Python%20是一個格式非常嚴格的程序設計語言。python%202.x%20默認不支持中文。
ASCII%20字符只包含%20256%20個字符,不支持中文
- Python%202.x%20的解釋器名稱是 python
- Python%203.x%20的解釋器名稱是 python3
為了照顧現有的程序,官方提供了一個過渡版本%20—— Python%202.6。
提示:如果開發時,無法立即使用%20Python%203.0(還有極少的第三方庫不支持%203.0%20的語法),建議
先使用%20Python%203.0%20版本進行開發%20然后使用%20Python%202.6、Python%202.7%20來執行,并且做一些兼容性的處理
IPython%20是一個%20python%20的 交互式%20shell,比默認的%20python%20shell%20好用得多,它支持%20bash%20shell%20命令,適合于學習/驗證%20Python%20語法或者局部代碼。
集成開發環境(IDE,Integrated%20Development%20Environment)—— 集成了開發軟件需要的所有工具,一般包括以下工具:
- 圖形用戶界面
- 代碼編輯器(支持 代碼補全/自動縮進)
- 編譯器/解釋器
- 調試器(斷點/單步執行)
- ……
PyCharm 是 Python 的一款非常優秀的集成開發環境
PyCharm運行工具欄
1.3. PyCharm 的設置
PyCharm 的 配置信息 是保存在 用戶家目錄下 的 .PyCharmxxxx.x 目錄下的,xxxx.x 表示當前使用的 PyCharm 的版本號
1.3.1 恢復 PyCharm 的初始設置:
- 關閉正在運行的 PyCharm
- 在終端中執行以下終端命令,刪除 PyCharm 的配置信息目錄:
$ rm -r ~/.PyCharm2016.3
- 重新啟動 PyCharm
1.3.2 PyCharm 安裝和啟動步驟:
- 執行以下終端命令,解壓縮下載后的安裝包
$ tar -zxvf pycharm-professional-2017.1.3.tar.gz
- 將解壓縮后的目錄移動到 /opt 目錄下,可以方便其他用戶使用
/opt 目錄用戶存放給主機額外安裝的軟件
$ sudo mv pycharm-2017.1.3/ /opt/
- 切換工作目錄
$ cd /opt/pycharm-2017.1.3/bin
- 啟動 PyCharm
$ ./pycharm.sh
1.3.3 設置啟動圖標
- 在專業版中,選擇菜單 Tools / Create Desktop Entry... 可以設置任務欄啟動圖標
- 注意:設置圖標時,需要勾選 Create the entry for all users
快捷方式文件
/usr/share/Applications/jetbrains-pycharm.desktop
在 ubuntu 中,應用程序啟動的快捷方式通常都保存在 /usr/share/applications 目錄下
1.3.4 卸載之前版本的 PyCharm
要卸載 PyCharm 只需要做以下兩步工作:
- 刪除解壓縮目錄
$ sudo rm -r /opt/pycharm-2016.3.1/
- 刪除家目錄下用于保存配置信息的隱藏目錄
$ rm -r ~/.PyCharm2016.3/
如果不再使用 PyCharm 還需要將 /usr/share/applications/ 下的 jetbrains-pycharm.desktop 刪掉
1.4. 多文件項目的演練
- 開發 項目 就是開發一個 專門解決一個復雜業務功能的軟件
- 通常每 一個項目 就具有一個 獨立專屬的目錄,用于保存 所有和項目相關的文件
- 在 PyCharm 中,要想讓哪一個 Python 程序能夠執行,必須首先通過 鼠標右鍵的方式執行 一下
- 對于初學者而言,在一個項目中設置多個程序可以執行,是非常方便的,可以方便對不同知識點的練習和測試
- 對于商業項目而言,通常在一個項目中,只有一個 可以直接執行的 Python 源程序
讓選中的程序可以執行
2. 注釋
- 注釋的作用
使用用自己熟悉的語言,在程序中對某些代碼進行標注說明,增強程序的可讀性
2.1 單行注釋(行注釋)
- 以 # 開頭,# 右邊的所有東西都被當做說明文字,而不是真正要執行的程序,只起到輔助說明作用
print("hello python") # 輸出 `hello python`
為了保證代碼的可讀性,# 后面建議先添加一個空格,然后再編寫相應的說明文字;為了保證代碼的可讀性,注釋和代碼之間 至少要有 兩個空格。
2.2 多行注釋(塊注釋)
- 要在 Python 程序中使用多行注釋,可以用 一對 連續的 三個 引號(單引號和雙引號都可以)
"""
這是一個多行注釋
在多行注釋之間,可以寫很多很多的內容……
"""
print("hello python")
提示:
- 注釋不是越多越好,對于一目了然的代碼,不需要添加注釋
- 對于 復雜的操作,應該在操作開始前寫上若干行注釋
- 對于 不是一目了然的代碼,應在其行尾添加注釋(為了提高可讀性,注釋應該至少離開代碼 2 個空格)
- 絕不要描述代碼,假設閱讀代碼的人比你更懂 Python,他只是不知道你的代碼要做什么
2.3 代碼規范:
- Python 官方提供有一系列 PEP(Python Enhancement Proposals) 文檔,其中第 8 篇文檔專門針對 Python 的代碼格式 給出了建議,也就是俗稱的 PEP 8: 文檔地址:https://www.python.org/dev/peps/pep-0008/ 谷歌有對應的中文文檔:http://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/
3. 運算符
3.1 算數運算符
是完成基本的算術運算使用的符號,用來處理四則運算,而“+”和“*”還可以用來處理字符串。
運算符 描述 實例 + 加 10 + 20 = 30 - 減 10 - 20 = -10 * 乘 10 * 20 = 200 / 除 10 / 20 = 0.5 // 取整除 返回除法的整數部分(商) 9 // 2 輸出結果 4 % 取余數 返回除法的余數 9 % 2 = 1 ** 冪 又稱次方、乘方,2 ** 3 = 8
3.2 比較(關系)運算符
運算符 描述 == 檢查兩個操作數的值是否 相等,如果是,則條件成立,返回 True != 檢查兩個操作數的值是否 不相等,如果是,則條件成立,返回 True > 檢查左操作數的值是否 大于右操作數的值,如果是,則條件成立,返回 True < 檢查左操作數的值是否 小于 右操作數的值,如果是,則條件成立,返回 True >= 檢查左操作數的值是否 大于或等于 右操作數的值,如果是,則條件成立,返回 True <= 檢查左操作數的值是否 小于或等于 右操作數的值,如果是,則條件成立,返回 True
Python 2.x 中判斷 不等于 還可以使用 <> 運算符 != 在 Python 2.x 中同樣可以用來判斷 不等于
3.3 賦值運算符
- 在 Python 中,使用 = 可以給變量賦值。在算術運算時,為了簡化代碼的編寫,Python 還提供了一系列的 與 算術運算符 對應的 賦值運算符,注意:賦值運算符中間不能使用空格。
運算符 描述 實例 = 簡單的賦值運算符 c = a + b 將 a + b 的運算結果賦值為 c += 加法賦值運算符 c += a 等效于 c = c + a -= 減法賦值運算符 c -= a 等效于 c = c - a *= 乘法賦值運算符 c *= a 等效于 c = c * a /= 除法賦值運算符 c /= a 等效于 c = c / a //= 取整除賦值運算符 c //= a 等效于 c = c // a %= 取 模 (余數)賦值運算符 c %= a 等效于 c = c % a **= 冪賦值運算符 c **= a 等效于 c = c ** a
3.4 身份運算符
身份運算符比較兩個對象的內存位置。常用的有兩個身份運算符,如下所述:
運算符 描述 示例 is 判斷兩個標識符是不是引用同一個對象 x is y,類似 id(x) == id(y) is not 判斷兩個標識符是不是引用不同對象 x is not y,類似 id(a) != id(b)
辨析
- is 用于判斷 兩個變量引用的對象是否為同一個
- == 用于判斷 引用變量的值 是否相等
3.5 成員運算符
Python成員運算符測試給定值是否為序列中的成員。 有兩個成員運算符,如下所述:
運算符 描述 in 如果在指定的序列中找到一個變量的值,則返回true,否則返回false。 not in 如果在指定序列中找不到變量的值,則返回true,否則返回false。
3.6 邏輯運算符
運算符 邏輯表達式 描述 and x and y 只有 x 和 y 的值都為 True,才會返回 True<br />否則只要 x 或者 y 有一個值為 False,就返回 False or x or y 只要 x 或者 y 有一個值為 True,就返回 True<br />只有 x 和 y 的值都為 False,才會返回 False not not x 如果 x 為 True,返回 False<br />如果 x 為 False,返回 True
3.7 運算符優先級
- 以下表格的算數優先級由高到最低順序排列:
運算符 描述 ** 冪 (最高優先級) * / % // 乘、除、取余數、取整除 + - 加法、減法 <= < > >= 比較運算符 == != 等于運算符 = %= /= //= -= += *= **= 賦值運算符 is is not 身份運算符 in not in 成員運算符 not or and 邏輯運算符
<補>程序執行原理
Python程序執行示意圖
- 操作系統會首先讓 CPU 把 Python 解釋器 的程序復制到 內存 中
- Python 解釋器 根據語法規則,從上向下 讓 CPU 翻譯 Python 程序中的代碼
- CPU 負責執行翻譯完成的代碼
Python 的解釋器有多大?
- 執行以下終端命令可以查看 Python 解釋器的大小
看完這篇文章,你的Python基礎就差不多了# 1. 確認解釋器所在位置
$ which python
# 2. 查看 python 文件大小(只是一個軟鏈接)
$ ls -lh /usr/bin/python
# 3. 查看具體文件大小
$ ls -lh /usr/bin/python2.7
4. 變量
4.1 變量定義
- 在 Python 中,每個變量 在使用前都必須賦值,變量 賦值以后 改變量 才會被創建
- 可以用 其他變量的計算結果 來定義變量
- 變量名 只有在 第一次出現 才是 定義變量
變量名 = 值
使用交互式方式,如果要查看變量內容,直接輸入變量名即可,不需要使用 print 函數使用解釋器執行,如果要輸出變量的內容,必須要要使用 print 函數
4.2 變量的類型
- 在 Python 中定義變量是 不需要指定類型(在其他很多高級語言中都需要),Python 可以根據 = 等號右側的值,自動推導出變量中存儲數據的類型
- 數據類型可以分為 數字型 和 非數字型 數字型 整型 (int):Python3中的所有整數都表示為長整數。 因此,長整數沒有單獨的數字類型。 浮點型(float) 布爾型(bool) :真 True 非 0 數 —— 非零即真,假 False 0。 復數型 (complex):復數是由x + yj表示的有序對的實數浮點數組成,其中x和y是實數,j是虛數單位。 非數字型:有些運算符還支持這些數據類型,詳見4.4.5.3 運算符。 字符串(str):加號(+)是字符串連接運算符,星號(*)是重復運算符。 列表(list) 元組(tuple) 字典(dict)
提示:在 Python 2.x 中,整數 根據保存數值的長度還分為:
int(整數) long(長整數)
- 使用 type 函數可以查看一個變量的類型
In [1]: type(name)
<補>不同類型變量之間的計算
- 數字型變量 之間可以直接計算
- 在 Python 中,兩個數字型變量是可以直接進行 算數運算的
- 如果變量是 bool 型,在計算時 True 對應的數字是 1 False 對應的數字是 0
- 字符串變量 之間使用 + 拼接字符串
- 字符串變量 可以和 整數 使用 * 重復拼接相同的字符串
- 數字型變量 和 字符串 之間 不能進行其他計算
<補>從鍵盤獲取輸入信息:input
- 在 Python 中可以使用 input 函數從鍵盤等待用戶的輸入
- 用戶輸入的 任何內容 Python 都認為是一個 字符串
字符串變量 = input("提示信息:")
<補>類型轉換函數
函數 說明 int(x) 將 x 轉換為一個整數 float(x) 將 x 轉換到一個浮點數 str(x) 將對象x轉換為字符串表示形式 tuple(s) 將s轉換為元組 list(s) 將s轉換為列表
price = float(input("請輸入價格:"))
<補>格式化輸出:print
- 如果希望輸出文字信息的同時,一起輸出 數據,就需要使用到 格式化操作符
- % 被稱為 格式化操作符,專門用于處理字符串中的格式 包含 % 的字符串,被稱為 格式化字符串 % 和不同的 字符 連用,不同類型的數據 需要使用 不同的格式化字符
格式化字符 含義 %s 字符串 %d 有符號十進制整數,%06d 表示輸出的整數顯示位數,不足的地方使用 0 補全 %f 浮點數,%.2f 表示小數點后只顯示兩位 %% 輸出 %
- 語法格式如下:
print("格式化字符串" % 變量1)
print("格式化字符串" % (變量1, 變量2...))
4.4.5 公共方法和變量的高級應用
4.4.5.1 內置函數
Python 包含了以下內置函數:
函數 描述 備注 len(item) 計算容器中元素個數 del(item) 刪除變量 del 有兩種方式 max(item) 返回容器中元素最大值 如果是字典,只針對 key 比較 min(item) 返回容器中元素最小值 如果是字典,只針對 key 比較 cmp(item1, item2) 比較兩個值,-1 小于 / 0 相等 / 1 大于 Python 3.x 取消了 cmp 函數
注意:字符串 比較符合以下規則: "0" < "A" < "a"。
4.4.5.2 切片
描述 Python 表達式 結果 支持的數據類型 切片 "0123456789"[::-2] "97531" 字符串、列表、元組
- 切片 使用 索引值 來限定范圍,從一個大的 字符串 中 切出 小的 字符串
- 列表 和 元組 都是 有序 的集合,都能夠 通過索引值 獲取到對應的數據
- 字典 是一個 無序 的集合,是使用 鍵值對 保存數據
面向對象編程 —— Object Oriented Programming 簡寫 OOP
- 面向過程 —— 怎么做?
把完成某一個需求的 所有步驟 從頭到尾 逐步實現
根據開發需求,將某些 功能獨立 的代碼 封裝 成一個又一個 函數
最后完成的代碼,就是順序地調用 不同的函數
特點:
注重 步驟與過程,不注重職責分工
如果需求復雜,代碼會變得很復雜
開發復雜項目,沒有固定的套路,開發難度很大! - 面向對象 —— 誰來做? 相比較函數,面向對象 是更大的封裝,根據職責在 一個對象中封裝多個方法 在完成某一個需求前,首先確定 職責 —— 要做的事情(方法)
根據 職責 確定不同的 對象,在 對象 內部封裝不同的 方法(多個)
最后完成的代碼,就是順序地讓 不同的對象 調用 不同的方法
特點:
注重 對象和職責,不同的對象承擔不同的職責
更加適合應對復雜的需求變化,是專門應對復雜項目開發,提供的固定套路
需要在面向過程基礎上,再學習一些面向對象的語法 - 類和對象
類 是對一群具有 相同 特征 或者 行為 的事物的一個統稱,是抽象的,特征 被稱為 屬性,行為 被稱為 方法。
對象 是 由類創建出來的一個具體存在,是類的實例化。
在程序開發中,要設計一個類,通常需要滿足一下三個要素: 類名 這類事物的名字,滿足大駝峰命名法 屬性 這類事物具有什么樣的特征 方法 這類事物具有什么樣的行為
2. 面向對象基礎語法
2.1 dir 內置函數和內置方法
在 Python 中 對象幾乎是無所不在的,我們之前學習的 變量、數據、函數 都是對象。在 Python 中可以使用以下兩個方法驗證:
- 在 標識符 / 數據 后輸入一個點 .,然后按下 TAB 鍵,iPython 會提示該對象能夠調用的方法列表。
- 使用內置函數 dir 傳入 標識符 / 數據,可以查看對象內的 所有屬性及方法。
提示__方法名__格式的方法是 Python 提供的 內置方法 / 屬性。
序號 方法名 類型 作用 01 __new__ 方法 創建對象時,會被 自動 調用 02 __init__ 方法 對象被初始化時,會被 自動 調用 03 __del__ 方法 對象被從內存中銷毀前,會被 自動 調用 04 __str__ 方法 返回對象的描述信息,print 函數輸出使用
提示 利用好 dir() 函數,在學習時很多內容就不需要死記硬背了。
2.2 定義簡單的類(只包含方法)
面向對象是更大的封裝,在 一個類中封裝多個方法,這樣通過這個類創建出來的對象,就可以直接調用這些方法了!
定義一個只包含方法的類:
class 類名:
def 方法1(self, 參數列表):
pass
def 方法2(self, 參數列表):
pass
方法 的定義格式和之前學習過的函數幾乎一樣,區別在于第一個參數必須是 self。注意:類名的 命名規則 要符合 大駝峰命名法。當一個類定義完成之后,要使用這個類來創建對象,語法格式如下:
對象變量 = 類名()
在面向對象開發中,引用的概念是同樣適用的!
使用 print輸出 對象變量,默認情況下,是能夠輸出這個變量 引用的對象 是 由哪一個類創建的對象,以及 在內存中的地址(十六進制表示)。
提示:在計算機中,通常使用 十六進制 表示 內存地址。
如果在開發中,希望使用 print輸出 對象變量 時,能夠打印 自定義的內容,就可以利用 __str__這個內置方法了:
class Cat:
def __init__(self, new_name):
self.name = new_name
print("%s 來了" % self.name)
def __del__(self):
print("%s 去了" % self.name)
def __str__(self):
return "我是小貓:%s" % self.name
tom = Cat("Tom")
print(tom)
注意:__str__方法必須返回一個字符串。
2.3 方法中的 self 參數
在 Python 中,要 給對象設置屬性,非常的容易,只需要在 類的外部的代碼 中直接通過 對象.設置一個屬性即可,但是不推薦使用:
看完這篇文章,你的Python基礎就差不多了class Cat:
"""這是一個貓類"""
def eat(self):
print("小貓愛吃魚")
def drink(self):
print("小貓在喝水")
tom = Cat()
# 給對象設置屬性
tom.name = "Tom"
因為:對象屬性的封裝應該封裝在類的內部
由哪一個對象調用的方法,方法內的 self就是哪一個對象的引用
- 在類封裝的方法內部,self 就表示當前調用方法的對象自己,在方法內部:
可以通過 self.訪問對象的屬性,也可以通過 self.調用對象的其他方法。 - 調用方法時,程序員不需要傳遞 self 參數。
- 在 類的外部,通過變量名.訪問對象的 屬性和方法
在 類封裝的方法中,通過 self.訪問對象的 屬性和方法
2.4 初始化方法:__init__
- 當使用 類名() 創建對象時,會 自動 執行以下操作:
為對象在內存中分配空間 —— 創建對象
為對象的屬性設置初始值 —— 初始化方法(__init__)
__init__ 方法是 專門 用來定義一個類具有哪些屬性的方法!
- 在 __init__ 方法內部使用 self.屬性名 = 屬性的初始值 就可以定義屬性,定義屬性之后,再使用 類創建的對象,都會擁有該屬性。
- 在開發中,如果希望在 創建對象的同時,就設置對象的屬性,可以對 __init__ 方法進行 改造: 把希望設置的屬性值,定義成 __init__方法的參數 在方法內部使用 self.屬性 = 形參 接收外部傳遞的參數 在創建對象時,使用 類名(屬性1, 屬性2...) 調用
class Cat:
def __init__(self, name):
print("初始化方法 %s" % name)
self.name = name
...
tom = Cat("Tom")
...
lazy_cat = Cat("大懶貓")
...
2.5 私有屬性和私有方法
應用場景
- 在實際開發中,對象 的 某些屬性或方法 可能只希望 在對象的內部被使用,而 不希望在外部被訪問到
- 私有屬性 就是 對象 不希望公開的 屬性
- 私有方法 就是 對象 不希望公開的 方法
定義方式
- 在 定義屬性或方法時,在 屬性名或者方法名前 增加 兩個下劃線,定義的就是 私有屬性或方法:
私有屬性和私有方法
偽私有屬性和私有方法Python 中,并沒有 真正意義 的 私有在給 屬性、方法 命名時,實際是對名稱做了一些特殊處理,使得外界無法訪問到處理方式:在 名稱 前面加上_類名 => _類名__名稱
# 私有屬性,外部不能直接訪問到
print(xiaofang._Women__age)
# 私有方法,外部不能直接調用
xiaofang._Women__secret()
提示:在日常開發中,不要使用這種方式,訪問對象的 私有屬性 或 私有方法。
3. 封裝、繼承和多態
面向對象三大特性:
- 封裝 根據 職責 將 屬性 和 方法 封裝 到一個抽象的 類 中
- 繼承 實現代碼的重用,相同的代碼不需要重復的編寫
- 多態 不同的對象調用相同的方法,產生不同的執行結果,增加代碼的靈活度
3.1 繼承
3.1.1 單繼承
繼承的概念:子類 擁有 父類 以及 父類的父類 中封裝的所有 屬性 和 方法。
class 類名(父類名):
pass
當 父類 的方法實現不能滿足子類需求時,可以對方法進行重寫(override)重寫 父類方法有兩種情況:
- 覆蓋 父類的方法:父類的方法實現 和 子類的方法實現完全不同
具體的實現方式,就相當于在 子類中 定義了一個 和父類同名的方法并且實現。 - 對父類方法進行 擴展:子類的方法實現 中 包含 父類的方法實現
在子類中 重寫 父類的方法;在需要的位置使用 super().父類方法 來調用父類方法的執行代碼;其他的位置針對子類的需求,編寫 子類特有的代碼實現。
關于 super
- 在 Python 中 super 是一個 特殊的類
- super()就是使用 super 類創建出來的對象
- 最常 使用的場景就是在 重寫父類方法時,調用 在父類中封裝的方法實現
調用父類方法的另外一種方式:在 Python 2.x 時,如果需要調用父類的方法,還可以使用以下方式:父類名.方法(self)。目前在 Python 3.x 還支持這種方式,但不推薦使用,因為一旦 父類發生變化,方法調用位置的 類名 同樣需要修改。
父類的 私有屬性 和 私有方法
子類對象 不能 在自己的方法內部,直接 訪問 父類的 私有屬性 或 私有方法子類對象 可以通過 父類 的 公有方法 間接 訪問到 私有屬性 或 私有方法
私有屬性、方法 是對象的隱私,不對外公開,外界 以及 子類 都不能直接訪問 私有屬性、方法 通常用于做一些內部的事情
3.1.2 多繼承
子類 可以擁有 多個父類,并且具有 所有父類 的 屬性 和 方法,例如:孩子 會繼承自己 父親 和 母親 的 特性。
class 子類名(父類名1, 父類名2...):
pass
Python 中的 MRO算法(Method Resolution Order)
- 如果 不同的父類 中存在 同名的方法,子類對象 在調用方法時,會調用 哪一個父類中的方法呢?
提示:開發時,應該盡量避免這種容易產生混淆的情況! —— 如果 父類之間 存在 同名的屬性或者方法,應該 盡量避免使用多繼承。 - Python 中針對 類 提供了一個 內置屬性__mro__ 可以查看 方法 搜索順序 在搜索方法時,是按照 mro 的輸出結果 從左至右 的順序查找的 如果在當前類中 找到方法,就直接執行,不再搜索 如果 沒有找到,就查找下一個類 中是否有對應的方法,如果找到,就直接執行,不再搜索 如果找到最后一個類,還沒有找到方法,程序報錯
MRO 是 method resolution order —— 方法搜索順序,主要用于 在多繼承時判斷 方法、屬性 的調用 路徑
新式類與舊式(經典)類
- 新式類:以 object 為基類的類,推薦使用
- 經典類:不以 object為基類的類,不推薦使用
在 Python 3.x 中定義類時,如果沒有指定父類,會 默認使用 object作為該類的 基類 —— Python 3.x 中定義的類都是 新式類,在 Python 2.x 中定義類時,如果沒有指定父類,則不會以 object 作為 基類。
- 為了保證編寫的代碼能夠同時在 Python 2.x 和 Python 3.x 運行!今后在定義類時,如果沒有父類,建議統一繼承自 object:
class 類名(object):
pass
object 是 Python 為所有對象提供的 基類,提供有一些內置的屬性和方法,可以使用 dir(object) 函數查看。
3.2 多態
面向對象三大特性:
- 封裝 根據 職責 將 屬性 和 方法 封裝 到一個抽象的 類 中 定義類的準則
- 繼承 實現代碼的重用,相同的代碼不需要重復的編寫 設計類的技巧 子類針對自己特有的需求,編寫特定的代碼
- 多態 不同的 子類對象 調用相同的 父類方法,產生不同的執行結果 增加代碼的靈活度 以 繼承 和 重寫父類方法 為前提 調用方法的技巧,不會影響到類的內部設計
多態 更容易編寫出出通用的代碼,做出通用的編程,以適應需求的不斷變化!
案例:在 Dog 類中封裝方法 game:普通狗只是簡單的玩耍定義 XiaoTianDog 繼承自 Dog,并且重寫 game 方法:哮天犬需要在天上玩耍定義 Person 類,并且封裝一個 和狗玩 的方法:在方法內部,直接讓 狗對象 調用 game 方法
多態示例
Person 類中只需要讓 狗對象 調用 game 方法,而不關心具體是 什么狗。
4. 類屬性和類方法
4.1 類的結構
通常會把:創建出來的 對象 叫做 類的實例創建對象的 動作 叫做 實例化對象的屬性 叫做 實例屬性對象調用的方法 叫做 實例方法每一個對象 都有自己獨立的內存空間,保存各自不同的屬性多個對象的方法,在內存中只有一份,在調用方法時,需要把對象的引用傳遞到方法內部
各個不同的屬性,獨一份的方法
在 Python 中,類是一個特殊的對象。
Python 中 一切皆對象:
class AAA: 定義的類屬于 類對象 obj1 = AAA() 屬于 實例對象
在程序運行時,類同樣會被加載到內存在程序運行時,類對象在內存中只有一份,使用 一個類可以創建出很多個對象實例除了封裝實例的屬性和方法外,類對象還可以擁有自己的屬性和方法——類屬性、類方法,通過 類名. 的方式可以 訪問類的屬性 或者 調用類的方法
類的結構
4.2 類屬性和實例屬性
類屬性 就是 類對象中定義的屬性通常用來記錄與這個類相關的特征類屬性不會用于記錄具體對象的特征示例:定義一個 工具類,每件工具都有自己的 name:需求 —— 知道使用這個類,創建了多少個工具對象?
屬性的獲取機制
在 Python 中 屬性的獲取 存在一個 向上查找機制
因此,要訪問類屬性有兩種方式:
- 類名.類屬性
- 對象.類屬性 (不推薦,因為如果使用 對象.類屬性 = 值 賦值語句,只會給對象添加一個屬性,而不會影響到類屬性的值)
4.3 類方法和靜態方法
4.3.1 類方法
- 類屬性 就是針對 類對象 定義的屬性 使用 賦值語句 在 class 關鍵字下方可以定義 類屬性 類屬性 用于記錄 與這個類相關 的特征
- 類方法 就是針對 類對象 定義的方法 在 類方法 內部可以直接訪問 類屬性 或者調用其他的 類方法
語法如下
@classmethod
def 類方法名(cls):
pass
- 類方法需要用 修飾器 @classmethod 來標識,告訴解釋器這是一個類方法
- 類方法的 第一個參數 應該是 cls 由 哪一個類 調用的方法,方法內的 cls 就是 哪一個類的引用 這個參數和 實例方法 的第一個參數是 self 類似 提示 使用其他名稱也可以,不過習慣使用 cls
- 通過 類名. 調用 類方法,調用方法時,不需要傳遞 cls 參數
- 在方法內部 可以通過 cls. 訪問類的屬性 也可以通過 cls. 調用其他的類方法
示例
- 定義一個 工具類,每件工具都有自己的 name
- 需求 —— 在 類 封裝一個 show_tool_count 的類方法,輸出使用當前這個類,創建的對象個數
@classmethod
def show_tool_count(cls):
"""顯示工具對象的總數"""
print("工具對象的總數 %d" % cls.count)
4.3.2 靜態方法
- 在開發時,如果需要在 類 中封裝一個方法,這個方法: 既 不需要 訪問 實例屬性 或者調用 實例方法 也 不需要 訪問 類屬性 或者調用 類方法
- 這個時候,可以把這個方法封裝成一個 靜態方法
語法如下
@staticmethod
def 靜態方法名():
pass
- 靜態方法 需要用 修飾器 @staticmethod 來標識,告訴解釋器這是一個靜態方法
- 通過 類名. 調用 靜態方法
示例:
- 靜態方法 show_help 顯示游戲幫助信息
- 類方法 show_top_score 顯示歷史最高分
- 實例方法 start_game 開始當前玩家的游戲
探索:
- 實例方法 —— 方法內部需要訪問 實例屬性 實例方法 內部可以使用 類名. 訪問類屬性
- 類方法 —— 方法內部 只需要訪問 類屬性
- 靜態方法 —— 方法內部,不需要訪問 實例屬性 和 類屬性
5. 單例
5.1 單例設計模式
- 設計模式 設計模式 是 前人工作的總結和提煉,通常,被人們廣泛流傳的設計模式都是針對 某一特定問題 的成熟的解決方案 使用 設計模式 是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
- 單例設計模式 目的 —— 讓 類 創建的對象,在系統中 只有 唯一的一個實例 每一次執行 類名() 返回的對象,內存地址是相同的
- 單例設計模式的應用場景 音樂播放 對象 回收站 對象 打印機 對象 ……
5.2 靜態方法: __new__
- 使用 類名() 創建對象時,Python 的解釋器 首先 會 調用 __new__ 方法為對象 分配空間
- __new__ 是一個 由 object 基類提供的 內置的靜態方法,主要作用有兩個: 在內存中為對象 分配空間 返回 對象的引用
- Python 的解釋器獲得對象的 引用 后,將引用作為 第一個參數,傳遞給 __init__ 方法
重寫 __new__ 方法 的代碼非常固定!
- 重寫 __new__ 方法 一定要 return super().__new__(cls),否則 Python 的解釋器 得不到 分配了空間的 對象引用,就不會調用對象的初始化方法
- 注意:__new__ 是一個靜態方法,在調用時需要 主動傳遞 cls 參數
5.3 Python 中的單例
- 單例 —— 讓 類 創建的對象,在系統中 只有 唯一的一個實例 定義一個 類屬性,初始值是 None,用于記錄 單例對象的引用 重寫 __new__ 方法 如果 類屬性 is None,調用父類方法分配空間,并在類屬性中記錄結果 返回 類屬性 中記錄的 對象引用
只執行一次初始化工作
- 在每次使用 類名() 創建對象時,Python 的解釋器都會自動調用兩個方法: __new__ 分配空間 __init__ 對象初始化
- 在對 __new__ 方法改造之后,每次都會得到 第一次被創建對象的引用
- 但是:初始化方法還會被再次調用
需求
- 讓 初始化動作 只被 執行一次
解決辦法
- 定義一個類屬性 init_flag 標記是否 執行過初始化動作,初始值為 False
- 在 __init__ 方法中,判斷 init_flag,如果為 False 就執行初始化動作
- 然后將 init_flag 設置為 True
- 這樣,再次 自動 調用 __init__ 方法時,初始化動作就不會被再次執行 了
Tips
1、Python 能夠自動的將一對括號內部的代碼連接在一起:
'''
**需求**
* 定義 `input_password` 函數,提示用戶輸入密碼
* 如果用戶輸入長度 < 8,拋出異常
* 如果用戶輸入長度 >=8,返回輸入的密碼
'''
def input_password():
# 1. 提示用戶輸入密碼
pwd = input("請輸入密碼:")
# 2. 判斷密碼長度,如果長度 >= 8,返回用戶輸入的密碼
if len(pwd) >= 8:
return pwd
# 3. 密碼長度不夠,需要拋出異常
# 1> 創建異常對象 - 使用異常的錯誤信息字符串作為參數
ex = Exception("密碼長度不夠")
# 2> 拋出異常對象
raise ex
try:
user_pwd = input_password()
print(user_pwd)
except Exception as result:
print("發現錯誤:%s" % result)
2、一個對象的 屬性 可以是 另外一個類創建的對象。3、在__init__方法中定義類的屬性時,如果 不知道設置什么初始值,可以設置為 None):None 關鍵字 表示 什么都沒有,表示一個 空對象,沒有方法和屬性,是一個特殊的常量。可以將 None 賦值給任何一個變量。
在 Python 中針對 None 比較時,建議使用is 判斷
4、eval() 函數十分強大 —— 將字符串 當成 有效的表達式 來求值 并 返回計算結果
在開發時千萬不要使用 eval 直接轉換 input 的結果,舉個例子:
看完這篇文章,你的Python基礎就差不多了__import__('os').system('ls')
# 等價代碼
import os
os.system("終端命令")