Skip to content

Instantly share code, notes, and snippets.

@KuRRe8
Last active June 6, 2025 17:35
Show Gist options
  • Save KuRRe8/36f63d23ef205a8e02b7b7ec009cc4e8 to your computer and use it in GitHub Desktop.
Save KuRRe8/36f63d23ef205a8e02b7b7ec009cc4e8 to your computer and use it in GitHub Desktop.
和Python使用有关的一些教程,按类别分为不同文件

Python教程

Python是一个新手友好的语言,并且现在机器学习社区深度依赖于Python,C++, Cuda C, R等语言,使得Python的热度稳居第一。本Gist提供Python相关的一些教程,可以直接在Jupyter Notebook中运行。

  1. 语言级教程,一般不涉及初级主题;
  2. 标准库教程,最常见的标准库基本用法;
  3. 第三方库教程,主要是常见的库如numpy,pytorch诸如此类,只涉及基本用法,不考虑新特性

其他内容就不往这个Gist里放了,注意Gist依旧由git进行版本控制,所以可以git clone 到本地,或者直接Google Colab\ Kaggle打开相应的ipynb文件

直接在网页浏览时,由于没有文件列表,可以按Ctrl + F来检索相应的目录,或者点击下面的超链接。

想要参与贡献的直接在评论区留言,有什么问题的也在评论区说 ^.^

目录-语言部分

目录-库部分

目录-具体业务库部分-本教程更多关注机器学习深度学习内容

目录-附录

  • sigh.md个人对于Python动态语言的看法
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Python 设计模式教程\n",
"\n",
"欢迎来到 Python 设计模式教程!设计模式是软件开发中针对常见问题的经过验证的、可重用的解决方案。它们不是具体的代码或库,而是一种描述问题和解决方案之间关系的方式,可以帮助你编写更灵活、可维护和可扩展的代码。\n",
"\n",
"Python 是一种动态且富有表现力的语言,其许多特性(如函数是一等公民、动态类型、鸭子类型)使得某些设计模式的实现比在静态类型语言中更简洁或有所不同。\n",
"\n",
"**为什么学习设计模式?**\n",
"\n",
"1. **提供通用词汇**:开发者之间可以更有效地沟通设计思想。\n",
"2. **重用经验证的解决方案**:避免重复造轮子,解决常见设计问题。\n",
"3. **提高代码质量**:使代码更易于理解、修改和维护。\n",
"4. **促进代码复用**:模式本身就是可复用的思想。\n",
"\n",
"**设计模式分类 (GoF - Gang of Four 经典分类):**\n",
"\n",
"* **创建型模式 (Creational Patterns)**:关注对象的创建机制,旨在以适合特定情况的方式创建对象。\n",
"* **结构型模式 (Structural Patterns)**:关注类和对象的组合,形成更大的结构。\n",
"* **行为型模式 (Behavioral Patterns)**:关注对象之间的职责分配和算法的抽象。\n",
"\n",
"本教程将介绍一些常见的设计模式及其在 Python 中的 Pythonic 实现。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. 创建型模式 (Creational Patterns)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 1.1 工厂方法 (Factory Method)\n",
"\n",
"**意图**:定义一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。\n",
"\n",
"**Pythonic 实现**:在 Python 中,由于函数是一等公民,工厂方法通常可以直接用一个返回不同类型实例的函数或静态方法来实现,不一定需要严格的类继承结构。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from abc import ABC, abstractmethod\n",
"\n",
"# 产品接口\n",
"class Document(ABC):\n",
" @abstractmethod\n",
" def open(self):\n",
" pass\n",
"\n",
"# 具体产品\n",
"class TextDocument(Document):\n",
" def open(self):\n",
" print(\"Opening text document...\")\n",
" return \"Text Content\"\n",
"\n",
"class PdfDocument(Document):\n",
" def open(self):\n",
" print(\"Opening PDF document...\")\n",
" return \"PDF Content\"\n",
"\n",
"# 创建者 (工厂) - 经典方式\n",
"class DocumentFactory(ABC):\n",
" @abstractmethod\n",
" def create_document(self) -> Document:\n",
" pass\n",
"\n",
" def process_document(self):\n",
" doc = self.create_document()\n",
" content = doc.open()\n",
" print(f\"Processing content: {content}\")\n",
"\n",
"# 具体创建者\n",
"class TextDocumentFactory(DocumentFactory):\n",
" def create_document(self) -> Document:\n",
" return TextDocument()\n",
"\n",
"class PdfDocumentFactory(DocumentFactory):\n",
" def create_document(self) -> Document:\n",
" return PdfDocument()\n",
"\n",
"print(\"--- Classic Factory Method ---\")\n",
"text_factory = TextDocumentFactory()\n",
"text_factory.process_document()\n",
"\n",
"pdf_factory = PdfDocumentFactory()\n",
"pdf_factory.process_document()\n",
"\n",
"# Pythonic 工厂函数\n",
"def create_document_pythonic(doc_type: str) -> Document:\n",
" if doc_type == 'text':\n",
" return TextDocument()\n",
" elif doc_type == 'pdf':\n",
" return PdfDocument()\n",
" else:\n",
" raise ValueError(f\"Unknown document type: {doc_type}\")\n",
"\n",
"print(\"\\n--- Pythonic Factory Function ---\")\n",
"doc1 = create_document_pythonic('text')\n",
"print(doc1.open())\n",
"doc2 = create_document_pythonic('pdf')\n",
"print(doc2.open())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 1.2 抽象工厂 (Abstract Factory)\n",
"\n",
"**意图**:提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。\n",
"\n",
"**场景**:当你的系统需要独立于其产品的创建、组合和表示时,或者当你有多个产品系列,并且希望在任何给定时间只使用一个系列时。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 抽象产品 A\n",
"class Button(ABC):\n",
" @abstractmethod\n",
" def paint(self):\n",
" pass\n",
"\n",
"# 抽象产品 B\n",
"class Checkbox(ABC):\n",
" @abstractmethod\n",
" def paint(self):\n",
" pass\n",
"\n",
"# 具体产品 (Windows 主题)\n",
"class WinButton(Button):\n",
" def paint(self):\n",
" print(\"Painting Windows button\")\n",
"\n",
"class WinCheckbox(Checkbox):\n",
" def paint(self):\n",
" print(\"Painting Windows checkbox\")\n",
"\n",
"# 具体产品 (Mac 主题)\n",
"class MacButton(Button):\n",
" def paint(self):\n",
" print(\"Painting Mac button\")\n",
"\n",
"class MacCheckbox(Checkbox):\n",
" def paint(self):\n",
" print(\"Painting Mac checkbox\")\n",
"\n",
"# 抽象工厂\n",
"class GUIFactory(ABC):\n",
" @abstractmethod\n",
" def create_button(self) -> Button:\n",
" pass\n",
"\n",
" @abstractmethod\n",
" def create_checkbox(self) -> Checkbox:\n",
" pass\n",
"\n",
"# 具体工厂 (Windows)\n",
"class WinFactory(GUIFactory):\n",
" def create_button(self) -> Button:\n",
" return WinButton()\n",
"\n",
" def create_checkbox(self) -> Checkbox:\n",
" return WinCheckbox()\n",
"\n",
"# 具体工厂 (Mac)\n",
"class MacFactory(GUIFactory):\n",
" def create_button(self) -> Button:\n",
" return MacButton()\n",
"\n",
" def create_checkbox(self) -> Checkbox:\n",
" return MacCheckbox()\n",
"\n",
"# 客户端代码\n",
"def create_ui(factory: GUIFactory):\n",
" button = factory.create_button()\n",
" checkbox = factory.create_checkbox()\n",
" button.paint()\n",
" checkbox.paint()\n",
"\n",
"print(\"--- Abstract Factory ---\")\n",
"print(\"Client: Creating UI with Windows theme\")\n",
"create_ui(WinFactory())\n",
"\n",
"print(\"\\nClient: Creating UI with Mac theme\")\n",
"create_ui(MacFactory())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 1.3 单例模式 (Singleton)\n",
"\n",
"**意图**:确保一个类只有一个实例,并提供一个全局访问点来访问该实例。\n",
"\n",
"**Pythonic 实现**:在 Python 中,由于模块本身在导入时就是单例的,所以一种常见的做法是使用模块级变量。如果确实需要类实现单例,可以使用元类、装饰器或覆盖 `__new__` 方法。\n",
"\n",
"**争议**:单例模式有时被认为是反模式,因为它引入了全局状态,可能使测试和代码理解变得困难。应谨慎使用。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 方法1: 使用元类\n",
"class SingletonMeta(type):\n",
" _instances = {}\n",
" def __call__(cls, *args, **kwargs):\n",
" if cls not in cls._instances:\n",
" instance = super().__call__(*args, **kwargs)\n",
" cls._instances[cls] = instance\n",
" return cls._instances[cls]\n",
"\n",
"class Logger(metaclass=SingletonMeta):\n",
" def __init__(self, filename):\n",
" # 注意:__init__ 仍然会在每次尝试创建时被调用,即使返回的是现有实例\n",
" # 因此,初始化逻辑可能需要特殊处理,确保只执行一次\n",
" if not hasattr(self, 'filename'): # 简单检查避免重复初始化\n",
" print(f\"Logger (metaclass) initialized with {filename}\")\n",
" self.filename = filename\n",
" \n",
" def log(self, message):\n",
" print(f\"LOG [{self.filename}]: {message}\")\n",
"\n",
"print(\"--- Singleton with Metaclass ---\")\n",
"logger1 = Logger(\"app.log\")\n",
"logger2 = Logger(\"another.log\") # __init__ 会被调用,但返回的是 logger1\n",
"logger1.log(\"Event 1\")\n",
"logger2.log(\"Event 2\") # 使用的还是 app.log\n",
"print(f\"logger1 is logger2: {logger1 is logger2}\")\n",
"print(f\"logger1.filename: {logger1.filename}\") # 仍是 app.log\n",
"\n",
"# 方法2: 使用装饰器 (更简洁,但 __init__ 行为类似)\n",
"def singleton_decorator(cls):\n",
" instances = {}\n",
" def get_instance(*args, **kwargs):\n",
" if cls not in instances:\n",
" instances[cls] = cls(*args, **kwargs)\n",
" return instances[cls]\n",
" return get_instance\n",
"\n",
"@singleton_decorator\n",
"class DatabaseConnection:\n",
" def __init__(self, dsn):\n",
" if not hasattr(self, 'dsn'): # 简单检查避免重复初始化\n",
" print(f\"DatabaseConnection (decorator) initialized with {dsn}\")\n",
" self.dsn = dsn\n",
" self.connection_id = id(self) # 只是为了演示\n",
" \n",
" def query(self, sql):\n",
" print(f\"Querying on {self.dsn} (ID: {self.connection_id}): {sql}\")\n",
"\n",
"print(\"\\n--- Singleton with Decorator ---\")\n",
"db1 = DatabaseConnection(\"user:pass@host1/db\")\n",
"db2 = DatabaseConnection(\"user:pass@host2/db\")\n",
"db1.query(\"SELECT * FROM users\")\n",
"db2.query(\"SELECT * FROM products\") # 使用的还是 host1\n",
"print(f\"db1 is db2: {db1 is db2}\")\n",
"\n",
"# 方法3: 模块级单例 (最 Pythonic 的方式之一)\n",
"# my_config.py\n",
"class AppConfig:\n",
" def __init__(self):\n",
" self.settings = {}\n",
" print(\"AppConfig (module level) initialized\")\n",
" def set(self, key, value):\n",
" self.settings[key] = value\n",
" def get(self, key):\n",
" return self.settings.get(key)\n",
"\n",
"# config_instance = AppConfig() # 在模块中创建实例\n",
"# # 在其他地方: from my_config import config_instance\n",
"print(\"\\n--- Singleton with Module ---\")\n",
"class ModuleSingletonSimulation: # 模拟模块导入行为\n",
" _instance = None\n",
" @classmethod\n",
" def get_instance(cls):\n",
" if cls._instance is None:\n",
" cls._instance = AppConfig()\n",
" return cls._instance\n",
"\n",
"config1 = ModuleSingletonSimulation.get_instance()\n",
"config2 = ModuleSingletonSimulation.get_instance()\n",
"config1.set(\"theme\", \"dark\")\n",
"print(f\"config2 theme: {config2.get('theme')}\")\n",
"print(f\"config1 is config2: {config1 is config2}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. 结构型模式 (Structural Patterns)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.1 适配器模式 (Adapter)\n",
"\n",
"**意图**:将一个类的接口转换成客户希望的另一个接口。适配器使原本由于接口不兼容而不能一起工作的那些类可以一起工作。\n",
"\n",
"**场景**:当你希望使用某个类,但是其接口与其他代码不兼容时。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 目标接口 (Target)\n",
"class ModernLogger:\n",
" def log_message(self, level: str, message: str):\n",
" print(f\"MODERN LOG [{level.upper()}]: {message}\")\n",
"\n",
"# 被适配者 (Adaptee) - 一个老的、接口不同的日志库\n",
"class LegacyLogger:\n",
" def write_log(self, text: str, severity_code: int):\n",
" # severity_code: 1=INFO, 2=WARNING, 3=ERROR\n",
" severity_map = {1: \"INFO\", 2: \"WARN\", 3: \"ERR\"}\n",
" print(f\"LEGACY LOG ({severity_map.get(severity_code, 'UNK')}): {text}\")\n",
"\n",
"# 适配器 (Adapter)\n",
"class LoggerAdapter(ModernLogger):\n",
" def __init__(self, legacy_logger: LegacyLogger):\n",
" self._legacy_logger = legacy_logger\n",
"\n",
" def log_message(self, level: str, message: str):\n",
" # 将 ModernLogger 的接口调用转换为 LegacyLogger 的接口调用\n",
" level_map = {\"INFO\": 1, \"WARNING\": 2, \"ERROR\": 3}\n",
" severity_code = level_map.get(level.upper(), 1) # 默认为 INFO\n",
" self._legacy_logger.write_log(message, severity_code)\n",
"\n",
"print(\"--- Adapter Pattern ---\")\n",
"legacy_logger_instance = LegacyLogger()\n",
"adapter = LoggerAdapter(legacy_logger_instance)\n",
"\n",
"# 客户端现在可以使用 ModernLogger 接口与 LegacyLogger 交互\n",
"adapter.log_message(\"info\", \"This is an informational message.\")\n",
"adapter.log_message(\"ERROR\", \"A critical error occurred!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.2 装饰器模式 (Decorator) - 结构型\n",
"\n",
"**意图**:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。\n",
"\n",
"**注意**:这里的“装饰器模式”是 GoF 设计模式中的一种结构型模式,它与 Python 语言特性中的“装饰器”(@-syntax) 虽然名称相同且有相似之处(都是包装),但概念上是独立的。Python 装饰器语法是实现装饰器模式的一种非常自然的方式。\n",
"\n",
"**场景**:当你希望在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 组件接口 (Component)\n",
"class Coffee(ABC):\n",
" @abstractmethod\n",
" def get_cost(self) -> float:\n",
" pass\n",
"\n",
" @abstractmethod\n",
" def get_description(self) -> str:\n",
" pass\n",
"\n",
"# 具体组件 (Concrete Component)\n",
"class SimpleCoffee(Coffee):\n",
" def get_cost(self) -> float:\n",
" return 5.0\n",
"\n",
" def get_description(self) -> str:\n",
" return \"Simple coffee\"\n",
"\n",
"# 装饰器基类 (Decorator Base)\n",
"class CoffeeDecorator(Coffee):\n",
" def __init__(self, wrapped_coffee: Coffee):\n",
" self._wrapped_coffee = wrapped_coffee\n",
"\n",
" @abstractmethod\n",
" def get_cost(self) -> float:\n",
" pass\n",
"\n",
" @abstractmethod\n",
" def get_description(self) -> str:\n",
" pass\n",
"\n",
"# 具体装饰器 (Concrete Decorators)\n",
"class MilkDecorator(CoffeeDecorator):\n",
" def get_cost(self) -> float:\n",
" return self._wrapped_coffee.get_cost() + 1.5\n",
"\n",
" def get_description(self) -> str:\n",
" return self._wrapped_coffee.get_description() + \", milk\"\n",
"\n",
"class SugarDecorator(CoffeeDecorator):\n",
" def get_cost(self) -> float:\n",
" return self._wrapped_coffee.get_cost() + 0.5\n",
"\n",
" def get_description(self) -> str:\n",
" return self._wrapped_coffee.get_description() + \", sugar\"\n",
"\n",
"print(\"--- Decorator Pattern (Structural) ---\")\n",
"my_coffee = SimpleCoffee()\n",
"print(f\"Coffee: {my_coffee.get_description()}, Cost: ${my_coffee.get_cost():.2f}\")\n",
"\n",
"# 加牛奶\n",
"my_coffee = MilkDecorator(my_coffee)\n",
"print(f\"Coffee: {my_coffee.get_description()}, Cost: ${my_coffee.get_cost():.2f}\")\n",
"\n",
"# 加糖\n",
"my_coffee = SugarDecorator(my_coffee)\n",
"print(f\"Coffee: {my_coffee.get_description()}, Cost: ${my_coffee.get_cost():.2f}\")\n",
"\n",
"# 再加一份牛奶 (可以多次装饰)\n",
"my_coffee_double_milk = MilkDecorator(MilkDecorator(SimpleCoffee()))\n",
"print(f\"Coffee: {my_coffee_double_milk.get_description()}, Cost: ${my_coffee_double_milk.get_cost():.2f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.3 外观模式 (Facade)\n",
"\n",
"**意图**:为子系统中的一组接口提供一个统一的、高层的接口。外观定义了一个高层接口,使得子系统更容易使用。\n",
"\n",
"**场景**:当你想为一个复杂的子系统提供一个简单的接口时,或者你想将子系统与客户端解耦。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 复杂的子系统组件\n",
"class CPU:\n",
" def freeze(self):\n",
" print(\"CPU: Freezing...\")\n",
" def jump(self, position):\n",
" print(f\"CPU: Jumping to {position}...\")\n",
" def execute(self):\n",
" print(\"CPU: Executing...\")\n",
"\n",
"class Memory:\n",
" def load(self, position, data):\n",
" print(f\"Memory: Loading data '{data}' to position {position}...\")\n",
"\n",
"class HardDrive:\n",
" def read(self, lba, size):\n",
" print(f\"HardDrive: Reading {size} bytes from LBA {lba}...\")\n",
" return \"boot_data\"\n",
"\n",
"# 外观 (Facade)\n",
"class ComputerFacade:\n",
" def __init__(self):\n",
" self.cpu = CPU()\n",
" self.memory = Memory()\n",
" self.hard_drive = HardDrive()\n",
"\n",
" def start(self):\n",
" print(\"\\n--- ComputerFacade: Starting computer ---\")\n",
" self.cpu.freeze()\n",
" boot_address = 0x0000\n",
" boot_sector_data = self.hard_drive.read(lba=0, size=512)\n",
" self.memory.load(boot_address, boot_sector_data)\n",
" self.cpu.jump(boot_address)\n",
" self.cpu.execute()\n",
" print(\"--- ComputerFacade: Computer started ---\")\n",
"\n",
"print(\"--- Facade Pattern ---\")\n",
"computer = ComputerFacade()\n",
"computer.start() # 客户端只需要调用一个简单的方法"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. 行为型模式 (Behavioral Patterns)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.1 策略模式 (Strategy)\n",
"\n",
"**意图**:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。策略模式使得算法可独立于使用它的客户而变化。\n",
"\n",
"**Pythonic 实现**:由于函数是一等公民,策略可以直接是函数,而不是必须是实现了特定接口的类。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from typing import List, Callable\n",
"\n",
"# 策略接口 (经典方式,Python中常直接用Callable)\n",
"class SortStrategy(ABC):\n",
" @abstractmethod\n",
" def sort(self, data: List[int]) -> List[int]:\n",
" pass\n",
"\n",
"# 具体策略\n",
"class BubbleSortStrategy(SortStrategy):\n",
" def sort(self, data: List[int]) -> List[int]:\n",
" print(\"Sorting using Bubble Sort\")\n",
" arr = list(data) # 创建副本以避免修改原始列表\n",
" n = len(arr)\n",
" for i in range(n):\n",
" for j in range(0, n - i - 1):\n",
" if arr[j] > arr[j + 1]:\n",
" arr[j], arr[j + 1] = arr[j + 1], arr[j]\n",
" return arr\n",
"\n",
"class QuickSortStrategy(SortStrategy):\n",
" def sort(self, data: List[int]) -> List[int]:\n",
" print(\"Sorting using Quick Sort (simplified)\")\n",
" arr = list(data)\n",
" # 实际的快速排序实现会更复杂,这里用内置排序代替简化\n",
" arr.sort() \n",
" return arr\n",
"\n",
"# 上下文 (Context)\n",
"class Sorter:\n",
" def __init__(self, strategy: SortStrategy = None):\n",
" self._strategy = strategy or QuickSortStrategy() # 默认策略\n",
"\n",
" def set_strategy(self, strategy: SortStrategy):\n",
" self._strategy = strategy\n",
"\n",
" def sort_data(self, data: List[int]) -> List[int]:\n",
" return self._strategy.sort(data)\n",
"\n",
"print(\"--- Strategy Pattern (Classic) ---\")\n",
"data_to_sort = [5, 1, 4, 2, 8]\n",
"sorter = Sorter() # 默认使用 QuickSort\n",
"print(f\"Sorted (default): {sorter.sort_data(data_to_sort)}\")\n",
"\n",
"sorter.set_strategy(BubbleSortStrategy())\n",
"print(f\"Sorted (bubble): {sorter.sort_data(data_to_sort)}\")\n",
"\n",
"# Pythonic 策略 (使用函数)\n",
"def bubble_sort_func(data: List[int]) -> List[int]:\n",
" print(\"Sorting using Bubble Sort (function)\")\n",
" # ... (实现同上)\n",
" arr = list(data)\n",
" n = len(arr)\n",
" for i in range(n):\n",
" for j in range(0, n - i - 1):\n",
" if arr[j] > arr[j + 1]:\n",
" arr[j], arr[j + 1] = arr[j + 1], arr[j]\n",
" return arr\n",
"\n",
"def quick_sort_func(data: List[int]) -> List[int]:\n",
" print(\"Sorting using Quick Sort (function)\")\n",
" arr = list(data)\n",
" arr.sort()\n",
" return arr\n",
"\n",
"class PythonicSorter:\n",
" def __init__(self, strategy_func: Callable[[List[int]], List[int]] = quick_sort_func):\n",
" self._strategy_func = strategy_func\n",
"\n",
" def set_strategy(self, strategy_func: Callable[[List[int]], List[int]]):\n",
" self._strategy_func = strategy_func\n",
"\n",
" def sort_data(self, data: List[int]) -> List[int]:\n",
" return self._strategy_func(data)\n",
"\n",
"print(\"\\n--- Strategy Pattern (Pythonic Functions) ---\")\n",
"py_sorter = PythonicSorter()\n",
"print(f\"Sorted (default func): {py_sorter.sort_data(data_to_sort)}\")\n",
"\n",
"py_sorter.set_strategy(bubble_sort_func)\n",
"print(f\"Sorted (bubble func): {py_sorter.sort_data(data_to_sort)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.2 观察者模式 (Observer)\n",
"\n",
"**意图**:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。\n",
"\n",
"**场景**:当一个对象的改变需要同时改变其他对象,而且你不知道具体有多少对象需要改变时。或者当一个对象应该能通知其他对象,而不需要知道那些对象是谁时。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 主题 (Subject / Observable)\n",
"class Subject:\n",
" def __init__(self):\n",
" self._observers: List[Callable] = [] # 存储观察者 (回调函数)\n",
" self._state = None\n",
"\n",
" def attach(self, observer: Callable):\n",
" if observer not in self._observers:\n",
" self._observers.append(observer)\n",
"\n",
" def detach(self, observer: Callable):\n",
" try:\n",
" self._observers.remove(observer)\n",
" except ValueError:\n",
" pass # Observer not found\n",
"\n",
" def notify(self):\n",
" print(\"Subject: Notifying observers...\")\n",
" for observer in self._observers:\n",
" observer(self._state) # 传递状态给观察者\n",
"\n",
" @property\n",
" def state(self):\n",
" return self._state\n",
"\n",
" @state.setter\n",
" def state(self, new_state):\n",
" print(f\"Subject: State changed to {new_state}\")\n",
" self._state = new_state\n",
" self.notify()\n",
"\n",
"# 观察者 (可以是函数或实现了特定接口的类)\n",
"def concrete_observer_A(state):\n",
" print(f\"Observer A: Received update, new state is {state}\")\n",
"\n",
"class ConcreteObserverB:\n",
" def __init__(self, name):\n",
" self.name = name\n",
"\n",
" def update(self, state):\n",
" print(f\"Observer {self.name}: Received update, new state is {state}\")\n",
"\n",
"print(\"--- Observer Pattern ---\")\n",
"subject = Subject()\n",
"\n",
"observer_b_instance = ConcreteObserverB(\"B1\")\n",
"\n",
"subject.attach(concrete_observer_A)\n",
"subject.attach(observer_b_instance.update) # 传递方法作为回调\n",
"\n",
"subject.state = \"NEW_DATA_1\"\n",
"print(\"-\")\n",
"subject.state = \"MORE_DATA_2\"\n",
"\n",
"subject.detach(concrete_observer_A)\n",
"print(\"-\")\n",
"subject.state = \"FINAL_DATA_3\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.3 命令模式 (Command)\n",
"\n",
"**意图**:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。\n",
"\n",
"**场景**:当你想把发出请求的对象与执行请求的对象解耦,或者想支持撤销/重做操作、事务等。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 命令接口 (Command)\n",
"class Command(ABC):\n",
" @abstractmethod\n",
" def execute(self):\n",
" pass\n",
"\n",
" # 可选的撤销方法\n",
" # @abstractmethod\n",
" # def undo(self):\n",
" # pass\n",
"\n",
"# 接收者 (Receiver) - 实际执行操作的对象\n",
"class Light:\n",
" def __init__(self, location: str):\n",
" self.location = location\n",
" self.is_on = False\n",
"\n",
" def turn_on(self):\n",
" self.is_on = True\n",
" print(f\"Light in {self.location} turned ON\")\n",
"\n",
" def turn_off(self):\n",
" self.is_on = False\n",
" print(f\"Light in {self.location} turned OFF\")\n",
"\n",
"# 具体命令 (Concrete Commands)\n",
"class LightOnCommand(Command):\n",
" def __init__(self, light: Light):\n",
" self._light = light\n",
"\n",
" def execute(self):\n",
" self._light.turn_on()\n",
"\n",
"class LightOffCommand(Command):\n",
" def __init__(self, light: Light):\n",
" self._light = light\n",
"\n",
" def execute(self):\n",
" self._light.turn_off()\n",
"\n",
"# 调用者 (Invoker) - 持有命令并请求执行\n",
"class RemoteControl:\n",
" def __init__(self):\n",
" self._command: Command = None\n",
"\n",
" def set_command(self, command: Command):\n",
" self._command = command\n",
"\n",
" def press_button(self):\n",
" if self._command:\n",
" print(\"Remote: Button pressed\")\n",
" self._command.execute()\n",
" else:\n",
" print(\"Remote: No command set\")\n",
"\n",
"print(\"--- Command Pattern ---\")\n",
"living_room_light = Light(\"Living Room\")\n",
"kitchen_light = Light(\"Kitchen\")\n",
"\n",
"light_on_living = LightOnCommand(living_room_light)\n",
"light_off_living = LightOffCommand(living_room_light)\n",
"light_on_kitchen = LightOnCommand(kitchen_light)\n",
"\n",
"remote = RemoteControl()\n",
"\n",
"remote.set_command(light_on_living)\n",
"remote.press_button()\n",
"\n",
"remote.set_command(light_off_living)\n",
"remote.press_button()\n",
"\n",
"remote.set_command(light_on_kitchen)\n",
"remote.press_button()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 总结\n",
"\n",
"设计模式为构建健壮、可维护的软件提供了宝贵的指导。\n",
"\n",
"* **创建型模式** 帮助你以灵活的方式创建对象。\n",
"* **结构型模式** 帮助你组合对象形成更大的结构。\n",
" * Python 的动态性和鸭子类型有时可以简化结构型模式的实现,例如,对于适配器,有时只需要一个简单的包装函数或类,而不必严格遵循接口继承。\n",
"* **行为型模式** 帮助你管理对象之间的交互和职责分配。\n",
" * Python 的一等函数特性使得许多行为型模式(如策略、命令、观察者中的回调)可以非常简洁地实现。\n",
"\n",
"**学习设计模式的关键:**\n",
"\n",
"1. **理解意图**:每个模式解决什么问题?\n",
"2. **了解结构**:模式中涉及哪些角色(类或对象)以及它们如何交互?\n",
"3. **思考适用场景**:什么时候应该使用这个模式?什么时候不应该?\n",
"4. **Pythonic 实现**:思考如何利用 Python 的特性(如动态类型、函数式特性、模块等)来更优雅地实现这些模式。\n",
"\n",
"不要试图一次性记住所有模式,而是要在实际开发中遇到类似问题时,能够识别出可能适用的模式,并查阅相关资料。最好的学习方式是通过实践和阅读优秀的代码。"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

对动态语言Python的一些感慨

众所周知Python是完全动态的语言,体现在

  1. 类型动态绑定
  2. 运行时检查
  3. 对象结构内容可动态修改(而不仅仅是值)
  4. 反射
  5. 一切皆对象(instance, class, method)
  6. 可动态执行代码(eval, exec)
  7. 鸭子类型支持

动态语言的约束更少,对使用者来说更易于入门,但相应的也会有代价就是运行时开销很大,和底层汇编执行逻辑完全解耦不知道代码到底是怎么执行的。

而且还有几点是我认为较为严重的缺陷。下面进行梳理。

破坏了OOP的语义

较为流行的编程语言大多支持OOP编程范式。即继承和多态。同样,Python在执行简单任务时候可以纯命令式(Imperative Programming),也可以使用复杂的面向对象OOP。

但是,其动态特性破环了OOP的结构:

  1. 类型模糊:任何类型实例,都可以在运行时添加或者删除属性或者方法(相比之下静态语言只能在运行时修改它们的值)。经此修改的实例,按理说不再属于原来的类型,毕竟和原类型已经有了明显的区别。但是该实例的内建__class__属性依旧会指向原类型,这会给类型的认知造成困惑。符合一个class不应该只是名义上符合,而是内容上也应该符合。
  2. 破坏继承:体现在以下两个方面
    1. 大部分实践没有虚接口继承。abc模块提供了虚接口的基类ABC,经典的做法是让自己的抽象类继承自ABC,然后具体类继承自自己的抽象类,然后去实现抽象方法。但PEP提案认为Pythonic的做法是用typing.Protocol来取代ABC,具体类完全不继承任何虚类,只要实现相应的方法,那么就可以被静态检查器认为是符合Protocol的。
    2. 不需要继承自具体父类。和上一条一样,即使一个类没有任何父类(除了object类),它依旧可以生成同名的方法,以实现和父类方法相同的调用接口。这样在语义逻辑上,类的定义完全看不出和其他类有何种关系。完全可以是一种松散的组织结构,任何两个类之间都没继承关系。
  3. 破坏多态:任何一个入参出参,天然不限制类型。这使得要求父类型的参数处,传入子类型显得没有意义,依旧是因为任何类型都能动态修改满足要求。

破坏了设计模式

经典的模式诸如工厂模式,抽象工厂,访问者模式,都严重依赖于继承和多态的性质。但是在python的设计中,其动态能力使得设计模式形同虚设。 大家常见的库中使用设计模式的有transformers库,其中的from_pretrained系列则是工厂模式,通过字符串名称确定了具体的构造器得到具体的子类。而工厂构造器的输出类型是一个所有模型的基类。

安全性问题

Python在代码层面一般不直接管理指针,所以指针越界,野指针,悬空指针等问题一般不存在。而gc机制也能自动处理垃圾回收使得编码过程不必关注这类安全性问题。但与之相对的,Python也有自己的安全性问题。以往非托管形式的代码的攻击难度较大,注入代码想要稳定执行需要避免破坏原来的结构导致程序直接崩溃(段错误)。 Python却可以直接注入任何代码修改原本的逻辑,并且由于不是在code段固定的内容,攻击时候也无需有额外考虑。运行时可以手动修改globals() locals()内容,亦有一定风险。 另一个危险则是类型不匹配导致的代码执行问题,因为只有在运行时才确定类型,无法提前做出保证,可能会产生类型错误的异常,造成程序崩溃。

总结

我出身于C++。但是近年来一直在用python编程。而且python的市场占有率已经多年第一,且遥遥领先。这和其灵活性分不开关系。对于一个面向大众的编程语言,这样的特性是必要的。即使以上说了诸多python的不严谨之处,但是对于程序员依旧可以选择严谨的面向对象写法。所以,程序的优劣不在于语言怎么样,而在于程序员本身。程序员有责任写出易于维护,清晰,规范的代码~

Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@KuRRe8
Copy link
Author

KuRRe8 commented May 8, 2025

返回顶部

有见解,有问题,或者单纯想盖楼灌水,都可以在这里发表!

因为文档比较多,有时候渲染不出来ipynb是浏览器性能的问题,刷新即可

或者git clone到本地来阅读

ChatGPT Image May 9, 2025, 04_45_04 AM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment