Python設計模式深度解析:裝飾器模式(Decorator Pattern)完全指南

Python設計模式深度解析:裝飾器模式(Decorator Pattern)完全指南

    • 前言
    • 什么是裝飾器模式?
      • 裝飾器模式的核心思想
    • Python函數裝飾器:從基礎到高級
      • 基礎函數裝飾器
      • 高級函數裝飾器實現
    • GUI裝飾器模式:動態界面增強
      • Tkinter按鈕裝飾器
    • 類裝飾器:元編程的力量
      • 數據類裝飾器對比
      • 自定義類裝飾器
    • 裝飾器模式 vs Python裝飾器語法
      • 相同點
      • 不同點
    • 實際應用場景
      • Web開發中的裝飾器
      • 性能監控裝飾器
    • 最佳實踐和注意事項
      • 1. 保持接口一致性
      • 2. 使用functools.wraps保持元數據
      • 3. 考慮裝飾器的順序
    • 總結
      • 關鍵要點
      • 選擇指南

前言

在軟件開發中,我們經常需要在不修改原有代碼的情況下為對象添加新功能。傳統的繼承方式雖然可以實現功能擴展,但會導致類的數量急劇增加,且缺乏靈活性。裝飾器模式(Decorator Pattern)為我們提供了一種更優雅的解決方案,它允許我們動態地為對象添加功能,而無需修改其結構。

本文將通過實際代碼示例,深入講解Python中裝飾器模式的實現方式、應用場景以及與Python內置裝飾器語法的關系。

什么是裝飾器模式?

裝飾器模式是一種結構型設計模式,它允許向一個現有的對象添加新的功能,同時又不改變其結構。這種模式創建了一個裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。

裝飾器模式的核心思想

  1. 組合優于繼承:通過對象組合而非繼承來擴展功能
  2. 透明性:裝飾器與被裝飾對象具有相同的接口
  3. 動態性:可以在運行時動態地添加或移除功能
  4. 可組合性:多個裝飾器可以組合使用

Python函數裝飾器:從基礎到高級

基礎函數裝飾器

讓我們從一個簡單的函數裝飾器開始:

def mathFunc(func):"""基礎裝飾器函數"""def wrapper(x):print("b4 func")  # 函數執行前func(x)           # 執行原函數print("after func")  # 函數執行后return wrapper# 方式1:手動應用裝飾器
def sayMath(x):print("math")sayMath = mathFunc(sayMath)  # 手動裝飾
sayMath(12)# 方式2:使用@語法糖
@mathFunc
def sayMath2(x):print("math")sayMath2(12)

這個例子展示了裝飾器的基本工作原理:

  1. 裝飾器函數接收一個函數作為參數
  2. 返回一個新的函數(wrapper)
  3. 新函數在調用原函數前后添加額外功能

高級函數裝飾器實現

讓我們實現一些更實用的裝飾器:

import time
import functools
from typing import Any, Callabledef timer(func: Callable) -> Callable:"""計時裝飾器"""@functools.wraps(func)def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)end_time = time.time()print(f"{func.__name__} 執行時間: {end_time - start_time:.4f}秒")return resultreturn wrapperdef logger(func: Callable) -> Callable:"""日志裝飾器"""@functools.wraps(func)def wrapper(*args, **kwargs):print(f"調用函數: {func.__name__}")print(f"參數: args={args}, kwargs={kwargs}")result = func(*args, **kwargs)print(f"返回值: {result}")return resultreturn wrapperdef retry(max_attempts: int = 3, delay: float = 1):"""重試裝飾器(參數化裝飾器)"""def decorator(func: Callable) -> Callable:@functools.wraps(func)def wrapper(*args, **kwargs):for attempt in range(max_attempts):try:return func(*args, **kwargs)except Exception as e:if attempt == max_attempts - 1:raise eprint(f"第{attempt + 1}次嘗試失敗: {e}")time.sleep(delay)return wrapperreturn decoratordef cache(func: Callable) -> Callable:"""緩存裝飾器"""cache_dict = {}@functools.wraps(func)def wrapper(*args, **kwargs):# 創建緩存鍵key = str(args) + str(sorted(kwargs.items()))if key in cache_dict:print(f"緩存命中: {func.__name__}")return cache_dict[key]result = func(*args, **kwargs)cache_dict[key] = resultprint(f"緩存存儲: {func.__name__}")return resultreturn wrapper# 使用裝飾器的示例
@timer
@logger
def calculate_sum(n: int) -> int:"""計算1到n的和"""return sum(range(1, n + 1))@cache
@timer
def fibonacci(n: int) -> int:"""計算斐波那契數列"""if n <= 1:return nreturn fibonacci(n - 1) + fibonacci(n - 2)@retry(max_attempts=3, delay=0.5)
def unreliable_network_call():"""模擬不可靠的網絡調用"""import randomif random.random() < 0.7:  # 70%失敗率raise Exception("網絡連接失敗")return "數據獲取成功"# 測試裝飾器
def test_decorators():print("=== 計時和日志裝飾器 ===")result = calculate_sum(1000)print("\n=== 緩存裝飾器 ===")print("第一次計算斐波那契:")fib_result = fibonacci(10)print("第二次計算斐波那契:")fib_result = fibonacci(10)  # 使用緩存print("\n=== 重試裝飾器 ===")try:result = unreliable_network_call()print(f"網絡調用成功: {result}")except Exception as e:print(f"網絡調用最終失敗: {e}")if __name__ == "__main__":test_decorators()

