Python 資料模型 (Data Model)

Python 的資料模型 (Data Model) 定義了物件在語言中的行為方式。在 Python 中,萬物皆物件 (Everything is an object),這句話是理解 Python 的關鍵。

物件的三要素

每個 Python 物件都有三個核心特性:

  1. 識別碼 (Identity)
  2. 型別 (Type)
  3. 值 (Value)

1. 識別碼 (Identity)

識別碼可以想像成物件在記憶體中的地址。一旦物件被建立,其識別碼就不會改變。

使用 id() 函數可以查看物件的識別碼:

x = 100
print(id(x))  # 例如: 4309854320

y = x
print(id(y))  # 與 x 相同,因為指向同一個物件

使用 is 運算子就是在比較兩個物件的識別碼是否相同:

a = [1, 2, 3]
b = [1, 2, 3]
c = a

print(a == b)  # True (值相同)
print(a is b)  # False (是不同的物件)
print(a is c)  # True (指向同一個物件)

2. 型別 (Type)

型別決定了物件支援哪些操作(例如長度、加法等)以及它可以儲存什麼值。

使用 type() 函數可以查看物件的型別:

print(type(10))       # <class 'int'>
print(type("Hello"))  # <class 'str'>
print(type([1, 2]))   # <class 'list'>

3. 值 (Value)

值是物件儲存的數據。根據值是否可以改變,物件分為可變 (Mutable) 與不可變 (Immutable)。

  • 不可變物件:建立後值不能改變(如 int, str, tuple)。
  • 可變物件:建立後值可以改變(如 list, dict, set)。

特殊屬性 (Special Attributes)

Python 物件通常包含一些以雙底線開頭和結尾的特殊屬性(唯讀或可寫),這些屬性儲存了物件的元數據 (metadata)。

__name__

__name__ 屬性儲存模組、類別、函數、方法等物件的名稱。

def my_function():
    pass

class MyClass:
    pass

print(my_function.__name__)  # my_function
print(MyClass.__name__)      # MyClass
print(str.__name__)          # str

對於模組來說,__name__ 特別重要。當模組被直接執行時,__name__ 會是 "__main__";當被匯入時,則是模組名稱。

__doc__

__doc__ 屬性儲存物件的文件字串 (Docstring)。

def square(x):
    """計算並回傳 x 的平方"""
    return x * x

print(square.__doc__)
# 計算並回傳 x 的平方

__dict__

__dict__ 屬性是一個字典,儲存了物件的可寫入屬性。這也是 Python 實現動態屬性的核心機制。

class Person:
    def __init__(self, name):
        self.name = name

p = Person("Alice")
print(p.__dict__)  # {'name': 'Alice'}

# 動態新增屬性其實就是加入到 __dict__ 中
p.age = 25
print(p.__dict__)  # {'name': 'Alice', 'age': 25}

__module__

__module__ 屬性儲存定義該類別或函數的模組名稱。

from datetime import date
print(date.__module__)  # datetime

__class__

__class__ 屬性指向產生該實例的類別(即物件的型別)。

x = 10
print(x.__class__)  # <class 'int'>
# 等同於 type(x)

特殊方法 (Magic Methods)

Python 資料模型的一大特色是使用特殊方法(如 __init__, __str__, __len__ 等)來定義物件的行為。這些方法讓自訂物件可以像內建型別一樣運作(例如支援 + 運算子或 len() 函數)。

詳細內容請參考 特殊方法 (Magic Methods)

物件管理的最佳實踐

  1. 善用 is==:比較 None 時使用 is None,比較值相等時使用 ==
  2. 理解可變性:避免使用可變物件(如 list)作為函數的預設參數。
  3. 查閱文件:善用 __doc__help() 來了解物件的用途。