最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python開發(fā)中transitions的使用小結(jié)

 更新時間:2026年06月10日 09:40:27   作者:程序員小jobleap  
在 Python 開發(fā)中,transitions 是最流行、功能最強大的有限狀態(tài)機(Finite State Machine, FSM)庫,本文就來詳細(xì)的介紹一下如何使用,感興趣的可以了解一下

在 Python 開發(fā)中,transitions 是最流行、功能最強大的有限狀態(tài)機(Finite State Machine, FSM)庫。以下為您提供一份核心優(yōu)先、結(jié)構(gòu)清晰的詳細(xì)使用教程。

?? 安裝

在 macOS 下,推薦使用 uv 管理依賴:

# 基礎(chǔ)安裝
uv pip install transitions
# 如果需要支持繪制狀態(tài)轉(zhuǎn)移圖 (需要系統(tǒng)已安裝 graphviz)
uv pip install transitions[diagrams]

1. 基礎(chǔ)概念與極簡示例

transitions 的核心由 States(狀態(tài))、Transitions(轉(zhuǎn)換關(guān)系)Machine(狀態(tài)機) 組成。

from transitions import Machine

# 1. 定義狀態(tài)列表
states = ['off', 'on']

# 2. 定義狀態(tài)轉(zhuǎn)換規(guī)則
# trigger: 觸發(fā)動作的方法名
# source: 轉(zhuǎn)換前的狀態(tài)
# dest: 轉(zhuǎn)換后的目標(biāo)狀態(tài)
transitions = [
    {'trigger': 'turn_on', 'source': 'off', 'dest': 'on'},
    {'trigger': 'turn_off', 'source': 'on', 'dest': 'off'}
]

# 3. 初始化狀態(tài)機
# 默認(rèn)情況下,如果不傳 model,Machine 實例本身將作為 Model
machine = Machine(states=states, transitions=transitions, initial='off')

# 4. 使用狀態(tài)機
print(machine.state)  # 輸出: off
machine.turn_on()     # 觸發(fā) 'turn_on'
print(machine.state)  # 輸出: on

2. 綁定自定義業(yè)務(wù)模型 (Model)

在實際開發(fā)中,我們通常將狀態(tài)機邏輯綁定到自定義的對象上。狀態(tài)機會動態(tài)地將狀態(tài)控制方法注入到該對象中。

from transitions import Machine

# 業(yè)務(wù)類
class LightBulb:
    def __init__(self):
        self.brightness = 100

bulb = LightBulb()
states = ['off', 'on', 'broken']

# 將狀態(tài)機綁定到 bulb 實例
machine = Machine(model=bulb, states=states, initial='off')

# 動態(tài)添加轉(zhuǎn)換規(guī)則
# '*' 代表可以從任何狀態(tài)轉(zhuǎn)換到 'broken'
machine.add_transition(trigger='burn_out', source='*', dest='broken')
machine.add_transition(trigger='turn_on', source='off', dest='on')

# 此時 bulb 對象擁有了 state 屬性和觸發(fā)器方法
print(bulb.state)  # 輸出: off
bulb.turn_on()
print(bulb.state)  # 輸出: on
bulb.burn_out()
print(bulb.state)  # 輸出: broken

3. 條件限制 (Conditions)與異常處理

你可以設(shè)置 conditionsunless 限制狀態(tài)轉(zhuǎn)移。只有當(dāng)條件函數(shù)返回 True(或 unless 返回 False)時,轉(zhuǎn)換才會發(fā)生。

from transitions import Machine, MachineError

class Water:
    def __init__(self):
        self.temperature = 20

    def is_hot(self):
        return self.temperature >= 100

water = Water()
states = ['liquid', 'gas']
# ignore_invalid_triggers=True 可以防止在無效狀態(tài)下調(diào)用觸發(fā)器拋出異常,而是返回 False
machine = Machine(model=water, states=states, initial='liquid', ignore_invalid_triggers=True)

machine.add_transition(
    trigger='evaporate', 
    source='liquid', 
    dest='gas', 
    conditions='is_hot'  # 綁定條件檢查方法
)

# 嘗試在 20 度時蒸發(fā)
success = water.evaporate()
print(success)      # 輸出: False (轉(zhuǎn)換失敗)
print(water.state)  # 輸出: liquid

# 加熱后再次嘗試
water.temperature = 100
success = water.evaporate()
print(success)      # 輸出: True (轉(zhuǎn)換成功)
print(water.state)  # 輸出: gas

4. 生命周期回調(diào)函數(shù) (Callbacks)

狀態(tài)轉(zhuǎn)換前后可以觸發(fā)各種生命周期鉤子:

  • prepare: 轉(zhuǎn)換開始前觸發(fā)(即使條件不滿足也會觸發(fā))。
  • before: 確定可以開始轉(zhuǎn)換時(條件滿足后)觸發(fā)。
  • after: 轉(zhuǎn)換成功后觸發(fā)。
class Hero:
    def wear_armor(self):
        print("[Callback] 穿上戰(zhàn)甲!")

    def log_success(self):
        print("[Callback] 狀態(tài)成功轉(zhuǎn)換。")

hero = Hero()
states = ['normal', 'combat']
machine = Machine(model=hero, states=states, initial='normal')

machine.add_transition(
    trigger='encounter_enemy', 
    source='normal', 
    dest='combat',
    before='wear_armor',
    after='log_success'
)

hero.encounter_enemy()
# 控制臺輸出:
# [Callback] 穿上戰(zhàn)甲!
# [Callback] 狀態(tài)成功轉(zhuǎn)換。

5. 分層/嵌套狀態(tài)機 (Hierarchical State Machine)

當(dāng)業(yè)務(wù)復(fù)雜、狀態(tài)具有層級關(guān)系時,可以使用 HierarchicalMachine。例如:設(shè)備在 on 狀態(tài)下,又分為 standbyworking 子狀態(tài)。

from transitions.extensions import HierarchicalMachine as Machine

# 定義嵌套狀態(tài)結(jié)構(gòu)
states = [
    'off',
    {
        'name': 'on',
        'children': ['standby', 'working'],
        'initial': 'standby'
    }
]

machine = Machine(states=states, initial='off')

machine.add_transition('power_on', 'off', 'on')
machine.add_transition('activate', 'on_standby', 'on_working')
# 從 on 下的任何子狀態(tài)均可 power_off 轉(zhuǎn)換到 off
machine.add_transition('power_off', 'on', 'off')

print(machine.state)  # 輸出: off
machine.power_on()
print(machine.state)  # 輸出: on_standby (進(jìn)入 on 狀態(tài)的默認(rèn)初始子狀態(tài))
machine.activate()
print(machine.state)  # 輸出: on_working

6. 異步狀態(tài)機 (AsyncMachine)

在 FastAPI 等異步上下文中,你可以使用 AsyncMachine。其所有回調(diào)和觸發(fā)器都會以協(xié)程形式運行。

import asyncio
from transitions.extensions.asyncio import AsyncMachine

class AsyncTask:
    async def notify_server(self):
        print("開始向服務(wù)器同步狀態(tài)...")
        await asyncio.sleep(0.5)
        print("同步完成。")

task = AsyncTask()
states = ['pending', 'completed']
machine = AsyncMachine(model=task, states=states, initial='pending')

machine.add_transition(
    trigger='complete', 
    source='pending', 
    dest='completed',
    before='notify_server'
)

async def main():
    # 異步觸發(fā)器必須使用 await
    await task.complete()
    print(f"當(dāng)前狀態(tài): {task.state}")

asyncio.run(main())

在結(jié)合 PostgreSQL 使用時,最優(yōu)雅的實踐是使用 SQLAlchemy 2.0 (ORM)。通過配置 transitionsmodel_attribute 參數(shù),狀態(tài)機可以直接讀寫 SQLAlchemy 托管的數(shù)據(jù)庫字段,狀態(tài)變更會被 SQLAlchemy 自動追蹤,最后通過 session.commit() 持久化到 PostgreSQL。

以下是基于 異步 SQLAlchemy 2.0 + PostgreSQL 的完整持久化實踐教程。

?? 1. 安裝依賴

uv pip install sqlalchemy asyncpg transitions

?? 2. 設(shè)計核心方案

我們將定義一個 Order(訂單)模型,其狀態(tài)字段為 status。我們將狀態(tài)機設(shè)置為單例,并在從數(shù)據(jù)庫查詢出訂單后,動態(tài)將其綁定到狀態(tài)機中。

代碼實現(xiàn):database.py&models.py

import asyncio
from sqlalchemy import String, Integer
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, DeclarativeBase
from sqlalchemy.orm import Mapped, mapped_column
from transitions import Machine

# 1. 初始化數(shù)據(jù)庫連接 (請?zhí)鎿Q為您的 PostgreSQL 連接串)
DATABASE_URL = "postgresql+asyncpg://postgres:password@localhost:5432/mydb"
engine = create_async_engine(DATABASE_URL, echo=True)
async_session = async_sessionmaker(engine, expire_on_commit=False)

class Base(DeclarativeBase):
    pass

# 2. 定義 SQLAlchemy 訂單模型
class Order(Base):
    __tablename__ = "orders"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    title: Mapped[str] = mapped_column(String(100))
    # 狀態(tài)字段,對應(yīng)狀態(tài)機中的狀態(tài)
    status: Mapped[str] = mapped_column(String(50), default="created")

# 3. 初始化全局狀態(tài)機 (不綁定具體 model)
# model_attribute='status' 關(guān)鍵參數(shù):指示狀態(tài)機讀寫 model 的 status 屬性而不是默認(rèn)的 state
states = ["created", "paid", "shipped", "completed", "cancelled"]
order_machine = Machine(
    model=None,  # 初始不綁定任何 model
    states=states, 
    initial="created", 
    model_attribute="status",
    ignore_invalid_triggers=True
)

# 4. 定義轉(zhuǎn)換規(guī)則
order_machine.add_transition(trigger="pay", source="created", dest="paid")
order_machine.add_transition(trigger="ship", source="paid", dest="shipped")
order_machine.add_transition(trigger="complete", source="shipped", dest="completed")
order_machine.add_transition(trigger="cancel", source=["created", "paid"], dest="cancelled")

?? 3. 業(yè)務(wù)層使用:查詢、轉(zhuǎn)換與持久化

在業(yè)務(wù)邏輯中,我們從 PostgreSQL 讀取 Order 實例,將其加入狀態(tài)機,觸發(fā)轉(zhuǎn)換后提交事務(wù)。

# service.py
from database import async_session, Order, order_machine
from sqlalchemy import select

async def create_new_order(title: str) -> int:
    """創(chuàng)建新訂單,初始狀態(tài)為 'created'"""
    async with async_session() as session:
        async with session.begin():
            new_order = Order(title=title)
            session.add(new_order)
        # commit 在 begin() 塊結(jié)束時自動發(fā)生
        return new_order.id

async def process_order_payment(order_id: int):
    """處理訂單支付:狀態(tài)從 'created' -> 'paid'"""
    async with async_session() as session:
        async with session.begin():
            # 1. 從 PostgreSQL 查詢訂單
            result = await session.execute(select(Order).where(Order.id == order_id))
            order = result.scalar_one_or_none()
            
            if not order:
                print("訂單不存在")
                return

            # 2. 將此訂單實例注冊到全局狀態(tài)機中
            # transitions 內(nèi)部使用弱引用(weakref)管理 model,不會造成內(nèi)存泄漏
            order_machine.add_model(order)

            # 3. 觸發(fā)轉(zhuǎn)換 (會自動修改 order.status 屬性)
            print(f"當(dāng)前數(shù)據(jù)庫狀態(tài): {order.status}")  # created
            success = order.pay()  # 觸發(fā) 'pay'
            
            if success:
                print(f"內(nèi)存狀態(tài)已變更為: {order.status}")  # paid
                # 4. 離開 begin() 塊時,SQLAlchemy 會自動發(fā)出 UPDATE 語句持久化到 PostgreSQL
            else:
                print("狀態(tài)轉(zhuǎn)換失敗,不滿足轉(zhuǎn)換條件")

            # 5. 轉(zhuǎn)換結(jié)束,從狀態(tài)機中注銷 model (可選,弱引用會自動回收,但手動移除更干凈)
            order_machine.remove_model(order)

?? 4. 進(jìn)階:在生命周期回調(diào)中讀寫數(shù)據(jù)庫

如果需要在狀態(tài)轉(zhuǎn)換的 beforeafter 回調(diào)中執(zhí)行數(shù)據(jù)庫操作(例如:記錄狀態(tài)變更日志表 OrderLog),可以結(jié)合異步狀態(tài)機 AsyncMachine。

from transitions.extensions.asyncio import AsyncMachine
from sqlalchemy.ext.asyncio import AsyncSession

# 1. 聲明包含 DB 回調(diào)邏輯的 Model 基類或 Mixin
class OrderWithCallback(Order):
    # 此方法將作為 transitions 的 before/after 回調(diào)運行
    async def log_status_change(self, event_data):
        # 從觸發(fā)參數(shù)中獲取當(dāng)前的 db session
        session: AsyncSession = event_data.kwargs.get("session")
        if session:
            print(f"正在向日志表寫入:訂單 {self.id} 狀態(tài)從 {event_data.transition.source} 變更為 {event_data.transition.dest}")
            # 執(zhí)行額外的 DB 插入操作,例如: session.add(OrderLog(...))

# 2. 使用 AsyncMachine
async_order_machine = AsyncMachine(
    model=None, 
    states=states, 
    initial="created", 
    model_attribute="status"
)

async_order_machine.add_transition(
    trigger="pay", 
    source="created", 
    dest="paid",
    after="log_status_change"  # 綁定回調(diào)
)

# 3. 業(yè)務(wù)調(diào)用
async def pay_with_callback(order_id: int):
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(select(OrderWithCallback).where(OrderWithCallback.id == order_id))
            order = result.scalar_one()
            
            async_order_machine.add_model(order)
            # 傳入 session 供回調(diào)函數(shù)使用
            await order.pay(session=session) 

