Python高級基礎

Python高級基礎

1.文件

1.1文件操作步驟

  • 打開文件

  • 讀寫等操作

  • 關閉文件

1.1.1文件操作的函數/方法

序號 函數/方法 說明
01 open 打開文件,並且返回文件操作對象
02 read 將文件內容讀取到內存
03 write 將指定內容寫入文件
04 close 關閉文件
  • open 函數負責打開文件,並且返回文件對象

  • read/write/close 三個方法都需要通過 文件對象 來調用

  • open 函數的第一個參數是要打開的文件名(文件名區分大小寫)

    • 如果文件 存在,返回 文件操作對象

    • 如果文件 不存在,會 拋出異常

  • read 方法可以一次性 讀入返回 文件的 所有內容

  • close 方法負責 關閉文件

1)打開/寫入文件

在Python中,使用open函數,可以打開一個已經存在的文件,或者創建一個新文件,語法如下:

 open(name, mode)

name:是要打開目標文件名的字符串(可以包含文件所在的具體路徑)

mode:設置打開文件的模式(訪問模式):只讀、寫入、追加等

訪問方式 說明
r 只讀方式打開文件。文件的指針將會放在文件的開頭,這是默認模式。如果文件不存在,拋出異常
w 只寫方式打開文件。如果文件存在會被覆蓋。如果文件不存在,創建新文件
a 追加方式打開文件。如果該文件已存在,文件指針將會放在文件的結尾。如果文件不存在,創建新文件進行寫入
r+ 讀寫方式打開文件。文件的指針將會放在文件的開頭。如果文件不存在,拋出異常
w+ 讀寫方式打開文件。如果文件存在會被覆蓋。如果文件不存在,創建新文件
a+ 讀寫方式打開文件。如果該文件已存在,文件指針將會放在文件的結尾。如果文件不存在,創建新文件進行寫入

提示

  • 頻繁的移動文件指針,會影響文件的讀寫效率,開發中更多的時候會以 只讀只寫 的方式來操作文件

打開文件並進行寫入示例

 # 打開文件
 f = open("README", "w")
 ​
 f.write("hello python!\n")
 f.write("今天天氣真好")
 ​
 # 關閉文件
 f.close()

2)讀取文件

1. read()

 文件對象.read(num)

num表示要從文件中讀取的數據的長度(單位都是字節),如果沒有傳入num,那麼就表示讀取文件的所有數據

一次性讀取文件內容

 # 1. 打開 - 文件名需要注意大小寫
 file = open("README")
 ​
 # 2. 讀取
 text = file.read()
 print(text)
 ​
 # 3. 關閉
 file.close()

注意read 方法執行後,會把 文件指針 移動到 文件的末尾

文件指針

  • 文件指針 標記 從哪個位置開始讀取數據

  • 第一次打開 文件時,通常 文件指針會指向文件的開始位置

  • 當執行了 read 方法後,文件指針 會移動到 讀取內容的末尾

    • 默認情況下會移動到 文件末尾

2. readlines()

readlines可以按照行的方式把整個文件中的內容按行進行一次性讀取,並且返回的是一個列表,其中每一行的數據爲一個元素

 fp = open("E:\student.txt", "r")
 result = fp.readlines()
 print(result)  # ['aaa\n', 'bbb\n', 'ccc\n', 'ddd']
 fp.close()

3. readline()

  • readline 方法可以一次讀取一行內容

  • 方法執行後,會把 文件指針 移動到下一行,準備再次讀取,適用於讀取大文件

讀取大文件的正確姿勢

 # 打開文件
 file = open("README")
 ​
 while True:
     # 讀取一行內容
     text = file.readline()
 ​
     # 判斷是否讀到內容
     if not text:
         break
 ​
     # 每讀取一行的末尾已經有了一個 `\n`
     print(text, end="")
 ​
 # 關閉文件
 file.close()

1.1.2 r+ 和 w+ 和 a+ 區別

 """
 1. r+ 和 w+ a+區別
 2. 文件指針對數據讀取的影響
 3. test.txt已存在並且有數據,test1.txt不存在
 """
 # r+: 文件不存在則報錯,文件指針在開頭,能夠讀出數據
 # f = open('test1.txt', 'r+')
 # f = open('test.txt', 'r+')
 ​
 # w+:文件不存在會新建文件,文件指針在開頭,讀數據時會用新內容覆蓋原內容
 # f = open('test1.txt', 'w+')
 # f = open('test.txt', 'w+')
 ​
 # a+:文件不存在會新建文件,文件指針在末尾,不能夠讀出數據
 f = open('test1.txt', 'a+')
 f = open('test.txt', 'a+')
 con = f.read()
 print(con)
 ​
 f.close()

1.1.3 seek()

作用:用來移動文件指針

語法如下:

 文件對象.seek(偏移量, 起始位置)

起始位置:

  • 0:文件開頭

  • 1:當前位置

  • 2:文件結尾

# r 改變文件指針位置:改變讀取數據開始位置或把文件指針放在末尾(無法讀取數據)
fp = open('E:/student.txt', 'r')

# 改變文件指針,讀取改變後的數據
fp.seek(6, 0)
# 文件指針放在末尾(無法讀取數據)
# fp.seek(0, 2)
con = fp.read()
print(con)

fp.close()

1.2 文件備份

需求:用戶輸入當前目錄下任意文件名,程序完成對該文件的備份功能(備份文件名爲xx[備份]後綴,例如:test[備份].txt)

1.2.1步驟

  1. 接收用戶輸入的文件名

  2. 規劃備份文件名

  3. 備份文件寫入數據

1.2.2代碼實現

# 1.接收用戶輸入目標文件
old_name = input('請輸入你要備份的文件名:')

# 2.規劃備份文件的名字
# 2.1提取目標文件後綴
index = old_name.rfind('.')
# 2.2有效文件才備份
if index > 0:
    postfix = old_name[index:]
else:
    print("輸入文件名無效!")
# 2.3組織新文件名:舊文件名 + [備份] + 後綴
new_name = old_name[:index] + '[備份]' + postfix
print(new_name)

# 3.備份文件寫入數據(數據和原文件一樣)
# 3.1打開文件
old_fp = open(old_name, 'rb')
new_fp = open(new_name, 'wb')

# 3.2將原文件數據寫入備份文件
while True:
    con = old_fp.read(1024)
    if len(con) == 0:
        break
    new_fp.write(con)

# 3.3關閉文件
old_fp.close()
new_fp.close()

1.3文件和文件夾的操作

在Python中文件和文件夾的操作要藉助os模塊裏面的相關功能,具體步驟如下:

  1. 導入os模塊

    import os
  2. 使用os模塊相關功能

os.函數名()

1.3.1文件重命名

os.rename(目標文件名,新文件名)

1.3.2刪除文件

os.remove(目標文件名)
# 導入模塊os
import os

# 1.rename():重命名
os.rename('test.txt', 'lyc.txt')

# 2.remove():刪除文件
os.remove('test[備份].txt')

1.3.3創建文件夾

os.mkdir(文件夾名字)

1.3.4刪除文件夾

os.rmdir(文件夾名字)

1.3.5獲取當前目錄

os.getcwd()

1.3.6改變默認目錄

os.chdir(目錄)

1.3.7獲取目錄列表

os.listdir(目錄)
# 導入模塊os
import os

# 1.mkdir():創建文件夾
# os.mkdir('lyc')

# 2.rmdir():刪除文件夾
# os.rmdir('lyc')

# 3.getcwd():獲取當前目錄
path = os.getcwd()
print(path)

# 4.chdir():改變默認目錄路徑
# 需求:在lyc文件夾裏創建文件夾aa
# os.mkdir('lyc')
# os.chdir('lyc')
# os.mkdir('aa')

# 5.listdir():獲取目錄列表
print(os.listdir('lyc'))

# 6.rename():重命名文件夾
os.rename('lyc', 'bb')

1.3.8應用案例

需求:批量修改文件名,既可添加指定字符串,又能刪除指定字符串

  • 步驟

    1. 設置添加刪除字符串的標識

    2. 獲取指定目錄的所有文件

    3. 將原有文件名添加/刪除指定字符串,構造新名字

    4. os.rename()重命名

  • 代碼

# 需求1:把code文件夾所有文件重命名 Python_xxxx
import os

# 設置重命名標識:如果flag取值爲1則添加指定字符,flag取值爲2則刪除指定字符
flag = 1
# 獲取指定目錄
dir_name = './'

# 獲取指定目錄的文件列表
file_list = os.listdir(dir_name)

# 遍歷文件列表內的文件
for name in file_list:
    # 添加指定字符
    if flag == 1:
        new_name = 'Python_' + name
    # 刪除指定字符
    elif flag == 2:
        num = len('Python_')
        new_name = name[num:]
    # 打印新文件名,測試程序正確性
    print(new_name)
    # 重命名
    os.rename(dir_name+name,dir_name+new_name)

