程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python系列(八):“一網打盡”類

編輯:Python

一.類概述

作為一門面向對象(Object)的編程語言,Python的核心當然包含類(class)的設計。本文詳細介紹了類的方法面面,具體介紹內容包括如下圖所示:

二.變量

2.1 類變量

類變量會在所有類實例間共享,類實例還未創建時,類變量就已經存在。類變量在所有方法之外定義,通常是在類頭的正下方以及構造函數和其它方法之前。

class People():
class_name = "demo" # 類變量
def __init__(self):
pass
if __name__ == "__main__":
print(People.class_name)
# demo
print(People().class_name)
# demo

類變量可以通過類名直接引用,也可以通過類實例來引用。

2.2 類實例變量

類實例變量由類實例所擁有,每個類實例都由自己一套獨立的類實例變量。

class People():
class_name = "demo" # 類變量
def __init__(self, name="", age=1, sex="M") -> None:
self.name = name # 類實例變量
self.age = age
self.sex = sex
if __name__ == "__main__":
p = People(name="Tom")
p1 = People(name="Tony")
print(p.name, p1.name)
# Tom Tony

三.類中的方法

3.1 實例方法

實例方法(instance methods)對由實例變量提供的數據/值執行一系列的操作。實例方法的第一個參數須為self,它指的是當前對象,用於訪問類中的變量和方法。實例方法不在類間共享。下面的示例代碼中,__init__print_info都是類的實例方法。

class People():
def __init__(self, name="", age=1, sex="M") -> None:
self.name = name
self.age = age
self.sex = sex
def print_info(self):
print(f"Name: {
self.name}, Age: {
self.age}, Sex: {
self.sex}")
if __name__ == "__main__":
p = People("Tom", 22, "M")
p.print_info()

3.1.1 類初始化方法

這裡著重介紹一下類的初始化方法__init__(),該方法在類實例創建的時候該方法會被自動調用

在類的構造方法中,若存在繼承關系,可以通過super()方法來調用父類的初始化方法完成父類屬性的初始化。

super()方法可以返回超類的臨時對象,然後可以通過它調用超類的方法。super()方法可以包含兩個參數:

  • 子類(subclass);
  • 子類的一個實例對象。
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * self.length + 2 * self.width
class Square(Rectangle):
def __init__(self, length):
super(Square, self).__init__(length, length)

Python3中super(Square, self)的調用等效於無參super()的調用。

3.1.2 __call__方法

Python允許class定義特殊的實例方法__call__,通過該方法可以讓像調用函數一樣調用對象

from collections import defaultdict
class CountMissing():
def __init__(self):
self.add = 0
def __call__(self):
self.add += 1
return 0
if __name__ == "__main__":
items = {
'apple': 3, 'banana': 2}
goods = [('orange', 6), ('watermelon', 1), ('strawberry', 9), ('apple', 8)]
# 統計goods在items不存在的水果類別
counter = CountMissing()
items = defaultdict(counter, items)
for fruit, num in goods:
items[fruit] += num
print(counter.add)
# 3

3.2 類方法

同類變量一樣,類方法(class methods)是所有類示例共享的方法。類方法只能訪問類變量,而不能訪問類實例變量(因為類實例還未創建)。類方法可以通過修改類變量來修改類的狀態

3.2.1 通過@classmethod裝飾器

在Python中,可以使用@classmethod裝飾器來將方法聲明為類方法。

class People():
class_name = "demo" # 類屬性
def __init__(self, name="", age=1, sex="M"):
self.name = name # 實例屬性
self.age = age
self.sex = sex
@classmethod
def print_info(cls):
print(f"class name: {
cls.class_name}")
if __name__ == "__main__":
People.print_info()
# class name: demo
People().print_info()
# class name: demo

類方法的注意事項包括:

  • 第一個參數必須為cls
  • 類方法僅能訪問類變量,例如class_name,但不能訪問實例屬性,例如self.name
  • 既可以通過類名.方法名來調用,也可以通過類實例對象.方法名來調用。