?? 最佳實踐總結(jié)

  1. 單例狀態(tài)機:不要在每次請求時重新實例化 Machine,應(yīng)保持 Machine 全局唯一,通過 add_model / remove_model 動態(tài)綁定查詢出來的 DB 實體。
  2. model_attribute:必須設(shè)置該參數(shù),將其指向 ORM 托管的字段(如 status 或 state)。
  3. 事務(wù)一致性:狀態(tài)機的轉(zhuǎn)移僅修改了內(nèi)存中實體的屬性,必須確保在同一數(shù)據(jù)庫事務(wù)(session.commit())中完成提交,以保證數(shù)據(jù)持久化的一致性。

到此這篇關(guān)于Python開發(fā)中transitions的使用小結(jié)的文章就介紹到這了,更多相關(guān)Python transitions使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python利用 utf-8-sig 編碼格式解決寫入 csv 文件亂碼問題

    Python利用 utf-8-sig 編碼格式解決寫入 csv 文件亂碼問題

    這篇文章主要介紹了Python利用 utf-8-sig 編碼格式解決寫入 csv 文件亂碼問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-02-02
  • python反轉(zhuǎn)單鏈表算法題

    python反轉(zhuǎn)單鏈表算法題

    這篇文章主要為大家詳細(xì)介紹了python反轉(zhuǎn)單鏈表算法題,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 淺談一下python線程池簡單應(yīng)用

    淺談一下python線程池簡單應(yīng)用

    這篇文章主要介紹了淺談一下python線程池簡單應(yīng)用,線程池在系統(tǒng)啟動時即創(chuàng)建大量空閑的線程,程序只要將一個函數(shù)提交給線程池,線程池就會啟動一個空閑的線程來執(zhí)行它,需要的朋友可以參考下
    2023-04-04
  • Python實現(xiàn)時鐘顯示效果思路詳解

    Python實現(xiàn)時鐘顯示效果思路詳解

    這篇文章主要介紹了Python實現(xiàn)時鐘顯示,需要的朋友可以參考下
    2018-04-04
  • python3實現(xiàn)倒計時效果

    python3實現(xiàn)倒計時效果

    這篇文章主要為大家詳細(xì)介紹了python3實現(xiàn)倒計時效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Python中Selenium上傳文件的幾種方式

    Python中Selenium上傳文件的幾種方式

    本文主要介紹了Python中Selenium上傳文件的幾種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • sublime3之內(nèi)網(wǎng)安裝python插件Anaconda的流程

    sublime3之內(nèi)網(wǎng)安裝python插件Anaconda的流程

    這篇文章主要介紹了sublime3之內(nèi)網(wǎng)安裝python插件Anaconda的流程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • vscode和Anaconda安裝以及相關(guān)環(huán)境配置指南

    vscode和Anaconda安裝以及相關(guān)環(huán)境配置指南

    Anaconda是一個開源的python發(fā)行版本,是現(xiàn)在比較流行的python數(shù)據(jù)科學(xué)平臺,可以對python的科學(xué)包做到有效管理,這篇文章主要給大家介紹了關(guān)于vscode和Anaconda安裝以及相關(guān)環(huán)境配置指南的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • pyspark自定義UDAF函數(shù)調(diào)用報錯問題解決

    pyspark自定義UDAF函數(shù)調(diào)用報錯問題解決

    這篇文章主要為大家介紹了pyspark自定義UDAF函數(shù)調(diào)用報錯問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • python中os模塊詳解

    python中os模塊詳解

    os模塊提供了多數(shù)操作系統(tǒng)的功能接口函數(shù).當(dāng)os模塊被導(dǎo)入后,它會自適應(yīng)于不同的操作系統(tǒng)平臺,如posix或NT系統(tǒng)平臺,os模塊會根據(jù)不同的平臺進(jìn)行相應(yīng)的操作.本節(jié)內(nèi)容將對os模塊提供的函數(shù)進(jìn)行詳細(xì)的解讀.
    2016-10-10

最新評論

布尔津县| 常宁市| 卫辉市| 全椒县| 金寨县| 缙云县| 伊通| 香格里拉县| 鄢陵县| 临汾市| 钟祥市| 焉耆| 康马县| 乳源| 鲁山县| 平凉市| 太湖县| 灵宝市| 泽普县| 延寿县| 土默特右旗| 公安县| 浦东新区| 瑞丽市| 宜君县| 清远市| 奉新县| 金华市| 宾阳县| 漳浦县| 澳门| 宿迁市| 五大连池市| 武威市| 洞口县| 荃湾区| 郴州市| 密山市| 建阳市| 徐州市| 张家港市|