學習Python進階!!!
類與物件
類
類,簡單理解就相當於一個圖紙,在程式中需要根據類來建立物件,類就是物件的圖紙,而物件是類的例項
物件的建立流程
- 建立一個變數
- 在記憶體中建立一個新物件
- 執行類中程式碼塊中的程式碼
- init__(self)方法執行
- 將物件的id賦值給變數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-L005Elha-1611136578559)(images/圖片1.png)]
類的定義
類和物件都是對現實生活的或者程式中的內容的抽象
類的組成:
- 資料(屬性)
- 行為(方法)
呼叫方法,物件.方法名()
方法呼叫和函式呼叫的區別:
- 函式呼叫,則呼叫時傳幾個引數,就會有幾個實參
- 方法呼叫,預設傳遞一個引數,所以方法中至少有一個形參
class Person:
name = 'May'
def sayHello(param):
print("世界", '你好')
per = Person()
print(per.sayHello())
類的特殊方法init
類的基本結構:
class 類名([父類]):
公共的屬性...
# 物件的初始化方法
def _init_(self,...):
...
# 其它方法
def mothod(self,..):
...
例項:
class Person:
def __init__(self, name):
# print('特殊方法執行')
self.name = name
def sayHello(self):
print("%s 你好" % self.name)
per = Person("世界")
per.sayHello()
封裝
封裝指的是隱藏物件中一些不希望被外部所訪問到的屬性和方法
封裝方法一
需要提供一個getter和setter方法使外部可以訪問到屬性
- getter:獲取物件中的指定屬性
- setter:用來設定物件的指定屬性
class Dog:
def _init_(self, name):
self.hidden_name = name
def sayHello(self):
print("我是 %s" % self.hidden_name)
def getName(self):
return self.hidden_name
def setName(self, name):
self.hidden_name = name
dog = Dog("小黑")
dog.sayHello()
封裝方法二
可以為物件的屬性使用雙下劃線開頭,_XXX雙下劃線開頭的屬性,是物件的隱藏屬性,隱藏屬性只能在類的內部訪問,無法通過物件訪問
注意:其實隱藏屬性只不過是Python自動為屬性改的一個名字,實際上是將名字修改為,_類名__屬性名
class Person:
def __init__(self, name):
self.__name = name
def getName(self):
return self.__name
def setName(self, name):
self.__name = name
per = Person("May")
封裝方法三
property裝飾器:用來將一個get方法轉換為物件的屬性,新增property裝飾器以後我們就可以像呼叫屬性一樣使用get方法,使用property裝飾的方法,必須和屬性名一樣
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
# setter 方法的裝飾器:@name.setter
@name.setter
def name(self, name):
self._name = name
per = Person("May")
per.name = 'May五月'
print(per.name)
繼承
繼承的簡介
繼承可以使一個類獲取其它類中的屬性和方法,在定義類時,可以在類名後的括號中指定當前類的父類(超類、基類、super),通過繼承之後子類可以直接繼承父類中的所有的屬性和方法
class Animal:
def run(self):
print('跑跑跑.....')
def bark(self):
print('叫叫叫.....')
class Dog(Animal):
def sleep(self):
print('睡覺時間到了.....')
class Hashiqi(Dog):
def name(self):
print('我是哈士奇.....')
animal = Dog()
dog = Hashiqi()
animal.bark()
dog.name()
當我們呼叫一個物件的方法時:
會優先去當前物件中尋找是否具有該方法,如果有則直接呼叫
如果沒有,則去當前物件的父類中尋找,如果父類中有則直接呼叫父類中的方法
如果沒有,則去父類的父類中尋找,以此類推,直到找到object,如果依然沒有找到,則報錯
super()
class Animal:
def __init__(self, name):
self._name = name
def run(self):
print('跑跑跑.....')
def bark(self):
print('叫叫叫.....')
class Dog(Animal):
def __init__(self, name, age):
super().__init__(name)
self._age = age
def sleep(self):
print('睡覺時間到了.....')
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
animal = Dog('May', 18)
print(animal.name)
print(animal.age)
在Python中支援多繼承,也就是我們可以為一個類同時指定多個父類,可以在類名的()後邊新增多個類,來實現多重繼承,多重繼承,會使子類同時擁有多個父類,並且會獲取到所有父類中方法
類名._bases_這個屬性可以用來獲取當前類的所有父類
在開發中沒有特殊的情況下,應該避免使用多繼承,因為多重繼承會讓我們的程式碼過於複雜
多型
簡介
一個物件可以以不同的形態去呈現
面向物件三大特徵:
- 封裝
- 確保物件中的資料安全
- 繼承
- 保證了物件的可擴充套件性
- 多型
- 保證了程式的靈活性
屬性和方法
類屬性和方法
類屬性:
定義:直接在類中定義的屬性是類屬性
類屬性可以通過類或者類的例項訪問到,但是類屬性只能通過類物件來修改,無法通過例項物件來修改
類方法:
在類內部使用@classmethod來修飾的方法屬於類方法
類方法的第一個引數是cls,也會被自動傳遞,cls就是當前的類物件
類方法和例項方法的區別,例項方法的第一個引數是self,類方法的第一個引數是cls
類方法可以通過類方法呼叫,也可以通過例項呼叫,沒有區別
例項屬性
定義:通過例項物件新增的屬性屬於例項屬性
例項屬性只能通過例項物件來訪問和修改,類物件無法訪問修改
例項方法:
在類中定義,以self為第一個引數的方法都是例項方法
例項方法在呼叫時,Python會將呼叫物件作為self傳入
例項方法可以通過通過例項和類去呼叫
當通過例項呼叫時,會自動將當前呼叫物件作為self傳入
當通過類呼叫時,不會自動傳遞self,此時我們必須手動傳遞self
靜態方法
在類中使用@staticmethod來修飾的方法屬於靜態方法
靜態方法不需要指定任何的預設引數,靜態方法可以通過類和例項去呼叫
靜態方法,基本上是一個和當前類無關的方法,它只是一個儲存在當前類中函式
靜態方法一般都是一些工具方法,和當前類無關
class Person:
"""
類屬性可以通過類或者類的例項訪問到,
但是類屬性只能通過類物件來修改,
無法通過例項物件來修改
"""
count = 0
# 類方法可以通過類方法呼叫,也可以通過例項呼叫
@classmethod
def person(cls):
print("該方法是類方法...")
# 例項方法
# 例項方法可以通過通過例項和類去呼叫
# 當通過例項呼叫時,會自動將當前呼叫物件作為self傳入
# 當通過類呼叫時,不會自動傳遞self,此時我們必須手動傳遞self
def instance(self):
print(self, "呼叫該方法...")
per = Person()
per.count = 5
# 通過例項物件和類物件呼叫類屬性
print(per.count)
print(Person.count)
# 通過例項物件和類物件呼叫類方法
per.person()
Person.person()
# 通過例項物件和類物件呼叫例項方法
per.instance()
Person.instance(per)
特殊方法
特殊方法也稱為魔術方法。
特殊方法都是使用____開頭和結尾的,特殊方法一般不需要手動呼叫,需要在一些特殊的情況下自動執行
- r_str_()這個特殊方法會在嘗試將物件轉換為字串的時候呼叫
- 它的作用可以用來指定物件轉換為字串的結果
- r_repr_()這個特殊方法會在對當前物件使用repr()函式時呼叫
- 它的作用是指定物件在“互動模式”中直接輸出的效果
- r_gt_()會在物件做大於比較的時候呼叫,該方法的返回值將會作為比較的結果
- 它需要兩個引數,一個self表示當前物件,other表示和當前物件比較的物件
- ….特殊方法有很多
模組化
模組化:將一個程式分解為一個一個小的模組
模組化的特點:
- 方便開發
- 方便維護
- 模組可以複用
在一個模組中引入外部模組
-
import 模組名(模組名就是python檔案的名字)
-
import 模組名 as 模組別名
- 可以引入同一個模組多次,但是模組的例項只會建立一個
- import可以在程式的任何位置呼叫,但是在一般情況下,import語句都會統一寫在程式的開頭
- 在每一個模組的內部都會有一個__name__屬性,通過這個屬性可以獲取模組的名字
- 主模組就是我麼直接通過 python 執行的模組
-
from 模組名 import 模組中需要的部分
-
from 模組名 import *
- 匯入模組中的所有內容
- 但是如果想限制獲取的內容,可以在模組中使用____all = [使用*可以訪問到的內容]
包中init檔案
只要匯入包,包中的init檔案就會首先執行
作用:
- 但匯入包的時候,把一些初始化的函式、變數、類定義在__init__.py檔案中
- 此檔案中函式,變數等的訪問,只需要通過包名.函式…
- 結合__all__= [通過 * 可以訪問的模組]
正則表示式
正則表示式是對字串操作的一種邏輯公式,就是事先定義一些特定的字元,及這些字元的組合,組成一個規則字串,這個規則字串就稱為正則表示式
正則表示式又稱為正則表式式,規則表示式,常規表示式
正則表示式的作用:
- 給定的字串是否符合正則表示式的過濾邏輯
- 可以通過正則表示式,從字串中獲取我們想要的特定部分
正則表示式的特點:
- 靈活性、邏輯性和功能性非常強
- 可以迅速的用極簡單的方式達到字串的複雜控制
- 對於剛接觸的人來說,比較難懂
正則表示式模組中方法
match 匹配方法是從頭進行匹配,如果匹配不成功就返回None
search 方法進行正則字串匹配方法,匹配的是整個字串
group 用來提取匹配到的內容部分
sub 替換
split 分割
# 匯入正則表示式模組
import re
str = '五月六月七月'
# match 匹配方法是從頭進行匹配,如果匹配不成功就返回None
result = re.match('五月', str)
print(result.span())
# search 方法進行正則字串匹配方法,匹配的是整個字串
result1 = re.search('七月', str)
print(result1.span())
# group 用來提取匹配到的內容部分
print(result.group())
print(result1.group())
匹配字元:
-
. 表示任意的字元
-
^是開頭
-
$表示的是結尾
-
[] 表示的是一個範圍
-
*用於將前面的模式匹配零次或者是多次
-
+用於將前面的模式匹配一次或者是多次
-
?用於將前面的模式匹配一次或者是零次
-
{m} 用於驗證前面的模式匹配 m 次
-
{m,}用於驗證將前面的模式匹配 m 次或者大於 m 次
-
{m, n}用於驗證前面的模式匹配大於等於 m 小於等於 n 次
# 匯入正則表示式模組
import re
str = 'adsa46da56'
# [] 表示的是一個範圍
# search 方法匹配到一個就不在繼續往下找
result = re.search('[a-z][0-9][0-9]', str)
print(result.group())
# findall 方法匹配整個字串,找到一個繼續向下找,一直找到字串的結尾
result1 = re.findall('[a-z][0-9][0-9]', str)
print(result1)
result2 = re.findall('[a-z][0-9]+', str)
print(result2)
\A:表示從字串的開始出匹配
\Z:表示從字串的結束處開始匹配,如果存在換行,只匹配到換行前的結束字串。
\b:匹配一個單詞邊界,也就是指單詞和空格間的位置。例如'py\b'可以匹配到'python'中的'py'
\B:匹配非單詞邊界
\d:匹配任意數字,等價於[0-9]
\D:匹配任意非數字字元
\s:匹配任意空白字元
\S:匹配任意非空白字元
\w:匹配任意字母數字及下劃線
\W:匹配任意非字母數字及下劃線
\\:匹配原意的反斜槓
分組匹配
()表示分組,group(1) 表示第一組的內容,group(2) 表示第二組的內容
import re
msg = '<html>abc</html>'
result = re.match(r'<[0-9a-zA-Z]>(.+)</\1>')
print(result.group(1))
起名
起名的方式為:(?P<起的名字>)
引用:</(?P=起的名字)>
貪婪和非貪婪
貪婪:總是嘗試匹配儘可能多的字元
非貪婪:總是匹配儘可能少的字元
如果貪婪模式想轉變為非貪婪模式,只需要在正則表示式的後面加上==?==,預設是貪婪的
import re
# 預設是貪婪的,如果想將貪婪模式變為非貪婪模式,只需要在正則表示式後面加上?即可
msg = 'abc123as'
result = re.match(r'abc(\d+?)', msg)
print(result)
程序
異常
處理異常的語句:
try:
程式碼塊(可以出現錯誤的語句)
except:
程式碼塊(出現錯誤之後的處理方式)
else:
程式碼塊(沒有錯誤是要執行的語句)
finally:
程式碼塊(該程式碼塊總會執行)
異常傳播:當在函式中出現異常時,如果對異常進行處理,則異常不會再繼續傳播,如果沒有對異常進行處理,則異常會繼續向函式呼叫處傳播,如果函式呼叫處處理了異常,則不會傳播,如果沒有處理則繼續向呼叫處傳播,直到傳遞到全域性作用域(主模組)如果依然沒有處理異常,則程式終止,顯示異常資訊。
當程式執行過程中出現異常後,所有的異常資訊都會儲存到一個專門的異常物件中,而異常傳播就是異常物件拋給了呼叫處
異常物件
- 如果except後面不跟任何內容,則此時會捕獲到所有的異常;
- 如果在except後面跟上一個異常的型別,則此時只會捕獲該型別的異常;
print('異常執行前:')
try:
print(May)
# print(10/0)
except NameError:
print('出現 NameError 錯誤')
except ZeroDivisionError:
print('出現 ZeroDivisionError 錯誤')
except IndexError:
print('出現 IndexError 錯誤')
# Exception 是所有異常類的父類,所以如果except後跟的是Exception,它也會捕捉到所有的異常
# 可以在異常類後面跟著一個 as xx 此時 xx 就是異常物件
except Exception as e:
print('未知異常', e)
finally:
print('該段程式總會執行')
print('異常出現後')
自定義異常物件
自定義異常的格式:
class 類名(Exception):
程式碼塊
raise:可以向外部丟擲異常,後面可以跟一個異常類,或者是異常類的例項
# 自定義異常
class MyException(Exception):
pass
# 求兩個數的和,要求兩個數不能是負數
def add(a, b):
if a < 0 or b < 0:
raise MyException('出現負數')
r = a + b
return r
print(add(-23, 32))
檔案
開啟檔案
python通過呼叫open()來開啟一個檔案,可以將檔案分成兩種型別
- 純文字檔案(使用utf-8等編碼編寫的檔案)
- 二進位制檔案(圖片、mp3、PPT等檔案)
open()開啟檔案時預設是以文字的形式開啟的,但是open(),預設的編碼是None所以處理檔案時,補習指定檔案的編碼
file_name = 'File.txt'
try:
with open(file_name, encoding = 'utf-8') as file_obj:
print(file_obj.read())
except Exception as e:
print('未知錯誤', e)
讀取檔案和關閉檔案
**read()**方法用來讀取檔案中的內容,它會將內容全部儲存為一個字串返回。read()引數預設是-1,一次讀取所有的字元,如果給read()寫入引數n,則一次讀取n個字元
**close()**用來關閉已經開啟的檔案
# 開啟檔案
file_name = 'File.txt'
file_obj = open(file_name)
# 當我們獲取了檔案物件以後,所有的檔案的操作都應該通過物件進行
# read()方法用來讀取檔案中的內容,它會將內容全部儲存為一個字串返回
centent = file_obj.read()
print(centent)
# 關閉檔案
file_obj.close()
讀取大檔案:
file_name = 'File.txt'
try:
with open(file_name, encoding="utf-8") as file_obj:
# 定義一個變數,來指定每次讀取的大小
chunk = 100
while True:
content = file_obj.read(chunk)
# 檢查是否讀取到了內容
if not content:
break
print(content)
except FileNotFoundError:
print(f'{file_name} 這個檔案不存在')
with…as 語句
在with語句中可以直接使用file_obj來做檔案操作,此時這個檔案只能在with中使用,一旦with結束後文件自動關閉
file_name = 'File.txt'
try:
with open(file_name) as file_obj:
print(file_obj.read())
except Exception as e:
print('未知錯誤', e)
寫入檔案
引數表示的含義:
-
r 表示只讀
-
x 表示用來建立檔案,如果檔案不存在就建立,存在則報錯
-
w 表示可以,使用 w 來寫入檔案時,如果檔案不存在會建立檔案,如果檔案存在則會截斷檔案
截斷檔案指的是刪除原來檔案中的所有內容
-
a 表示追加內容,如果檔案不存在會建立檔案,如果檔案存在會向檔案中追加內容
-
+為操作符增加功能
-
r+ 即可讀又可寫,檔案不存在會報錯
-
w+ 即可寫又可讀
-
a+ 即可追加又可讀
-
file_name = 'File.txt'
# 使用open()開啟檔案必須要指定開啟檔案所需要做的操作(讀、寫、追加)
# 如果不指定操作型別,則預設是讀取檔案,而讀取檔案是不能向檔案中寫入的
# r 表示只讀
# x 表示用來建立檔案,如果檔案不存在則建立愛你,存在則報錯
# w 表示可以,使用 w 來寫入檔案時,如果檔案不存在會建立檔案,如果檔案存在則會截斷檔案
# 截斷檔案指的是刪除原來檔案中的所有內容
# a 表示追加內容,如果檔案不存在會建立檔案,如果檔案存在會向檔案中追加內容
# + 為操作符增加功能
# r+ 即可讀又可寫,檔案不存在會報錯
# w+ 即可寫又可讀
# a+ 即可追加又可讀
with open(file_name, 'w', encoding='utf-8') as file_obj:
file_obj.write("有時候,我們活得累,")
file_obj.write('並非生活過於刻薄,而是我們太容易被外界的氛圍所感染,')
file_obj.write('被他人的情緒所左右')
二進位制檔案
-
b 表示讀取二進位制檔案
-
讀取文字檔案時,是以字元為單位的
-
讀取二進位制檔案時,是以位元組為單位的
file_name = '二進位制檔案的路徑'
# t 讀取文字檔案
# b 讀取二進位制檔案
with open(file_name, 'rb') as file_obj:
# 讀取文字檔案時,size是以字元為單位的
# 讀取二進位制檔案時,size是以位元組為單位的
# 將讀到的二進位制檔案再寫入檔案中
new_name = '寫入檔案的名稱'
with open(new_name, 'ab') as new_obj:
# 定義每次讀取的大小
chunk = 100 * 1024
while True:
# 從已有物件中讀取資料
content = file_obj.read(chunk)
if not content:
break
new_obj.write(content)
seek()和tell()
seek():可以修改當前讀取的位置
seek():需要兩個引數
- 第一個 引數,是要切換到的位置
- 第二個引數,計算位置的方式
- 0 從頭計算,預設值
- 1 從當前位置計算
- 2 從最後位置開始計算