使用@classmethod的好處:在之後重構類時,不需要修改初始化函數,只需額外添加處理的函數,然後使用@classmethod即可。

3.2.2 通過classmethod()方法

Python中還可以通過內置的classmethod(function)方法來將正常的方法的方法轉換為類方法,其中function便是要轉換為類方法的函數名。

class People():
class_name = "demo" # 類屬性
def __init__(self, name="", age=1, sex="M"):
self.name = name # 實例屬性
self.age = age
self.sex = sex
def print_info(cls):
print(f"class name: {
cls.class_name}")
if __name__ == "__main__":
People.print_info = classmethod(People.print_info)
People().print_info()
# class name: demo

3.3 靜態方法

靜態方法(static methods)與類方法有些相似,它也是綁定在類上,而不是類實例對象上。但靜態方法沒有像selfcls這樣的隱式的第一個參數,這意味著它不能訪問類變量和類實例變量。靜態方法也能通過類名.靜態方法名的方式來調用。

與類方法類似,靜態方法通過可以通過@staticmethod裝飾器或內置的staticmethod(function)方法來定義。

class People():
class_name = "demo" # 類屬性
def __init__(self, name="", age=1, sex="M"):
self.name = name # 實例屬性
self.age = age
self.sex = sex
@staticmethod
def temp(x):
print(x)
def temp1(x, y):
print(x + y)
if __name__ == "__main__":
People.temp1 = staticmethod(People.temp1)
People.temp(10) # 10
People.temp1(10, 20) # 30

四.類裝飾器

4.1 @property裝飾器

Python提供了@property裝飾器,它使得在類中使用gettersetter變得容易。一般情況下,只要不將類屬性設置為私有屬性就可以在類外自由的使用類屬性。但是有時候,可能希望在設置屬性時進行一些特殊的行為,例如檢查設置的值是否大於0。這種情況下,@property裝飾器便能排上用場了,例如:

class Circle():
def __init__(self, radius):
self.radius = radius
@property
def radius(self):
return self.radius
@radius.setter
def radius(self, radius):
if radius <= 0:
raise ValueError(f"Circle's radius must be > 0, but get {
radius}")
self.radius = radius
c = Circle(-2)
# ValueError: Circle's radius must be > 0, but get -2

在該例子中,類初始化傳入參數radius=-2,在類初始化函數中當執行self.radius = radius時會自動調用@radius.setter方法,其檢查raduis的值小於等於0,引發異常。

五.訪問權限控制

Python的類同樣也有類似Java和C++的訪問權限控制,它同樣可以分為PublicProtectedPrivate

  • 公有:默認的方法和成員權限,通過對象的點運算符.訪問即可直接訪問;
  • 受保護:以單下劃線開頭_,只能通過類方法和子類本身進行訪問。注意,這並非是強制要求,只是希望用戶遵循這樣的要求。
  • 私有:以雙下劃線__開頭,只能通過類方法訪問。
class People():
def __init__(self, name, age, id):
self.name = name # public
self._age = age # protected
self.__id = id # private
def _protected_mthd(self):
print("Protected")
def __private_mthd(self):
print("Private")
if __name__ == "__main__":
p = People("Tom", 22, "1001")
print(p._age) # 雖然定義為包含類型,但還是可以直接訪問,只是Python不建議這樣做
# 22
p._protected_mthd()
# Protected
print(p.__id)
# AttributeError: 'People' object has no attribute '__id'
p.__private_mthd()
# AttributeError: 'People' object has no attribute '__private_mthd'

5.1 私有類型的名稱轉寫機制

實際上,Python中並沒有禁止訪問類中某一成員的保護機制。在外界看來無法訪問私有屬性的原因並不是因為保護機制,而是類方法使用了名稱轉寫機制,即對於私有屬性__X,其會被轉寫為_classname__X,其中classname為類名(私有方法也類似)。

print(p._People__id)
# 1001
p._People__private_mthd()
# Private

通過上述的名稱轉寫機制,可以避免類繼承過程中的命名沖突(子類定義與父類相同名稱的屬性)。


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved