今日任務:

  1. 類的定義
  2. pass佔位語句
  3. 類的初始化方法
  4. 類的普通方法
  5. 類的繼承:屬性的繼承、方法的繼承

類的定義

對類進行定義時,使用class關鍵字,注意與函數不同,在類名的後面不需要加括號,示例如下:

class ClassName: #類名通常遵循大駝峯命名法 (UpperCamelCase),即每個單詞的首字母都大寫
    """類的文檔字符串"""
    # 類的內容
    pass #pass 為佔位符,避免運行錯誤

關於pass與縮進:

  • Python通過縮進定義代碼塊的結構,對於def,class,if等,如果後續代碼塊為空,那麼就會因為無法確定結構的範圍而拋出IndentationError。
  • pass本身不執行任何操作,但它可以起到一個佔位置的作用。因此,當需要一個語法上存在的代碼塊,但又暫時不想在其中放入任何實際的邏輯時,就可以使用pass佔位。

在定義一個類時,它可以具有屬性和方法兩個部分。

  • 屬性(是什麼):用於存儲數據,初始化方法構造類內部直接定義、類外部添加
  • 方法(做什麼):定義行為,初始化方法(__init__)、類方法、靜態方法、魔術方法等等

類的方法

上面提到了類的方法和屬性,在調用時,對方法和屬性分別使用example.method()、example.name。

下面主要説明初始化方法和自定義的普通方法。

初始化方法

__init__(注意前後均各有兩條下劃線)屬於類的構造方法,當創建對象時,會被自動調用

關於參數,可以自己使用self.屬性名給出默認值或者賦值給外部傳入的參數值。

class Teacher:
    def __init__(self, name, age):# 初始化方法,傳入了參數
        print(f"self的內存地址: {id(self)}") #打印內存地址
        self.name = name # 外界的參數,需要通過self.xxx來複制給類自己的屬性
        self.age = age
        self.subject = "English"  # 這個屬性仍然是在創建時就設定好的
# 創建一個Teacher對象的例子,構造方法的參數必須
teacher_1 = Teacher("Susan", 33) # 如果在初始化方法中設置了非默認的參數,那麼外界就必須要傳入才行
print(f"teacher_1的內存地址: {id(teacher_1)}")
print(teacher.name)  # 輸出: Susan
print(teacher.age)   # 輸出: 33
print(teacher.subject)  # 輸出: English
teacher_1.subject = 'Math' #修改屬性
print(teacher.subject)  # 輸出: Math

2.7 面向對象介紹 2.8 類的屬性 2.9 類的方法 - JasonYan86的個人空間 -_初始化方法

在使用__init__初始化時,必須先填入'self',因為self代表的是實例本身(打印內存地址查看):

  • 對同一個類,可以創建不同的實例,每次調用,可以將不同實例作為self參數傳入
  • 通過self.屬性名self.方法名()獲取實例的屬性和方法
  • 數據隔離:確保每個實例有獨立的數據空間

注意在對類實例化時,傳入的參數是初始化方法中的(一些屬性)。後續在普通方法中的參數,是在調用函數的時候傳入(與之前的普通函數調用相同)。當然,這些參數肯定是除‘self’之外的。

普通方法(自定義)

與Init方法不同,自定義的方法只有手動調用時才會被執行。但相同的時,第一個參數也是'self',原因同上。其他的寫法與之前單獨的函數寫法基本相同,但區別如下:

  • 第一個參數是“self”,後面是正常的參數
  • 需要在函數內部使用類的屬性和方法時,必須使用self,比如self.name而不是name
class Teacher:
    # 初始化方法接受參數以動態設置教師的屬性
    def __init__(self, name, subject, age):
        self.name = name
        self.subject = subject
        self.age = age
    # 不是init的都叫做普通方法
    # 普通方法,模擬教師上課的行為
    def teach_lesson(self):
        print(f"{self.name}正在教{self.subject}。")
    # 另一個普通方法,模擬教師批評學生的行為
    def criticize(self, student_name):
        print(f"{self.name}正在批評{student_name}。")
# 創建Teacher類的實例
teacher = Teacher("Susan", "English", 33)
# 調用教師的方法
teacher.teach_lesson()
teacher.criticize("John")#普通方法的參可以等到調用該方法的時候再傳

關於構造方法與普通方法的對比:

2.7 面向對象介紹 2.8 類的屬性 2.9 類的方法 - JasonYan86的個人空間 -_初始化方法_02

類的繼承

類的繼承是面向對象編程的重要特性,允許基於已有的類創建新類,而新類會自動獲得父類的屬性和方法,並可以添加新的功能或修改現有功能。

使用類的繼承,實際上很大程度上與之前的函數封裝、裝飾器類似,就是減少代碼重複。比如定義了一個貓類別和狗類別,然後發現它們中存在相同的地方(吃東西、睡覺),完全可以將這些提取出來,使用一個父類(動物)來包含。貓類和狗類只要繼承就可以,而對應於別的動物(魚類、鳥類)也可以適用。

此外,適用類的繼承有如下用途:

  • 建立層次關係,更精確地建模現實世界,比如上面的動物——貓/狗/魚/鳥
  • 擴展和定製功能,在每一個子類中可以重寫新增屬性或方法作為自身的特色
  • 多態性、便於維護和更新(修改父類可影響所有子類)

在用代碼實現時需要注意:

  • 類名後的括號中填入父類名稱(可以不只一個)
  • 使用super()調用父類方法:子類初始化或者需要擴展父類方法時使用;完全重寫或新增方法時不需要

下面是代碼示例:

# 定義一個父類
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def sleep(self):
        print(f'{self.name}在睡覺')
    def speak(self):
        print(f"{self.name} 發出聲音")
class Dog(Animal): #繼承需要在括號中指定父類
    def __init__(self,name,age,color): #傳入父類的參數,同時也可以傳入自己的參數
        # super()函數 除了在構造方法中使用,還可以在其他方法中使用
        super().__init__(name,age) #調用父類的構造方法,super()是一個內置函數,返回父類的實例
        self.color = color #新增子類特有的屬性
    #重寫方法,如果子類定義了與父類同名的方法,子類實例會優先調用子類的方法。
    def sleep(self):
        print(f'{self.color}的{self.name}在睡覺')
    #重寫——擴展父類功能
    def speak(self):
        super().speak()  # 先調用父類的方法
        print("汪汪叫")    # 再添加子類的行為
    #新增功能
    def run(self):
        pass
dog = Dog("旺財", 3,'紅色')
dog.sleep()

作業

題目1:定義圓(Circle)類

要求:

  1. 包含屬性:半徑 radius。
  2. 包含方法:calculate_area():計算圓的面積(公式:πr²)。calculate_circumference():計算圓的周長(公式:2πr)。
  3. 初始化時需傳入半徑,默認值為 1。
import math
class Circle:
    def __init__(self,radius):
        self.radius = radius
    def calculate_area(self): #計算面積
        area = round(math.pi*pow(self.radius,2),2)
        return area
    def calculate_circumference(self): #計算周長
        circumference = round(2*math.pi*self.radius,2)
        return circumference
#調用
circle = Circle(5)
print(f"半徑:{circle.radius}")       # 輸出:半徑:5
print(f"面積:{circle.calculate_area()}")   # 輸出:面積:78.54
print(f"周長:{circle.calculate_circumference()}") # 輸出:周長:31.42

題目2:定義長方形(Rectangle)類

  1. 包含屬性:長 length、寬 width。
  2. 包含方法:calculate_area():計算面積(公式:長×寬)。calculate_perimeter():計算周長(公式:2×(長+寬))。 is_square() 方法,判斷是否為正方形(長 == 寬)。
  3. 初始化時需傳入長和寬,默認值均為 1。
class Rectangle:
    def __init__(self,length=1,width=1): #長和寬默認為1
        self.length = length
        self.width = width
    def calculate_area(self): #計算面積
        area = self.length * self.width
        return area
    def calculate_perimeter(self): #計算周長
        perimeter = 2*(self.length + self.width)
        return perimeter
    def is_square(self): #判斷是否為正方形
        return self.length == self.width
rect = Rectangle(4, 6)
print(f"長:{rect.length}, 寬:{rect.width}")  # 輸出:長:4, 寬:6
print(f"面積:{rect.calculate_area()}")      # 輸出:面積:24
print(f"周長:{rect.calculate_perimeter()}")  # 輸出:周長:20
print(f"是否為正方形:{rect.is_square()}")    # 輸出:是否為正方形:False
square = Rectangle(5, 5)
print(f"是否為正方形:{square.is_square()}")  # 輸出:是否為正方形:True

題目3:圖形工廠

創建一個工廠函數 create_shape(shape_type, *args),根據類型創建不同圖形對象:圖形工廠(函數或類)。

示例:shape_type='circle':創建圓(參數:半徑);shape_type='rectangle':創建長方形(參數:長、寬)

import math
# 定義圓類
class Circle:
    def __init__(self,radius):
        self.radius = radius
    def calculate_area(self): #計算面積
        area = round(math.pi*pow(self.radius,2),2)
        return area
    def calculate_circumference(self): #計算周長
        circumference = round(2*math.pi*self.radius,2)
        return circumference
# 定義長方形類
class Rectangle:
    def __init__(self,length=1,width=1): #長和寬默認為1
        self.length = length
        self.width = width
    def calculate_area(self): #計算面積
        area = self.length * self.width
        return area
    def calculate_perimeter(self): #計算周長
        perimeter = 2*(self.length + self.width)
        return perimeter
    def is_square(self): #判斷是否為正方形
        return self.length == self.width
# 圖形工廠
def create_shape(shape_type,*args):
    if shape_type.lower() == 'circle':
        return Circle(args[0])
    elif shape_type.lower() == 'rectangle':
        return Rectangle(args[0],args[1])
    else:
        return '抱歉,目前支持創建圓或長方形!'
# 測試
shape1 = create_shape("Circle", 5)
print(shape1.calculate_circumference())  # 輸出:31.42
shape2 = create_shape("RecTangle", 3, 4)
print(shape2.is_square())                # 輸出:False
shape3 = create_shape('triangle',3,4,5)
print(shape3)                            # 抱歉,目前支持創建圓或長方形!