首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Python 函數與類核心筆記:參數機制、作用域、裝飾器、繼承與多態

     編輯:Java 程式設計入門

前言

本文整理 Python 函數與類的核心知識點,針對**參數傳遞機制、作用域規則、裝飾器本質、類方法靜態方法、繼承 MRO、數據模型協議**進行系統筆記,適合 Java/Go 開發者快速遷移、面試複習或項目查漏補缺。

一、函數參數機制:位置、關鍵字、收集、解包

1. 參數定義順序 (強制)


def func(pos_only, /, pos_or_kw, *, kw_only, **kwargs):
    pass
# 1. 位置-only (Python 3.8+ / 分隔符)
# 2. 位置或關鍵字 (預設)
# 3. *args 收集剩餘位置參數 → tuple
# 4. 關鍵字-only (* 後或 *args 後)
# 5. **kwargs 收集剩餘關鍵字參數 → dict

2. 傳遞語義:Call by Object Reference (對象引用傳遞)

  • **不可變對象** (int, str, tuple):**值傳遞效果**,函數內重新賦值不影響外部。
  • **可變對象** (list, dict, set, 自定義類):**引用傳遞效果**,函數內修改內容 (如 append) 影響外部;**重新賦值參數變量**不影響外部。

def modify(lst, num):
    lst.append(99)      # 影響外部
    num = 100           # 不影響外部
    lst = [1,2,3]       # 不影響外部 (重新綁定局部變量)

a = [1,2]; b = 10
modify(a, b)
print(a, b)  # [1, 2, 99] 10

3. 默認參數陷阱:可變對象只在定義時計算一次


def bad_append(val, lst=[]):  # 危險!
    lst.append(val)
    return lst

print(bad_append(1)) # [1]
print(bad_append(2)) # [1, 2] ← 共享同一列表!

def good_append(val, lst=None):
    if lst is None: lst = []
    lst.append(val)
    return lst

4. *args / **kwargs 收集與解包


def demo(a, b, *args, kw1, kw2, **kwargs):
    print(a, b, args, kw1, kw2, kwargs)

demo(1, 2, 3, 4, kw1=5, kw2=6, kw3=7, kw4=8)
# 1 2 (3, 4) 5 6 {'kw3': 7, 'kw4': 8}

# 解包調用
tup = (10, 20)
dct = {'kw1': 30, 'kw2': 40, 'kw3': 50}
demo(*tup, **dct)  # 10 20 () 30 40 {'kw3': 50}

二、作用域規則:LEGB 法則與 nonlocal/global


x = 100  # Global (模塊級)

def outer():
    x = 200  # Enclosing
    def inner():
        nonlocal x  # 修改 Enclosing 層 x
        x = 300
        print("inner:", x)  # 300
    inner()
    print("outer:", x)  # 300 (被修改)

outer()
print("global:", x)  # 100 (未被修改)
| 作用域 | 關鍵字 | 可讀 | 可寫 (需聲明) | |--------|--------|------|---------------| | Local (函數內) | - | ✅ | ✅ | | Enclosing (外層函數) | `nonlocal` | ✅ | ✅ | | Global (模塊級) | `global` | ✅ | ✅ | | Builtins (內建) | - | ✅ | ❌ |

三、裝飾器本質:高階函數 + 語法糖

1. 基礎模板


import functools

def timer(func):
    @functools.wraps(func)  # 保留 __name__, __doc__, __annotations__
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        print(f"{func.__name__} took {time.perf_counter()-start:.4f}s")
        return result
    return wrapper

@timer
def slow_add(a, b):
    time.sleep(0.1)
    return a + b

2. 帶參數裝飾器 (三層嵌套)


def repeat(times):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello {name}")

3. 類裝飾器 (可保持狀態)


class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"Call {self.count} to {self.func.__name__}")
        return self.func(*args, **kwargs)

@CountCalls
def add(a, b): return a + b

四、類機制:方法類型、屬性、繼承、MRO、數據模型

1. 三種方法類型


class Demo:
    def instance_method(self):        # 實例方法:隱式傳 self
        return self

    @classmethod
    def class_method(cls):            # 類方法:隱式傳 cls,可被繼承覆寫
        return cls

    @staticmethod
    def static_method():              # 靜態方法:無隱式傳遞,工具函數歸屬類命名空間
        return "static"

# 調用
Demo.instance_method(Demo())  # 手動傳 self
Demo.class_method()           # 自動傳 Demo
Demo.static_method()          # 直接調用

2. 屬性協議


class Celsius:
    def __init__(self, temp=0):
        self._temp = temp

    @property
    def temperature(self):
        return self._temp

    @temperature.setter
    def temperature(self, value):
        if value < -273.15: raise ValueError("Below absolute zero")
        self._temp = value

    @temperature.deleter
    def temperature(self):
        del self._temp

3. 私有化慣例:名稱修飾


class A:
    def __init__(self):
        self.public = 1
        self._protected = 2   # 約定俗成:內部使用
        self.__private = 3    # 名稱修飾 → _A__private

a = A()
print(a._A__private)  # 3 (可訪問,但不建議)

4. 繼承與 MRO (Method Resolution Order)


class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

print(D.__mro__)
# (D, B, C, A, object) ← C3 線性化算法:深度優先、左優先、單調性

5. 核心數據模型協議 (雙下劃線方法)

協議方法用途
構造/初始化`__new__`, `__init__`實例創建、初始化
字串表示`__str__`, `__repr__``print()` vs 除錯
比較`__eq__`, `__lt__`...`==`, `<`, `sorted()`
容器`__len__`, `__getitem__`, `__setitem__`, `__iter__``len()`, `[]`, `in`, `for`
可呼叫`__call__``obj()`
上下文管理`__enter__`, `__exit__``with obj:`
屬性訪問`__getattr__`, `__setattr__`, `__getattribute__`動態屬性、代理
序列化`__reduce__`, `__getstate__`, `__setstate__``pickle`

6. 多重繼承鑽石問題解決


class Base: pass
class Left(Base): pass
class Right(Base): pass
class Diamond(Left, Right): pass

# MRO: Diamond → Left → Right → Base → object
# super() 按 MRO 鏈調用,保證每個類只初始化一次

五、常見面試題速答

  1. is vs ==:is 比較身份 (id/記憶體地址);== 比較值 (調用 __eq__)。[] is [] → False, [] == [] → True。
  2. lambda 限制:只能包含**單一表達式**,無法包含語句 (賦值、循環、try)。
  3. 尾遞歸優化:**CPython 不支援**;需手動改迴圈或用 `functools.lru_cache` 遞歸備忘錄。
  4. __slots__:限制實例屬性、節省記憶體 (無 `__dict__`)、禁止動態添加屬性。
  5. 元類:`type` 是預設元類;自定義元類控制類創建過程 (如單例、ORM 欄位註冊)。

💡 Pythonic 原則:顯式優於隱式、簡單優於複雜、可讀性至上。善用 `with`、列表推導式、生成器、上下文管理器、類型提示 (PEP 484) 寫出健壯、可維護的代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved