Python 物件導向的核心在於**屬性**(資料)與**方法**(行為)的封裝。本文系統整理:公有/私有屬性、名稱修飾機制、四種方法型別(實例、類別、靜態、私有)、裝飾器語法、存取控制最佳實務與繼承場景應用。
class People:
def __init__(self):
self.name = '張珊' # 公有屬性
self.__age = 23 # 私有屬性(雙下劃線開頭)
p = People()
print(p.name) # 張珊
# print(p.__age) # AttributeError: 'People' object has no attribute '__age'
# 實際儲存名稱(名稱修飾 Name Mangling)
print(p._People__age) # 23(_ClassName__attr)
print(p.__dict__) # {'name': '張珊', '_People__age': 23}
__attr → _ClassName__attr_attr:慣例內部使用,不修飾__attr__:特殊方法,不修飾
class People:
def __init__(self, name, age):
self.name = name
self.__age = age
# 公有方法存取私有屬性
def get_age(self):
return self.__age
def set_age(self, age):
if 0 < age < 150:
self.__age = age
else:
raise ValueError("Invalid age")
# 唯讀屬性(Pythonic 方式)
@property
def age(self):
return self.__age
p = People("Alice", 25)
print(p.get_age()) # 25
print(p.age) # 25(屬性存取,無括號)
# p.age = 30 # AttributeError: can't set attribute(無 setter)
class People:
def __init__(self, name):
self.name = name
self.__secret = "hidden"
# 1. 實例方法:存取 self(實例屬性)
def instance_method(self):
print(f"Instance: {self.name}, secret: {self.__secret}")
# 2. 私有方法:內部使用,名稱修飾
def __private_method(self):
print("Private method called")
def public_caller(self):
self.__private_method() # 內部可呼叫
# 3. 類別方法:存取 cls(類別屬性)、可被繼承覆寫
@classmethod
def class_method(cls):
print(f"Class method of {cls.__name__}")
# 4. 靜態方法:無 self/cls,邏輯歸屬類別
@staticmethod
def static_method():
print("Static method: utility function")
# 使用
p = People("Bob")
p.instance_method() # Instance: Bob, secret: hidden
p.public_caller() # Private method called
People.class_method() # Class method of People
People.static_method() # Static method: utility function
# 實例也可呼叫類別/靜態方法
p.class_method()
p.static_method()
| 型別 | 裝飾器 | 第一參數 | 存取 | 呼叫方式 | 典型用途 |
|---|---|---|---|---|---|
| 實例方法 | 無 | self | 實例/類別屬性 | obj.method() | 操作實例狀態 |
| 私有方法 | 無(命名__) | self | 實例/類別屬性 | self.__method() | 內部實現細節 |
| 類別方法 | @classmethod | cls | 類別屬性 | Class.method() / obj.method() | 替代建構子、類別狀態 |
| 靜態方法 | @staticmethod | 無 | 無(傳入參數) | Class.method() / obj.method() | 工具函式、邏輯分組 |
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def from_string(cls, date_str):
"""從 'YYYY-MM-DD' 建立實例"""
year, month, day = map(int, date_str.split('-'))
return cls(year, month, day)
@classmethod
def today(cls):
"""建立今天日期實例"""
import datetime
today = datetime.date.today()
return cls(today.year, today.month, today.day)
def __str__(self):
return f"{self.year}-{self.month:02d}-{self.day:02d}"
d1 = Date(2024, 1, 15)
d2 = Date.from_string("2024-12-25")
d3 = Date.today()
print(d1, d2, d3)
class MathUtils:
@staticmethod
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5)+1):
if n % i == 0:
return False
return True
@staticmethod
def gcd(a, b):
while b:
a, b = b, a % b
return a
print(MathUtils.is_prime(17)) # True
print(MathUtils.gcd(48, 18)) # 6
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name} makes a sound")
@classmethod
def species(cls):
return cls.__name__
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # 呼叫父類別 __init__
self.breed = breed
def speak(self): # 覆寫
print(f"{self.name} barks!")
class Cat(Animal):
def speak(self):
print(f"{self.name} meows~")
animals = [Dog("Buddy", "Golden"), Cat("Whiskers")]
for a in animals:
a.speak() # 多態:Buddy barks! / Whiskers meows~
print(f"Species: {a.species()}") # 類別方法繼承
class Base:
def __init__(self, x):
self.x = x
print(f"Base init: {x}")
class Derived(Base):
def __init__(self, x, y):
super().__init__(x) # Python 3 簡潔語法
self.y = y
print(f"Derived init: {y}")
# 多重繼承 MRO
class A:
def method(self):
print("A")
class B(A):
def method(self):
super().method()
print("B")
class C(A):
def method(self):
super().method()
print("C")
class D(B, C):
def method(self):
super().method()
print("D")
D().method()
# A -> C -> B -> D (MRO 順序)
print(D.__mro__)
_attr 表內部使用。from_string、today 等。super().__init__()**:確保父類別正確初始化。Python 屬性與方法機制靈活強大:**公有預設、私有慣例/名稱修飾、四種方法型別分工明確**。掌握 @property 封裝存取、@classmethod 替代建構子、@staticmethod 工具分組、super() 協同初始化,能寫出清晰、可擴充、符合 Python 慣用語的物件導向代碼。記住:**Python 信任開發者,封裝靠慣例與文件,而非語法強制**。