GUI裝飾器模式:動態界面增強

Tkinter按鈕裝飾器

基于您的代碼,讓我們看看如何在GUI中應用裝飾器模式:

from tkinter import *class Decorator(Button):"""按鈕裝飾器基類"""def __init__(self, master, **kwargs):super().__init__(master, **kwargs)# 默認設置為平面樣式self.configure(relief=FLAT)# 綁定鼠標事件self.bind("<Enter>", self.on_enter)self.bind("<Leave>", self.on_leave)def on_enter(self, evt):"""鼠標進入時的效果"""self.configure(relief=RAISED)def on_leave(self, evt):"""鼠標離開時的效果"""self.configure(relief=FLAT)class HoverButton(Decorator):"""懸停效果按鈕"""def __init__(self, master, text="按鈕", **kwargs):super().__init__(master, text=text, **kwargs)class ClickCountButton(Decorator):"""點擊計數按鈕裝飾器"""def __init__(self, master, text="按鈕", **kwargs):super().__init__(master, **kwargs)self.click_count = 0self.original_text = textself.configure(text=f"{text} (0)")self.configure(command=self.on_click)def on_click(self):"""點擊事件處理"""self.click_count += 1self.configure(text=f"{self.original_text} ({self.click_count})")class ColorChangeButton(Decorator):"""顏色變化按鈕裝飾器"""def __init__(self, master, text="按鈕", **kwargs):super().__init__(master, text=text, **kwargs)self.colors = ['lightblue', 'lightgreen', 'lightcoral', 'lightyellow']self.color_index = 0self.configure(bg=self.colors[0])self.configure(command=self.change_color)def change_color(self):"""改變按鈕顏色"""self.color_index = (self.color_index + 1) % len(self.colors)self.configure(bg=self.colors[self.color_index])# GUI應用示例
class DecoratorGUIDemo:def __init__(self):self.root = Tk()self.root.title("裝飾器模式GUI演示")self.root.geometry("400x300")self.create_widgets()def create_widgets(self):"""創建界面組件"""Label(self.root, text="裝飾器模式按鈕演示", font=("Arial", 16)).pack(pady=10)# 基礎懸停按鈕hover_btn = HoverButton(self.root, "懸停效果按鈕")hover_btn.pack(pady=5)# 點擊計數按鈕count_btn = ClickCountButton(self.root, "點擊計數按鈕")count_btn.pack(pady=5)# 顏色變化按鈕color_btn = ColorChangeButton(self.root, "顏色變化按鈕")color_btn.pack(pady=5)# 組合裝飾器按鈕combo_btn = self.create_combo_button()combo_btn.pack(pady=5)# 退出按鈕Button(self.root, text="退出", command=self.root.quit).pack(pady=20)def create_combo_button(self):"""創建組合裝飾器按鈕"""class ComboButton(ClickCountButton, ColorChangeButton):def __init__(self, master, text="組合按鈕", **kwargs):# 多重繼承需要小心處理Decorator.__init__(self, master, text=text, **kwargs)self.click_count = 0self.original_text = textself.colors = ['lightblue', 'lightgreen', 'lightcoral', 'lightyellow']self.color_index = 0self.configure(text=f"{text} (0)", bg=self.colors[0])self.configure(command=self.on_combo_click)def on_combo_click(self):"""組合點擊事件"""self.click_count += 1self.color_index = (self.color_index + 1) % len(self.colors)self.configure(text=f"{self.original_text} ({self.click_count})",bg=self.colors[self.color_index])return ComboButton(self.root, "組合裝飾器按鈕")def run(self):"""運行應用"""self.root.mainloop()# 運行GUI演示
if __name__ == "__main__":app = DecoratorGUIDemo()app.run()

類裝飾器:元編程的力量

數據類裝飾器對比

讓我們對比傳統類定義和使用@dataclass裝飾器的區別:

# 傳統類定義(基于您的dclasse.py)
class Employee:def __init__(self, frname: str, lname: str, idnum: int,town='Stamford', state='CT', zip='06820'):self.frname = frnameself.lname = lnameself.idnum = idnumself.town = townself.state = stateself.zip = zipdef nameString(self):return f"{self.frname} {self.lname} {self.idnum}"def __repr__(self):return f"Employee({self.frname}, {self.lname}, {self.idnum})"def __eq__(self, other):if not isinstance(other, Employee):return Falsereturn (self.frname == other.frname and self.lname == other.lname and self.idnum == other.idnum)# 使用@dataclass裝飾器(基于您的dclass.py)
from dataclasses import dataclass@dataclass
class EmployeeDataClass:frname: strlname: stridnum: inttown: str = "Stamford"state: str = 'CT'zip: str = '06820'def nameString(self):return f"{self.frname} {self.lname} {self.idnum}"# 對比測試
def compare_implementations():"""對比兩種實現方式"""print("=== 傳統類實現 ===")emp1 = Employee('Sarah', 'Smythe', 123)emp2 = Employee('Sarah', 'Smythe', 123)print(f"emp1: {emp1}")print(f"emp1 == emp2: {emp1 == emp2}")print(f"emp1.nameString(): {emp1.nameString()}")print("\n=== @dataclass實現 ===")emp3 = EmployeeDataClass('Sarah', 'Smythe', 123)emp4 = EmployeeDataClass('Sarah', 'Smythe', 123)print(f"emp3: {emp3}")print(f"emp3 == emp4: {emp3 == emp4}")  # 自動生成__eq__print(f"emp3.nameString(): {emp3.nameString()}")if __name__ == "__main__":compare_implementations()

自定義類裝飾器

讓我們實現一些實用的類裝飾器:

def singleton(cls):"""單例裝飾器"""instances = {}def get_instance(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return get_instancedef add_repr(cls):"""添加__repr__方法的裝飾器"""def __repr__(self):attrs = ', '.join(f'{k}={v!r}' for k, v in self.__dict__.items())return f"{cls.__name__}({attrs})"cls.__repr__ = __repr__return clsdef validate_types(**type_validators):"""類型驗證裝飾器"""def decorator(cls):original_setattr = cls.__setattr__def new_setattr(self, name, value):if name in type_validators:expected_type = type_validators[name]if not isinstance(value, expected_type):raise TypeError(f"{name} must be of type {expected_type.__name__}, "f"got {type(value).__name__}")original_setattr(self, name, value)cls.__setattr__ = new_setattrreturn clsreturn decoratordef auto_property(*attr_names):"""自動屬性裝飾器"""def decorator(cls):for attr_name in attr_names:private_name = f"_{attr_name}"def make_property(name, private):def getter(self):return getattr(self, private, None)def setter(self, value):setattr(self, private, value)return property(getter, setter)setattr(cls, attr_name, make_property(attr_name, private_name))return clsreturn decorator# 使用類裝飾器的示例
@singleton
@add_repr
class DatabaseConnection:def __init__(self, host="localhost", port=5432):self.host = hostself.port = portself.connected = Falseprint(f"創建數據庫連接: {host}:{port}")def connect(self):self.connected = Trueprint("連接到數據庫")@validate_types(name=str, age=int, salary=float)
@add_repr
class Person:def __init__(self, name, age, salary):self.name = nameself.age = ageself.salary = salary@auto_property('name', 'age')
class Student:def __init__(self, name, age):self.name = name  # 會調用setterself.age = age    # 會調用setter# 測試類裝飾器
def test_class_decorators():print("=== 單例裝飾器測試 ===")db1 = DatabaseConnection()db2 = DatabaseConnection("remote", 3306)print(f"db1 is db2: {db1 is db2}")  # True,單例模式print(f"db1: {db1}")print("\n=== 類型驗證裝飾器測試 ===")try:person = Person("Alice", 25, 50000.0)print(f"person: {person}")person.age = "invalid"  # 會拋出TypeErrorexcept TypeError as e:print(f"類型驗證失敗: {e}")print("\n=== 自動屬性裝飾器測試 ===")student = Student("Bob", 20)print(f"student.name: {student.name}")print(f"student._name: {student._name}")  # 私有屬性if __name__ == "__main__":test_class_decorators()

裝飾器模式 vs Python裝飾器語法

相同點

  1. 功能增強:都用于為對象或函數添加額外功能
  2. 透明性:都保持原有接口不變
  3. 組合性:都可以組合使用

不同點

  1. 應用層面

    • 裝飾器模式:主要用于對象級別的功能擴展
    • Python裝飾器:主要用于函數和類的元編程
  2. 實現方式

    • 裝飾器模式:通過類的組合和繼承
    • Python裝飾器:通過函數的高階特性
  3. 運行時行為

    • 裝飾器模式:可以在運行時動態添加/移除裝飾器
    • Python裝飾器:在定義時就確定了裝飾關系

實際應用場景

Web開發中的裝飾器

# Flask風格的路由裝飾器
def route(path):def decorator(func):# 注冊路由app.routes[path] = funcreturn funcreturn decorator# 權限驗證裝飾器
def require_auth(func):@functools.wraps(func)def wrapper(*args, **kwargs):if not current_user.is_authenticated:raise PermissionError("需要登錄")return func(*args, **kwargs)return wrapper# 使用示例
@route('/api/users')
@require_auth
def get_users():return {"users": ["Alice", "Bob"]}

性能監控裝飾器

import psutil
import threadingdef monitor_performance(func):"""性能監控裝飾器"""@functools.wraps(func)def wrapper(*args, **kwargs):# 記錄開始狀態start_memory = psutil.Process().memory_info().rssstart_time = time.time()try:result = func(*args, **kwargs)return resultfinally:# 記錄結束狀態end_memory = psutil.Process().memory_info().rssend_time = time.time()print(f"函數 {func.__name__} 性能報告:")print(f"  執行時間: {end_time - start_time:.4f}秒")print(f"  內存變化: {(end_memory - start_memory) / 1024 / 1024:.2f}MB")return wrapper@monitor_performance
def heavy_computation():"""重計算任務"""data = [i ** 2 for i in range(1000000)]return sum(data)

最佳實踐和注意事項

1. 保持接口一致性

# 好的做法:保持接口一致
class TextProcessor:def process(self, text):return textclass UpperCaseDecorator:def __init__(self, processor):self._processor = processordef process(self, text):  # 保持相同的方法簽名return self._processor.process(text).upper()# 不好的做法:改變接口
class BadDecorator:def __init__(self, processor):self._processor = processordef process_text(self, text):  # 改變了方法名return self._processor.process(text).upper()

2. 使用functools.wraps保持元數據

import functoolsdef good_decorator(func):@functools.wraps(func)  # 保持原函數的元數據def wrapper(*args, **kwargs):return func(*args, **kwargs)return wrapperdef bad_decorator(func):def wrapper(*args, **kwargs):  # 丟失原函數的元數據return func(*args, **kwargs)return wrapper@good_decorator
def example_function():"""這是一個示例函數"""passprint(example_function.__name__)  # 輸出: example_function
print(example_function.__doc__)   # 輸出: 這是一個示例函數

3. 考慮裝飾器的順序

@timer
@logger
@cache
def complex_function(n):"""復雜函數"""# 執行順序:cache -> logger -> timer -> complex_functionreturn sum(range(n))# 等價于:
# complex_function = timer(logger(cache(complex_function)))

總結

裝飾器模式是一種強大的設計模式,它提供了比繼承更靈活的功能擴展方式。在Python中,我們既可以使用傳統的面向對象方式實現裝飾器模式,也可以利用Python的裝飾器語法來實現類似的功能。

關鍵要點

  1. 組合優于繼承:裝飾器模式通過組合來擴展功能
  2. 透明性:裝飾器與被裝飾對象具有相同接口
  3. 靈活性:可以動態地添加、移除或組合裝飾器
  4. Python特色:充分利用Python的裝飾器語法和元編程特性

選擇指南

  • 對象功能擴展:使用傳統的裝飾器模式
  • 函數功能增強:使用Python函數裝飾器
  • 類功能增強:使用Python類裝飾器
  • 元編程需求:結合使用多種裝飾器技術

通過本文的學習,相信您已經掌握了裝飾器模式的精髓。在實際開發中,請根據具體場景選擇合適的實現方式,并始終考慮代碼的可讀性和可維護性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/89323.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/89323.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/89323.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JVM--虛擬線程

首先了解一個理念&#xff1a;線程與 OS 線程 1:1 綁定在傳統 Java 線程&#xff08;平臺線程&#xff09;模型中&#xff1a;每個 Java 線程直接對應一個操作系統級別的線程操作系統負責調度這些線程線程的創建、管理和調度都由操作系統內核處理這種模型稱為 1:1 線程模型&…

掌握系統設計的精髓:12個核心設計模式的通俗解讀

在構建復雜且高可用的軟件系統時&#xff0c;僅僅了解編程語言和算法是不夠的。真正的挑戰在于如何設計出能夠應對并發、故障、擴展等各種問題的健壯架構。系統設計模式正是前輩們在無數實踐中提煉出的智慧結晶&#xff0c;它們是解決常見系統問題的“最佳實踐”。 本文將深入淺…

概率論與數理統計(二)

事件的概率 概率&#xff1a;可能性的大小 古典概率模型&#xff1a; 1&#xff09;有限個樣本點 2&#xff09;等可能性 P(A)A中包含的基本事件數基本事件總和 P(A) \frac{A中包含的基本事件數}{基本事件總和} P(A)基本事件總和A中包含的基本事件數? 頻率與概率 nnn 次實驗…

新型eSIM攻擊技術可克隆用戶資料并劫持手機身份

eSIM技術存在重大安全漏洞研究人員發現eSIM技術中存在一個關鍵漏洞&#xff0c;攻擊者可利用該漏洞克隆移動用戶資料并劫持手機身份。AG安全研究團隊宣布&#xff0c;他們成功攻破了采用GSMA消費者證書的Kigen eUICC&#xff08;嵌入式通用集成電路卡&#xff09;安全防護&…

langchain教程2:更加高級和靈活的Prompt模板

文章目錄 prompt模板 對話Prompt模板 函數大師 使用jinja2與f-string實現提示詞模板格式化 組合式提示詞模板 prompt模板 from langchain.prompts import PromptTemplateprompt = PromptTemplate.from_template("你是一個{name},幫我起一個具有{country}特色的{gender}名…

UE5使用Motion Warping有什么用?

在 UE5 中&#xff0c;Motion Warping 是一套用于「動態調整根運動動畫」的系統插件&#xff0c;它能讓帶有根運動&#xff08;Root Motion&#xff09;的動畫根據游戲運行時的環境自動變形&#xff08;Warp&#xff09;&#xff0c;以更精準地貼合目標位置或目標方向&#xff…

類模版的相關案例

案例實現&#xff1a;實現一個通用的數組類&#xff0c;要求如下&#xff1a;可以對內置數據類型以及自定義數據類型的數據進行存儲將數組中的數據存儲到堆區構造函數中可以傳入數組的容量提供對應的拷貝構造函數以及operator防止淺拷貝問題提供尾插法和尾刪法對數組中的數據進…

服務器端安全檢測與防御技術概述

一、服務器安全風險1.不必要的訪問&#xff08;如只提供HTTP服務&#xff09;--應用識別控制2.公網發起IP或端口掃描、DDOS攻擊等--防火墻3.漏洞攻擊&#xff08;針對服務器操作系統等&#xff09;--IPS4.根據軟件版本的已知漏洞進行攻擊&#xff0c;口令暴力破解、獲取用戶權限…

前端性能與可靠性工程系列: 渲染、緩存與關鍵路徑優化

前端性能與可靠性工程系列: 渲染、緩存與關鍵路徑優化 第一部分:揭秘瀏覽器 - 關鍵渲染路徑 (CRP) 關鍵渲染路徑 (Critical Rendering Path - CRP) 是指瀏覽器從接收到最初的 HTML、CSS 和 JavaScript 字節,到最終將它們渲染成可見像素所必須經過的一系列步驟。我們的目標,…

基于CentOS的分布式GitLab+Jenkins+Docker架構:企業級CI/CD流水線實戰全記錄

引言&#xff1a;從單機到分布式容器架構的演進在傳統Web應用部署中&#xff0c;我們常常面臨環境不一致、部署效率低下等問題。我曾經維護過一個需要手動在5臺服務器上重復部署的游戲項目&#xff0c;每次發布都如同走鋼絲。本文將詳細分享如何基于CentOS系統&#xff0c;構建…

JVM——為什么Java8移除了永久代(PermGen)并引入了元空間(Metaspace)?

Java8移除永久代并引入元空間&#xff0c;主要是為了解決 PermGen 固定大小、容易導致內存溢出、GC 效率低的問題。元空間使用本地內存&#xff0c;具備更靈活的內存分配能力&#xff0c;提升了垃圾收集和內存管理的效率。 PermGen 的局限性 ①固定大小:永久代的內存空間大小在…

3.正則化——新聞分類

影響結果出了最終的目標&#xff0c;還會有許多細節因素 在機器學習中&#xff0c;往往會面臨很多過擬合和欠擬合的問題。 欠擬合是訓練不到位&#xff0c;過擬合是訓練過頭&#xff0c;會導致泛化性差正則化是在損失函數中添加一個懲罰項&#xff0c;以簡化模型對于懲罰項Pena…

HTML的重要知識

什么是HTMLHTML是Hyper Text Markup Language的縮寫&#xff0c;意思是超文本標記語言。標簽標題標簽&#xff1a;————-h1,h2,h3.....段落標簽 &#xff1a;————p換行標簽&#xff1a; ————br列表標簽&#xff1a;有序列表&#xff1a;——ol無序列表&#xff1a;—…

【C語言網絡編程】HTTP 客戶端請求(發送請求報文過程)

在 C 語言中&#xff0c;我們可以使用 socket 編程來手動實現一個簡單的 HTTP 客戶端&#xff0c;像瀏覽器一樣請求網頁數據。本文將結合實際代碼&#xff0c;重點講解如何通過 C 語言構造并發送一個 HTTP 請求報文&#xff0c;實現與服務器的基本通信。 文章目標 通過一個簡單…

oracle2kingbase的字段長度問題

實驗一&#xff1a; oracle中&#xff1a; create table testlen(c1 varchar2(2)); insert into testlen values(山); --成功 insert into testlen values(山西); --失敗 ORA-12899: 列 "TESTK"."TESTLEN"."C1" 的值太大 (實際值: 4, 最大值: 2…

單鏈表的題目,咕咕咕

1.咕 203. 移除鏈表元素 - 力扣&#xff08;LeetCode&#xff09; 給你一個鏈表的頭節點 head 和一個整數 val &#xff0c;請你刪除鏈表中所有滿足 Node.val val 的節點&#xff0c;并返回 新的頭節點 struct ListNode* removeElements(struct ListNode* head, int val) …

關于程序=數據結構+算法這句話最近的一些思考

最近看了很多單片機STM32的的相關程序&#xff0c;尤其是設計到ringbuff、buffer_manage、os_memory預計mem_manage等程序中間層的用法&#xff0c;我對這句話有了一些更深的思考&#xff0c;現在記錄下來&#xff0c;希望對處于相同階段的程序一些思想啟迪。首先“數據結構”也…

Rust 錯誤處理

Rust 錯誤處理 引言 Rust 是一種系統編程語言&#xff0c;以其安全、并發和性能著稱。在 Rust 中&#xff0c;錯誤處理是一個核心概念&#xff0c;它確保了程序在遇到異常情況時能夠優雅地處理。本文將深入探討 Rust 中的錯誤處理機制&#xff0c;包括錯誤類型、錯誤傳播、錯誤…

17. 什么是 webSocket ?

總結 WebSocket 是 HTML5 引入的一種新協議&#xff0c;允許客戶端和服務器之間進行雙向實時通信。建立在 TCP 協議之上&#xff0c;默認端口是 80&#xff08;ws&#xff09; 和 443&#xff08;wss&#xff09;&#xff0c;沒有同源限制&#xff0c;客戶端可以與任意服務器通…

從零開始跑通3DGS教程:(五)3DGS訓練

寫在前面 本文內容 所屬《從零開始跑通3DGS教程》系列文章; 本文介紹在docker中訓練3dgs的方法 平臺/環境 linux, nvidia GPU, docker 轉載請注明出處: https://blog.csdn.net/qq_41102371/article/details/146535874 目錄 寫在前面系列文章準備docker創建環境參考完系列文章…