2.面向對象

面向對象就是將編程當成一個是一個事物,對外界來說,事物是直接食用的,不用去管他內部的情況。而編程就是設置事物能夠做什麼事

2.1類和對象

在面向對象編程過程中,有兩個重要組成部分:類和對象

類和對象關係:用類去創建一個對象

2.1.1類

類是一系列具有相同特徵和行爲的事物的統稱,是一個抽象概念,不是真實存在的事物

  • 特徵即是屬性

  • 行爲即是方法

2.1.2對象

對象是創建出來的真實存在的事物

2.2面向對象實現方法

2.2.1定義類

Python2中類分爲:經典類和新式類

  • 語法

class 類名():
    代碼
    .......

注意:類名要滿足標識符的命名規則,同時遵循大駝峯命名習慣

2.2.2創建對象

對象又名實例

  • 語法

對象名 = 類名()
  • 體驗

# 需求:洗衣機 功能:洗衣服
# 1.定義洗衣機類
class Washer():
    def wash(self):
        print("洗衣服")

# 2.創建對象
haier = Washer()
# 實例方法  對象名.wash()
haier.wash()

2.2.3self

self指的是調用該函數的對象

# 需求:洗衣機 功能:洗衣服
# 1.定義洗衣機類
class Washer():
    def wash(self):
        print("我會洗衣服")
        # <__main__.Washer object at 0x000001EAE7699A58>
        print(self)

# 2.創建對象
haier = Washer()
# <__main__.Washer object at 0x000001EAE7699A58>
print(haier)
haier.wash()

2.3添加和獲取對象屬性

屬性即是特徵,比如:洗衣機的寬度、高度、重量...

對象屬性既可以是在類外面添加和獲取,也能在類裏面添加和獲取

2.3..1類外面添加對象屬性

  • 語法

對象名.屬性名 = 值
  • 體驗

haier.width = 500
haier.height = 800

2.3.2類外面獲取對象屬性

  • 語法

對象名.屬性名
  • 體驗

print(f'haier洗衣機的寬度是{haier.width}')
print(f'haier洗衣機的高度是{haier.height}')

2.4類裏面獲取對象屬性

  • 語法

self.屬性名
  • 體驗

# 1.定義洗衣機類
class Washer():
    def print_info(self):
        # 類裏面獲取實例屬性
        print(f'haier洗衣機的寬度是{self.width}')
        print(f'haier洗衣機的高度是{self.height}')

# 2.創建對象
haier = Washer()

haier.width = 400
haier.height = 500

haier.print_info()

2.5魔法方法

在Python中,__xx__()的函數叫做魔法方法,指的是具有特殊功能的函數

2.5.1__init__()

2.5.1.1體驗__init__()

__init__方法的作用:初始化對象。

class Washer():
    # 定義__init__,添加實例屬性
    def __init__(self):
        # 添加實例屬性
        self.width = 500
        self.height = 800
        self.color = 'red'

    def print_info(self):
        # 類裏面調用實例屬性
        print(f'洗衣機的寬度是{self.width},高度是{self.height}')

haier = Washer()
# 洗衣機的寬度是500,高度是800
haier.print_info()

注意:

  • __init__()方法,在創建一個對象時默認被調用,不需要手動調用

  • __init__(self)中的self參數,不需要開發者傳遞,python解釋器會自動把當前的對象引用傳遞過去

2.5.1.2帶參數的__init()

思考:一個類可以創建多個對象,如何對不同的對象設置不同的初始化屬性呢?

答:傳參數

class Washer():
    # 定義__init__,添加實例屬性
    def __init__(self, width, height, color):
        # 添加實例屬性
        self.width = width
        self.height = height
        self.color = color

        
    def print_info(self):
        # 類裏面調用實例屬性
        print(f'洗衣機的寬度是{self.width},高度是{self.height},顏色是{self.color}')

        
haier1 = Washer(100, 300, 'red')
haier1.print_info()

haier2 = Washer(400, 500, 'white')
haier2.print_info()

2.5.2__str__()

當使用print輸出對象的時候,默認打印對象的內存地址。如果定義了__str__方法,那麼就會打印從這個方法中return的數據

class Washer():
    # 定義__init__,添加實例屬性
    def __init__(self, width, height, color):
        # 添加實例屬性
        self.width = width
        self.height = height
        self.color = color
	# 解釋說明信息
    def __str__(self):
        return '洗衣機寬度是:' + str(self.width) + ',洗衣機寬度:' + str(self.height) + ',洗衣機顏色是:' + self.color


haier1 = Washer(100, 300, 'red')
print(haier1)

2.5.3__del__()

當刪除對象時,python解釋器也會默認調用__del__()方法

class Washer():
    # 定義__init__,添加實例屬性
    def __init__(self, width, height, color):
        # 添加實例屬性
        self.width = width
        self.height = height
        self.color = color

    def __del__(self):
        print(f'{self}對象已經被刪除')

# <__main__.Washer object at 0x000002C8E3429080>對象已經被刪除
haier1 = Washer(100, 300, 'red')

2.6綜合應用

2.6.1烤地瓜

2.6.1.1需求:

需求:

  1. 被烤的時間和對應的地瓜狀態:

    0-3分鐘:生的

    3-5分鐘:半生不熟

    5-8分鐘:熟的

    超過8分鐘:烤糊了

  2. 添加的調料

    用戶可以按自己的意願添加調料

2.6.2步驟分析

需求涉及一個事物: 地瓜,故案例涉及一個類:地瓜類

2.6.2.1定義類

  • 地瓜的屬性

    • 被烤的時間

    • 地瓜的狀態

    • 添加的佐料

  • 地瓜的方法

    • 被烤

      • 用戶根據意願設定每次烤地瓜的時間

      • 判斷地瓜被烤的總時間是在哪個區間,修改地瓜狀態

    • 添加佐料

      • 用戶根據意願設定添加的佐料

      • 將用戶添加的佐料存儲

  • 顯示對象信息

2.6.2.2代碼實現

class SweetPotato():

    def __init__(self):
        # 被烤的時間
        self.cook_time = 0
        # 烤的狀態
        self.cook_state = '生的'
        # 佐料列表
        self.condiments = []

    def cook(self, time):
        """烤地瓜方法"""
        self.cook_time += time
        if 0 <= self.cook_time < 3:
            self.cook_state = '生的'
        elif 3 <= self.cook_time < 5:
            self.cook_state = '半生不熟的'
        elif 5 <= self.cook_time < 8:
            self.cook_state = '熟了的'
        elif 8 <= self.cook_time:
            self.cook_state = '糊了的'

    def __str__(self):
        return f'這個地瓜烤了{self.cook_time}分鐘,狀態是{self.cook_state},添加的調料有{self.condiments}'

    def add_condiments(self, condiment):
        """添加佐料"""
        self.condiments.append(condiment)


digua1 = SweetPotato()
print(digua1)
digua1.cook(2)
digua1.add_condiments('辣椒麪')
print(digua1)

digua1.cook(2)
digua1.add_condiments('食鹽')
print(digua1)

digua1.cook(2)
digua1.add_condiments('孜然粉')
print(digua1)

2.7繼承

Python面向對象的繼承指的是多個類之間的所屬關係,即子類默認繼承父類的所有屬性和方法,具體如下:

# 父類A
class A(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)


# 子類B
class B(A):
    # 空語句,保持程序的完整性
    pass


result = B()
result.info_print() # 1

在Python中,所有類默認繼承object類,object類是頂級類或基類;其他子類叫派生類

2.7.1單繼承

所謂單繼承就是一個類繼承一個父類

# 1.師父類
class Master(object):
    def __init__(self):
        self.koufu = '[古法煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.koufu}製作煎餅果子')


# 2.徒弟類繼承師父類Master
class Prentice(Master):
    pass

# 3.創建對象daqiu
daqiu = Prentice()
# 4.對象訪問實例屬性
print(daqiu.koufu)
daqiu.make_cake()

2.7.2多繼承

所謂多繼承就是一個類同時繼承多個父類

# 1.師父類
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


# 2.學校類
class School(object):
    def __init(self):
        self.kongfu = '[蜜汁煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


# 2.徒弟類
class Prentice(Master, School):
    pass

# 3.創建對象daqiu
daqiu = Prentice()
# 4.對象訪問實例屬性
# [古法煎餅果子配方]
print(daqiu.kongfu)
# 運用[古法煎餅果子配方]製作煎餅果子
daqiu.make_cake()

注意:當一個類有多個父類的時候,默認使用第一個父類的同名屬性和方法

2.7.3子類重寫父類同名方法和屬性

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class School(object):
    def __init(self):
        self.kongfu = '[蜜汁煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class Prentice(Master, School):
    def __init__(self):
        self.kongfu = '[獨創煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()
# 類名.__mro__得到該類的繼承關係
print(Prentice.__mro__)

注意:當子類重寫父類的同名屬性和方法時,子類創建對象調用屬性和方法時,調用到的是子類中的同名屬性和方法

2.7.4子類調用父類的同名方法和屬性

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class School(object):
    def __init__(self):
        self.kongfu = '[蜜汁煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class Prentice(Master, School):
    def __init__(self):
        self.kongfu = '[獨創煎餅果子配方]'

    def make_cake(self):
        # 如果是先調用了父類的屬性和方法,父類屬性會覆蓋子類的屬性,故在調用屬性前,先調用自己子類的初始化
        self.__init__()
        print(f'運用{self.kongfu}製作煎餅果子')

    def make_master_cake(self):
        # 如要調用父類的同名方法和屬性,必須先調用__init()方法
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)


daqiu = Prentice()
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()
daqiu.make_cake()

2.7.5多層繼承

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class School(object):
    def __init__(self):
        self.kongfu = '[蜜汁煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class Prentice(Master, School):
    def __init__(self):
        self.kongfu = '[獨創煎餅果子配方]'

    def make_cake(self):
        # 如果是先調用了父類的屬性和方法,父類屬性會覆蓋子類的屬性,故在調用屬性前,先調用自己子類的初始化
        self.__init__()
        print(f'運用{self.kongfu}製作煎餅果子')

    def make_master_cake(self):
        # 如要調用父類的同名方法和屬性,必須先調用__init()方法
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)


class Tusun(Prentice):
    pass

daqiu = Tusun()
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()

2.7.6 super()調用父類方法

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class School(Master):
    def __init__(self):
        self.kongfu = '[蜜汁煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')
        # 2.1super()帶參數寫法
        # super(School, self).__init__()
        # super(School, self).make_cake()
        # 2.2super()不帶參數寫法
        super().__init__()
        super().make_cake()

class Prentice(School):
    def __init__(self):
        self.kongfu = '[獨創煎餅果子配方]'

    def make_cake(self):
        # 如果是先調用了父類的屬性和方法,父類屬性會覆蓋子類的屬性,故在調用屬性前,先調用自己子類的初始化
        self.__init__()
        print(f'運用{self.kongfu}製作煎餅果子')

    # 需求:一次性調用父類School,Master的方法
    def make_old_cake(self):
        # 方法一: 如果定義的類名修改,這裏也要修改,麻煩,代碼量大,冗餘
        # Master.__init__(self)
        # Master.make_cake(self)
        # School.__init__(self)
        # School.make_cake(self)

        # 方法二:super()
        # 方法2.1 super(當前類名,self).函數()
        # super(Prentice, self).__init__()
        # super(Prentice, self).make_cake()
        # 2.2super()不帶參數寫法
        super().__init__()
        super().make_cake()
        
        
daqiu = Prentice()
daqiu.make_old_cake()

2.8私有權限

2.8.1定義私有屬性和方法

在Python中,可以爲實例屬性和方法設置私有權限,即設置某個實例屬性或實例方法不繼承給子類。

設置私有權限的方法:在屬性名和方法名前面加上兩個下劃線__

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class School(object):
    def __init__(self):
        self.kongfu = '[蜜汁煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[獨創煎餅果子配方]'
        # 私有屬性
        self.__money = 2000

    # 定義私有方法
    def __info_print(self):
        print(self.kongfu)
        print(self.__money)

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class Tusun(Prentice):
    pass


# 對象不能訪問私有屬性和方法
# daqiu = Prentice()
# print(daqiu.__money)
# daqiu.info_print()

# 子類無法繼承父類的私有屬性和私有方法
# xiaoqiu = Tusun()
# print(xiaoqiu.__money)
# xiaoqiu.__info_print()

2.8.2獲取或修改私有屬性值

在Python中,一般定義函數名get_xx用來獲取私有屬性,定義set_xx用來修改私有屬性值

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class School(object):
    def __init__(self):
        self.kongfu = '[蜜汁煎餅果子配方]'

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[獨創煎餅果子配方]'
        self.__money = 2000
	# 設置私有屬性值
    def set_money(self, money):
        self.__money = money
        
	# 獲取私有屬性值
    def get_money(self):
        return self.__money

    # 定義私有方法
    def __info_print(self):
        print(self.kongfu)
        print(self.__money)

    def make_cake(self):
        print(f'運用{self.kongfu}製作煎餅果子')


class Tusun(Prentice):
    pass


xiaoqiu = Tusun()
xiaoqiu.set_money(200000000)
print(xiaoqiu.get_money())

2.9面向對象三大特性

  • 封裝

    • 將屬性和方法書寫到類的裏面的操作即爲封裝

    • 封裝可以爲屬性和方法添加私有權限

  • 繼承

    • 子類默認繼承父類的所有屬性和方法

    • 子類可以重寫父類的屬性和方法

  • 多態

    • 傳入不同的對象,產生不同的結果

2.9.1多態

多態指的是一類事物有多種形態,(一個抽象類有多個子類,因而多態的概念依賴於繼承)

  • 定義:多態是一種使用對象的方式,子類重寫父類方法,調用不同子類對象的相同父類方法,可以產生不同的執行結果

  • 好處:調用靈活,有了多態,更容易編寫出通用的代碼,做出通用的編程,以適應需求的不斷變化

  • 實現步驟:

    • 定義父類,並提供公共方法

    • 定義子類,並重寫父類方法

    • 傳遞子類對象給調用者,可以看到不同子類執行效果不同

2.9.2體驗多態

class Dog(object):
    def work(self):
        # 父類提供統一方法,哪怕是空方法
        pass


class ArmyDog(Dog):
    # 繼承Dog類
    def work(self):  # 子類重寫父類同名方法
        print("追擊敵人...")


class DrugDog(Dog):
    def work(self):
        print("追查毒品...")


class Person(object):
    def work_with_dog(self, dog):  # 傳入不同的對象,執行不同的代碼,即不同的work函數
        dog.work()


ad = ArmyDog()
dd = DrugDog()

person = Person()
person.work_with_dog(ad)
person.work_with_dog(dd)

2.9.3類屬性和實例屬性

2.9.3.1設置和訪問類屬性

  • 類屬性就是類對象所擁有的屬性,它被該類的所有實例對象所共有

  • 類屬性可以使用類對象或實例對象訪問

class Dog(object):
    tooth = 10


huahua = Dog()
xiaohei = Dog()

print(Dog.tooth)  # 10
print(huahua.tooth)  # 10
print(xiaohei.tooth)  # 10

2.9.3.1.2修改類屬性

類屬性只能通過類對象修改,不能通過實例對象修改,如果通過實例對象修改類屬性,表示的是創建一個實例屬性

class Dog(object):
    tooth = 10


huahua = Dog()
xiaohei = Dog()

# 修改類屬性
Dog.tooth = 12
print(Dog.tooth)  # 12
print(huahua.tooth)  # 12
print(xiaohei.tooth)  # 12

# 不能通過對象修改屬性,如果這樣操作,實則是創建了一個實例屬性
huahua.tooth = 20
print(Dog.tooth)  # 12
print(huahua.tooth)  # 20
print(xiaohei.tooth)  # 12

2.9.4類方法和靜態方法

2.9.4.1類方法

2.9.4.1.1類方法特點

  • 需要用裝飾器@classmethod來標識其爲類方法,對於類方法,第一個參數必須是類對象,一般以cls作爲第一個參數

2.9.4.1.2類方法的使用場景

  • 當方法中需要使用類對象(如訪問私有屬性等)時,定義類方法

  • 類方法一般和類屬性配合使用

class Dog(object):
    __tooth = 10

    @classmethod
    def get_tooth(cls):
        return cls.__tooth


wangcai = Dog()
result = wangcai.get_tooth()
print(result)  # 10

2.9.4.2靜態方法

2.9.4.2.1靜態方法特點

  • 需要通過裝飾器@staticmethod來進行修飾,靜態方法既不需要傳遞類對象也不需要傳遞實例對象(形參沒有self/cls)

  • 靜態方法也能夠通過實例對象和類對象去訪問

2.9.4.2.2靜態方法使用場景

  • 當方法中既不需要使用實例對象(如實例對象,實例屬性),也不需要使用類對象(如類屬性、類方法、創建實例等)時,定義靜態方法

  • 取消不需要的參數傳遞,有利於減少不必要的內存佔用和性能消耗

class Dog(object):
    @staticmethod
    def info_print():
        print("這是一個狗類,用於創建狗實例...")


wangcai = Dog()
# 靜態方法既可以使用對象訪問又可以使用類訪問
wangcai.info_print()
Dog.info_print()

3.異常

3.1瞭解異常

當檢測到一個錯誤時,解釋器無法繼續執行時,反而出現了一些錯誤提示,這就是所謂的“異常”

例如:以r方式打開一個不存在的文件

open('test.txt', 'r')
D:\software\Python\Python37\python.exe E:/PycharmProjects/Python_Base/Python_Test_1/面向對象.py
Traceback (most recent call last):
  File "E:/PycharmProjects/Python_Base/Python_Test_1/面向對象.py", line 1, in <module>
    open('test.txt', 'r')
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'

3.2異常的寫法

3.2.1語法

try:
    可能發生錯誤的代碼
except:
    如果出現異常執行的代碼

3.2.2體驗

需求:嘗試以r模式打開文件,如果文件不存在,則以w方式打開

try:
    f = open('test.txt', 'r')
except:
    f = open('test.txt', 'w')
f.close()

3.3捕獲指定異常

3.3.1語法

try:
    可能發生錯誤的代碼
except 異常代碼:
    如果捕獲到該異常類型執行的代碼

3.3.2體驗

try:
    print(num)
except NameError:
    print("有錯誤")

注意:

1.如果嘗試執行的代碼的異常類型和要捕獲的異常類型不一致時,則無法捕獲異常

2.一般try下只放一行嘗試執行的代碼

3.4捕獲多個指定異常

當捕獲多個指定異常時,可以把要捕獲的異常類型的名字,放到except後,並使用元組的方式進行書寫

try:
    print(1/0)
except (NameError, ZeroDivisionError):
    print("有錯誤")

3.5捕獲指定異常描述信息

try:
    print(1/0)
except (NameError, ZeroDivisionError) as result:
    print(result)

3.6捕獲所有異常

Exception是所有程序異常類的父類

try:
    print(num)
except Exception as result:
    print(result)

3.7異常的else

else表示的是如果沒有異常要執行的代碼

try:
    print(1)
except Exception as result:
    print(result)
else:
    print("沒有異常時,執行的代碼")

3.8異常的finally

finally表示的是無論是否異常都要執行的代碼,例如關閉文件

try:
    f = open('test1.txt', 'r')
except:
    f = open('test1.txt', 'w')
else:
    print("沒有異常,真開心")
finally:
    f.close()

3.9異常的傳遞

體驗異常傳遞

需求:

  1. 嘗試只讀方式打開test.txt文件,如果文件存在則讀取文件內容,文件不存在則提示用戶即可

  2. 讀取內容要求:嘗試循環讀取內容,讀取過程中如果檢測到用戶意外終止程序,則except捕獲異常並提示用戶

import time
try:
    f = open('test.txt')
    try:
        while True:
            content = f.readline()
            if len(content) == 0:
                break
            time.sleep(2)
            print(content)
    except:
        # 如果在讀取文件的過程中,產生了異常,那麼就會捕獲到
        # 比如按下了ctrl+c
        print("意外終止讀取數據")
    finally:
        f.close()
        print("關閉文件")
except:
    print("文件不存在")

3.10自定義異常

在Python中,拋出自定義異常的語法爲raise 異常對象

需求:密碼長度不足,則報異常(用戶輸入密碼,如果輸入的長度不足3位,則報錯,即拋出自定義異常,並捕獲該異常)

# 自定義異常類,繼承Exception
class ShortInputError(Exception):
    def __init__(self, length, min_len):
        self.length = length
        self.min_len = min_len

    # 設置拋出異常的描述信息
    def __str__(self):
        return f'你輸入的長度是{self.length},不能少於{self.min_len}個字符'


def main():
    try:
        con = input("請輸入密碼:")
        if len(con) < 3:
            raise ShortInputError(len(con), 3)
    except Exception as result:
        print(result)
    else:
        print("密碼已經輸入完成")


main()

4.模塊和包

4.1模塊

Python模塊(Module),是一個Python文件,以.py結尾,包含了Python對象定義和Python語句

模塊能定義函數,類和變量,模塊裏也能包含可執行的代碼

4.1.1導入模塊的方式

  • import 模塊名

  • from 模塊名 import 功能名

  • from 模塊名 import *

  • import 模塊名 as 別名

  • from 模塊名 import 功能名 as 別名

4.1.1.1導入方式詳解

1.import

  • 語法

# 1.導入模塊
import 模塊名
import 模塊名1,模塊名2... #  不推薦

# 2.調用功能
模塊名.功能名()
  • 體驗

import math
print(math.sqrt(9))

2.from...import...

  • 語法

# 1.導入模塊
from 模塊名 import 功能1, 功能2, 功能3...
# 2.調用功能
功能名()
  • 體驗

from math import sqrt
print(sqrt(9))

3.from...import *

  • 語法

# 1.導入模塊
from 模塊名 import *
# 2.調用功能
功能名()
  • 體驗

from math import *
print(sqrt(9))

4.as定義別名

  • 語法

# 模塊定義別名
import 模塊名 as 別名

# 功能定義別名
from 模塊名 import 功能 as 別名
  • 體驗

# 模塊別名
import time as tt

tt.sleep(2)
print("hello")

# 功能別名
from time import sleep as sl
sl(2)
print('hello')

4.2製作模塊

在Python中,每個Python中都可以作爲一個模塊,模塊的名字就是文件的名字。也就是說自定義模塊名必須要符合標識符命名規則

4.2.1定義模塊

新建一個Python文件,命名爲my_module1.py,並定義testA函數

def testA(a, b):
    print(a + b)

4.2.2測試模塊

在實際開發中,當一個開發人員編寫完一個模塊後,爲了讓模塊能夠在項目中達到想要的效果,這個開發人員會自行在py文件中添加一些測試信息,例如,在my_module1.py文件中添加測試代碼

def testA(a, b):
    print(a + b)

# 測試信息
testA(1, 1)

此時,無論是當前文件,還是其他已經導入了該模塊的文件,在運行的時候都會自動執行testA函數的調用

解決辦法如下:

def testA(a, b):
    print(a + b)


# 只在當前文件調用該函數,其他導入的文件內不符合該條件,則不執行testA函數調用
# __name__是系統變量,是模塊的標識符,值是:如果是自身模塊,值是__main__,否則是當前模塊的名字
if __name__ == '__main__':
    testA(1, 1)

4.2.3調用模塊

import my_module1

my_module1.testA(2, 2)

4.3模塊定位順序

當導入一個模塊,Python解析器對模塊位置的搜索順序是:

  1. 當前目錄

  2. 如果不在當前目錄,Python則搜索在shell變量PYTHONPATH的每個目錄

  3. 如果都找不到,Python會查看默認目錄。UNIX下,默認路徑一般爲/usr/local/lib/python/

模塊搜素路徑存儲在system模塊的sys.path變量中。變量裏包含當前目錄,PYTHONPATH和由安裝過程決定的默認目錄

  • 注意

    • 自己的文件名不要和已有模塊名重複,否則導致模塊功能無法使用

    • 使用from 模塊名 import 功能的時候,如果功能名字重複,調用到的是最後定義或導入的功能

4.4__all__(all列表)

如果一個模塊文件中有__all__變量,當使用from xxx import *導入時,只能導入這個列表中的元素

  • my_module1模塊的代碼

__all__ = ['testA']


def testA():
    print('testA')


def testB():
    print('testB')
  • 導入模塊的文件代碼

from my_module1 import *
testA()
testB()
testA
Traceback (most recent call last):
  File "E:/PycharmProjects/Python_Base/Python_Test_1/1.py", line 3, in <module>
    testB()
NameError: name 'testB' is not defined

4.5包

包將有聯繫的模塊組織在一起,即放到同一個文件夾下,並且在這個文件夾創建一個名字爲__init__.py文件,那麼這個文件夾就稱之爲包

4.5.1製作包

[New]——[Python Package]——輸入包名——[OK]——新建功能模塊(有聯繫的模塊)

注意:新建包後,包內部會自動創建__init__.py文件,這個文件控制着包的導入行爲

4.5.1.1快速體驗

  1. 新建包mypackage

  2. 新建包內模塊:my_module1和my_module2

  3. 模塊代碼如下

# my_module1
print(1)


def info_print1():
    print('my_module1')
# my_module2
print(2)


def info_print1():
    print('my_module2')

4.5.2導入包

4.5.2.1方法一

import 包名.模塊名

包名.模塊名.功能

4.5.2.2體驗

import mypackage.my_module1

mypackage.my_module1.info_print1()

4.5.2.3方法二

注意:必須在__init__.py文件中添加__all__ = [],允許控制導入的模塊列表

from 包名 import *
模塊名.目標

4.5.2.4體驗

from mypackage import *

my_module1.info_print1()

__init__.py代碼

__all__ = ['my_module1']

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章