Python之Await 協(xié)議的實(shí)現(xiàn)
一、先澄清:await 到底在干什么
很多初學(xué)者會(huì)把 await 理解成“阻塞到結(jié)果返回”。這個(gè)理解不準(zhǔn)確。
在同步代碼里,函數(shù)調(diào)用通常意味著當(dāng)前線程一路執(zhí)行到底,中間不能主動(dòng)把控制權(quán)讓給別的任務(wù);而在異步代碼里,await 的含義更接近:
- 當(dāng)前協(xié)程運(yùn)行到這里,先暫停自己。
- 把“我依賴的那個(gè)異步對(duì)象”交給事件循環(huán)。
- 事件循環(huán)去執(zhí)行別的任務(wù)。
- 等這個(gè)對(duì)象完成后,再回來恢復(fù)當(dāng)前協(xié)程。
- 恢復(fù)點(diǎn)就在 await 之后。
所以,await 的核心不是“等待”,而是“協(xié)作式讓出執(zhí)行權(quán)”。
看一個(gè)最基本的例子:
import asyncio
async def fetch_data():
print("開始請(qǐng)求")
await asyncio.sleep(1)
print("請(qǐng)求結(jié)束")
return {"name": "alice"}
async def main():
result = await fetch_data()
print(result)
asyncio.run(main())
這里真正發(fā)生的事情是:
- 調(diào)用 fetch_data() 時(shí),不會(huì)立刻把整個(gè)函數(shù)跑完,而是先得到一個(gè)協(xié)程對(duì)象。
- main 中的 await fetch_data() 會(huì)驅(qū)動(dòng)這個(gè)協(xié)程對(duì)象執(zhí)行。
- 當(dāng) fetch_data 內(nèi)部又遇到 await asyncio.sleep(1) 時(shí),fetch_data 自己也會(huì)掛起。
- 事件循環(huán)此時(shí)可以去做別的事情。
- 1 秒后,sleep 對(duì)應(yīng)的等待對(duì)象完成,fetch_data 恢復(fù)執(zhí)行,最終把結(jié)果返回給 main。
所以,await 是“掛起與恢復(fù)”的語言級(jí)入口。
二、await 右邊到底能放什么
不是所有對(duì)象都能被 await。Python 只接受“awaitable object”,即可等待對(duì)象。
可等待對(duì)象主要分三類:
- 原生協(xié)程對(duì)象
- Future / Task 一類的對(duì)象
- 實(shí)現(xiàn)了 await 方法的自定義對(duì)象
先看第一類。
1. 原生協(xié)程對(duì)象
由 async def 定義的函數(shù),調(diào)用之后返回的是協(xié)程對(duì)象。
async def work():
return 42
obj = work()
print(type(obj))
這里的 obj 就是協(xié)程對(duì)象,它可以被 await。
注意:協(xié)程函數(shù)和協(xié)程對(duì)象不是一個(gè)東西。
- async def work: 協(xié)程函數(shù)
- work(): 協(xié)程對(duì)象
這和普通函數(shù)與函數(shù)調(diào)用結(jié)果的區(qū)別類似,只不過協(xié)程對(duì)象不是結(jié)果值,而是“尚未執(zhí)行完成的異步計(jì)算描述”。
2. Task 和 Future
在 asyncio 體系里,F(xiàn)uture 表示“未來某個(gè)時(shí)刻會(huì)產(chǎn)生結(jié)果”;Task 是“被事件循環(huán)調(diào)度執(zhí)行的協(xié)程”。
import asyncio
async def worker():
await asyncio.sleep(1)
return "done"
async def main():
task = asyncio.create_task(worker())
result = await task
print(result)
asyncio.run(main())
這里 task 不是協(xié)程函數(shù),也不是普通值,而是一個(gè) Task 對(duì)象。它之所以能出現(xiàn)在 await 右邊,是因?yàn)樗旧硎?awaitable。
3. 實(shí)現(xiàn)了await的對(duì)象
這是 await 協(xié)議真正的核心。只要對(duì)象實(shí)現(xiàn)了 await,并且實(shí)現(xiàn)方式符合規(guī)范,它就可以被 await。
import asyncio
class Delay:
def __init__(self, seconds, value):
self.seconds = seconds
self.value = value
def __await__(self):
return asyncio.sleep(self.seconds, result=self.value).__await__()
async def main():
result = await Delay(1, "hello")
print(result)
asyncio.run(main())
這里 Delay 不是協(xié)程對(duì)象,也不是 Task,但因?yàn)樗鼘?shí)現(xiàn)了 await,所以仍然可以被 await。
三、await 協(xié)議的正式定義是什么
嚴(yán)格地說,await 協(xié)議的核心要求是:
一個(gè)對(duì)象若想被 await,那么它必須是以下之一:
- 原生協(xié)程對(duì)象
- 生成器型協(xié)程對(duì)象
- 實(shí)現(xiàn)了 await 方法,并且該方法返回一個(gè)迭代器的對(duì)象
第三點(diǎn)尤其重要。很多人只記住“實(shí)現(xiàn) await 就行”,這是不完整的。真正的要求是:
await 必須返回一個(gè)迭代器,而不是任意對(duì)象。
例如下面這個(gè)寫法是錯(cuò)誤的:
class BadAwaitable:
def __await__(self):
return 123
因?yàn)?123 不是迭代器,所以 await BadAwaitable() 會(huì)報(bào)錯(cuò)。
正確的方式必須返回一個(gè)可迭代推進(jìn)的對(duì)象,最常見做法是直接復(fù)用另一個(gè) awaitable 的 await 結(jié)果:
import asyncio
class GoodAwaitable:
def __await__(self):
return asyncio.sleep(1, result="ok").__await__()
這背后的原因是:解釋器在執(zhí)行 await 時(shí),需要一個(gè)“可逐步推進(jìn)”的對(duì)象來承載掛起點(diǎn)和恢復(fù)點(diǎn),而這個(gè)載體就是迭代器。
四、為什么 await 要返回迭代器
這要追溯到 Python 異步模型的底層實(shí)現(xiàn)思路。
從語義上說,協(xié)程的掛起與恢復(fù),和生成器有非常強(qiáng)的親緣關(guān)系。生成器依靠 yield 暫停,下一次 next 或 send 時(shí)恢復(fù);協(xié)程雖然語法層面寫成了 async / await,但底層仍然沿用了“迭代推進(jìn)狀態(tài)機(jī)”的思想。
因此,await 并不是魔法??梢园阉斫獬梢环N受限、專用、語義更清晰的協(xié)程委托機(jī)制。其底層邏輯與生成器時(shí)代的 yield from 有很深的繼承關(guān)系。
概念上可以把:
result = await obj
近似理解為:
“取出 obj 對(duì)應(yīng)的 await 迭代器,把當(dāng)前協(xié)程的控制流委托給它,直到它結(jié)束,再拿到最終結(jié)果。”
當(dāng)然,這只是幫助理解的近似模型,不是源碼級(jí)等價(jià)翻譯,但非常接近真實(shí)語義。
五、一個(gè)自定義 awaitable 應(yīng)該怎樣寫
最穩(wěn)妥的工程做法通常不是自己手搓底層狀態(tài)機(jī),而是把已有的 awaitable 組合進(jìn)去。
例如我們封裝一個(gè)“延遲后返回結(jié)果”的對(duì)象:
import asyncio
class SleepThen:
def __init__(self, delay, value):
self.delay = delay
self.value = value
def __await__(self):
async def _inner():
await asyncio.sleep(self.delay)
return self.value
return _inner().__await__()
async def main():
value = await SleepThen(0.5, {"status": "ok"})
print(value)
asyncio.run(main())
這個(gè)實(shí)現(xiàn)有兩個(gè)優(yōu)點(diǎn):
- 語義清晰
- 不需要直接手動(dòng)操縱生成器協(xié)議細(xì)節(jié)
如果你硬要自己寫得更底層,也可以,例如:
import asyncio
class SleepThenLowLevel:
def __init__(self, delay, value):
self.delay = delay
self.value = value
def __await__(self):
yield from asyncio.sleep(self.delay).__await__()
return self.value
async def main():
value = await SleepThenLowLevel(0.5, "done")
print(value)
asyncio.run(main())
這里已經(jīng)非常接近協(xié)議本體了:
- yield from 把控制權(quán)委托給另一個(gè)等待對(duì)象
- 等它完成以后,返回最終值
這個(gè)寫法能更直觀地展示:await 協(xié)議本質(zhì)上是“以迭代器為載體的掛起協(xié)議”。
六、await 的結(jié)果值是怎么回來的
這一點(diǎn)必須講清,因?yàn)樗馨?ldquo;掛起”和“返回值”統(tǒng)一起來。
當(dāng)你寫:
result = await some_obj
你得到的 result,并不是 some_obj 本身,而是“這個(gè) awaitable 完成后產(chǎn)出的最終值”。
例如:
import asyncio
async def compute():
await asyncio.sleep(0.2)
return 100
async def main():
x = await compute()
print(x)
asyncio.run(main())
輸出是 100。
從底層協(xié)議視角看,這個(gè)“最終值”在迭代器語義里通常體現(xiàn)為終止時(shí)攜帶的值。對(duì)生成器模型熟悉的人會(huì)知道,生成器結(jié)束時(shí)可以通過 StopIteration.value 把值帶出來。Python 的協(xié)程模型沿用了這一思路,只是語言層已經(jīng)把細(xì)節(jié)包裝掉了。
所以,await 做的不是“讀取某個(gè)對(duì)象的字段”,而是“驅(qū)動(dòng)某個(gè)異步狀態(tài)機(jī)直到完成,并提取它的完成值”。
七、事件循環(huán)在 await 協(xié)議里扮演什么角色
await 協(xié)議本身只規(guī)定“對(duì)象如何可等待”,并不直接等于“調(diào)度機(jī)制”。真正負(fù)責(zé)調(diào)度的是事件循環(huán)。
這點(diǎn)很關(guān)鍵。因?yàn)楹芏嗳藭?huì)把 await 和 asyncio 混為一談,實(shí)際上兩者分工不同:
- await 是語言機(jī)制,定義了可等待語義
- asyncio 是標(biāo)準(zhǔn)庫中的事件循環(huán)與調(diào)度實(shí)現(xiàn)之一
看一個(gè)更接近底層的例子:
import asyncio
async def wait_on_future():
loop = asyncio.get_running_loop()
future = loop.create_future()
def complete():
print("設(shè)置 Future 結(jié)果")
future.set_result("future done")
loop.call_later(1, complete)
print("開始等待")
result = await future
print("拿到結(jié)果:", result)
asyncio.run(wait_on_future())
這里的關(guān)鍵流程是:
- 創(chuàng)建一個(gè) Future
- 當(dāng)前協(xié)程 await 這個(gè) Future
- 協(xié)程掛起
- 事件循環(huán)繼續(xù)運(yùn)行別的回調(diào)
- 1 秒后 complete 被調(diào)用,F(xiàn)uture 被標(biāo)記完成
- 事件循環(huán)恢復(fù)先前掛起的協(xié)程
- await 表達(dá)式返回 “future done”
由此可以看出:
await 協(xié)議告訴解釋器“這個(gè)對(duì)象可以掛起我”,而事件循環(huán)負(fù)責(zé)“什么時(shí)候恢復(fù)你”。
八、Task 為什么能被 await
Task 很值得單獨(dú)講,因?yàn)樗皿w現(xiàn)了“協(xié)議”和“調(diào)度”的結(jié)合。
import asyncio
async def worker():
await asyncio.sleep(1)
return "worker result"
async def main():
task = asyncio.create_task(worker())
print("task 已創(chuàng)建")
result = await task
print(result)
asyncio.run(main())
這里 worker() 先產(chǎn)生協(xié)程對(duì)象,create_task 再把它包裝成 Task。Task 由事件循環(huán)推進(jìn)執(zhí)行,因此:
- Task 是協(xié)程運(yùn)行的調(diào)度單元
- Task 也是 awaitable
- await task 的含義不是“把 task 當(dāng)函數(shù)調(diào)”,而是“等待 task 對(duì)應(yīng)的執(zhí)行單元結(jié)束,并取出它的結(jié)果”
所以 Task 是異步執(zhí)行的“運(yùn)行態(tài)對(duì)象”,協(xié)程對(duì)象更像“待運(yùn)行描述”。
九、await 與 inspect.isawaitable 的關(guān)系
工程里經(jīng)常要判斷一個(gè)對(duì)象能不能 await,這時(shí)不能只看它是不是協(xié)程對(duì)象。
錯(cuò)誤寫法:
import inspect
def only_coroutine(obj):
return inspect.iscoroutine(obj)
這會(huì)漏掉很多合法 awaitable,比如 Task、Future、自定義實(shí)現(xiàn)了 await 的對(duì)象。
更合理的方式是:
import inspect
import asyncio
class Custom:
def __await__(self):
return asyncio.sleep(0).__await__()
async def demo():
coro = asyncio.sleep(0)
task = asyncio.create_task(asyncio.sleep(0))
custom = Custom()
print(inspect.isawaitable(coro)) # True
print(inspect.isawaitable(task)) # True
print(inspect.isawaitable(custom)) # True
await coro
await task
await custom
asyncio.run(demo())
因此,在動(dòng)態(tài)調(diào)度、依賴注入、框架執(zhí)行器里,通常應(yīng)當(dāng)優(yōu)先使用 inspect.isawaitable,而不是只檢查 inspect.iscoroutine。
十、await 只能出現(xiàn)在什么位置
這是語法層面的硬約束。
在現(xiàn)代 Python 中,await 只能出現(xiàn)在 async def 定義的函數(shù)體內(nèi)。也就是說,await 本身不是一個(gè)可以到處隨便寫的表達(dá)式,它只能存在于“異步上下文”中。
例如下面是非法的:
import asyncio await asyncio.sleep(1)
在普通 Python 腳本頂層這會(huì)報(bào)語法錯(cuò)誤。正確寫法通常是:
import asyncio
async def main():
await asyncio.sleep(1)
asyncio.run(main())
不過在某些交互環(huán)境里,比如部分 notebook 或 REPL,會(huì)支持頂層 await,這是宿主環(huán)境額外提供的能力,不是普通腳本的默認(rèn)行為。
十一、await 和普通函數(shù)調(diào)用的根本差別
看這段代碼:
def sync_add(a, b):
return a + b
async def async_add(a, b):
return a + b
調(diào)用它們:
x = sync_add(1, 2) y = async_add(1, 2) print(x) # 3 print(y) # 協(xié)程對(duì)象,不是 3
這說明:
- 普通函數(shù)調(diào)用后直接得到結(jié)果
- 協(xié)程函數(shù)調(diào)用后得到的是“未來可產(chǎn)出結(jié)果的對(duì)象”
必須再經(jīng)過 await,才能得到最終值:
import asyncio
async def async_add(a, b):
return a + b
async def main():
y = await async_add(1, 2)
print(y) # 3
asyncio.run(main())
所以,await 不是“異步函數(shù)調(diào)用語法糖”,而是“異步結(jié)果兌現(xiàn)機(jī)制”。
十二、異常如何穿過 await 傳播
await 不只是傳值,也會(huì)傳異常。
import asyncio
async def bad():
await asyncio.sleep(0.1)
raise ValueError("boom")
async def main():
try:
await bad()
except ValueError as exc:
print("捕獲到異常:", exc)
asyncio.run(main())
這里 bad 內(nèi)部拋出的異常,會(huì)在 await bad() 處重新表現(xiàn)出來。
這說明 await 的語義和普通函數(shù)調(diào)用很像的一點(diǎn)在于:
- 正常完成時(shí),返回值向上傳播
- 出錯(cuò)時(shí),異常向上傳播
只是它們之間多了一層“掛起與恢復(fù)”。
十三、取消是 await 協(xié)議在調(diào)度層的重要延伸
在 asyncio 中,任務(wù)可以被取消,這通常通過 CancelledError 體現(xiàn)。
import asyncio
async def worker():
try:
print("開始工作")
await asyncio.sleep(10)
except asyncio.CancelledError:
print("收到取消請(qǐng)求")
raise
async def main():
task = asyncio.create_task(worker())
await asyncio.sleep(0.2)
task.cancel()
try:
await task
except asyncio.CancelledError:
print("task 已取消")
asyncio.run(main())
這里的重點(diǎn)不是“取消 API 怎么用”,而是理解其與 await 的關(guān)系:
- 當(dāng)前協(xié)程 await 某個(gè) Task
- 如果該 Task 被取消,那么 await 表達(dá)式不會(huì)正常產(chǎn)出結(jié)果
- 它會(huì)把取消異常傳播出來
這說明 await 協(xié)議并不只承載“最終成功值”,也承載“失敗與取消”的控制流。
十四、await 與 yield from 的關(guān)系
如果想真正理解 await 協(xié)議,必須知道它和 yield from 的歷史關(guān)系。
在 async / await 語法出現(xiàn)前,Python 曾使用“基于生成器的協(xié)程”。當(dāng)時(shí)異步協(xié)作常通過 yield from 來表達(dá)。
現(xiàn)代 Python 里,await 可以理解為對(duì)異步委托的專門化語法,它比 yield from 更嚴(yán)格、更清晰,原因包括:
- await 只能作用于 awaitable,而不是任意可迭代對(duì)象
- async def 明確標(biāo)記了協(xié)程函數(shù),避免與普通生成器混淆
- 語義上更聚焦于異步等待,而不是一般性的迭代委托
所以,await 不是憑空創(chuàng)造的新機(jī)制,而是在生成器語義基礎(chǔ)上為異步編程建立的專用協(xié)議層。
十五、一個(gè)更接近“協(xié)議本體”的最小示例
下面這個(gè)例子能幫助你從“語言糖”退回到“協(xié)議視角”。
import asyncio
class OneShotValue:
def __init__(self, value):
self.value = value
def __await__(self):
if False:
yield
return self.value
async def main():
result = await OneShotValue(123)
print(result)
asyncio.run(main())
這個(gè)例子看起來有些奇怪,尤其是:
if False:
yield
它的作用是讓這個(gè)函數(shù)在語法上成為生成器,從而返回一個(gè)迭代器對(duì)象。雖然不會(huì)真的 yield 出什么,但協(xié)議上它已經(jīng)滿足“返回迭代器”的要求了,因此 await 能工作。
這個(gè)例子很好地說明了一件事:
await 關(guān)心的不是“這個(gè)對(duì)象是不是某個(gè)具體類”,而是“它能否通過迭代器協(xié)議表達(dá)掛起/完成語義”。
不過,這種寫法更適合教學(xué),不適合生產(chǎn)環(huán)境。工程里一般應(yīng)當(dāng)復(fù)用已有 awaitable,而不是手寫這種技巧性實(shí)現(xiàn)。
十六、什么不屬于 await 協(xié)議
有幾個(gè)概念很容易混淆,必須分開。
1. 異步迭代不是 await 協(xié)議本身
異步迭代使用的是:
- aiter
- anext
對(duì)應(yīng)語法是 async for,而不是 await。
2. 異步上下文管理不是 await 協(xié)議本身
異步上下文管理使用的是:
- aenter
- aexit
對(duì)應(yīng)語法是 async with,而不是 await。
3. 普通可迭代對(duì)象不等于 awaitable
一個(gè)對(duì)象能被 for 遍歷,不代表它能被 await。await 要求的是 awaitable 協(xié)議,不是 iterable 協(xié)議。
例如列表、普通生成器都不能直接 await。
十七、工程上最常見的幾個(gè)誤區(qū)
1. 誤以為調(diào)用 async def 就已經(jīng)執(zhí)行了
錯(cuò)誤理解:
“我調(diào)用了異步函數(shù),所以它開始運(yùn)行了。”
實(shí)際上,單純調(diào)用 async def 函數(shù)只會(huì)得到協(xié)程對(duì)象,不保證執(zhí)行。執(zhí)行通常要通過以下方式之一觸發(fā):
- 被 await
- 被 create_task 包裝
- 被 asyncio.run 作為入口運(yùn)行
2. 誤以為 await 會(huì)阻塞整個(gè)線程
不準(zhǔn)確。await 會(huì)掛起當(dāng)前協(xié)程,但只要底層等待對(duì)象是非阻塞式的,事件循環(huán)仍然可以在同一線程調(diào)度其他任務(wù)。
3. 在自定義await里返回了錯(cuò)誤類型
最典型錯(cuò)誤就是返回普通值、列表、協(xié)程函數(shù)本身,而不是迭代器。
4. 把“能調(diào)用”誤認(rèn)為“能 await”
可調(diào)用對(duì)象和可等待對(duì)象是兩個(gè)不同維度。
- 函數(shù)對(duì)象未必能 await
- awaitable 未必可調(diào)用
十八、如何從框架角度理解 await 協(xié)議
如果你站在框架作者的角度看,await 協(xié)議的價(jià)值非常大,因?yàn)樗峁┝艘粚咏y(tǒng)一抽象:
不管右邊是:
- 原生協(xié)程
- Task
- Future
- 自定義 awaitable
只要符合協(xié)議,調(diào)用方都可以統(tǒng)一寫成:
result = await obj
這意味著上層業(yè)務(wù)邏輯不需要關(guān)心底層異步對(duì)象的具體類型,只需要關(guān)心它是否滿足 awaitable 語義。
這也是為什么“協(xié)議”比“類繼承”更重要。Python 在這里采用的是典型的鴨子類型哲學(xué):
你不必繼承某個(gè)統(tǒng)一基類,只要行為符合協(xié)議即可。
十九、一個(gè)完整示例:自定義 awaitable、Task、異常傳播放在一起
import asyncio
import inspect
class ResourceLoader:
def __init__(self, name, delay):
self.name = name
self.delay = delay
def __await__(self):
async def _load():
await asyncio.sleep(self.delay)
if self.name == "bad":
raise RuntimeError("resource load failed")
return {"resource": self.name}
return _load().__await__()
async def consume(obj):
if not inspect.isawaitable(obj):
raise TypeError("對(duì)象不可等待")
return await obj
async def main():
task = asyncio.create_task(consume(ResourceLoader("user", 0.5)))
result = await task
print(result)
try:
await consume(ResourceLoader("bad", 0.1))
except RuntimeError as exc:
print("異常傳播成功:", exc)
asyncio.run(main())
這段代碼展示了四件事:
- 自定義對(duì)象可以通過 await 變成 awaitable
- inspect.isawaitable 可以做統(tǒng)一判定
- Task 可以包裝異步工作并被 await
- 異常會(huì)從底層 awaitable 傳播到外層 await 表達(dá)式
二十、可以把 await 協(xié)議總結(jié)成什么
可以把整個(gè) await 協(xié)議總結(jié)為下面四條:
- await 作用的對(duì)象必須是 awaitable。
- 自定義 awaitable 的關(guān)鍵是實(shí)現(xiàn) await。
- await 的返回值必須是迭代器,而不是任意對(duì)象。
- await 的執(zhí)行語義是:掛起當(dāng)前協(xié)程,等待目標(biāo)對(duì)象完成,然后返回結(jié)果或拋出異常。
如果再進(jìn)一步壓縮成一句更偏底層的話:
await 協(xié)議就是“用迭代器描述異步掛起點(diǎn),并由事件循環(huán)負(fù)責(zé)恢復(fù)執(zhí)行”的一套語言約定。
二十一、學(xué)習(xí)這部分時(shí)最值得建立的心智模型
建議你把 Python 異步系統(tǒng)拆成三層看:
語法層
async def、await、async for、async with協(xié)議層
await、aiter、anext、aenter、aexit調(diào)度層
asyncio event loop、Future、Task、回調(diào)恢復(fù)
其中,await 協(xié)議位于“語法層”和“調(diào)度層”之間。它既不是純語法糖,也不是完整調(diào)度器;它是把“可掛起對(duì)象”接入異步執(zhí)行體系的橋。
這一層真正理解了,很多問題都會(huì)自然變得清楚:
- 為什么協(xié)程函數(shù)調(diào)用后不是結(jié)果值
- 為什么 Task 能被 await
- 為什么自定義對(duì)象實(shí)現(xiàn) await 就能接入系統(tǒng)
- 為什么 await 的本質(zhì)是掛起與恢復(fù),而不是線程阻塞
到此這篇關(guān)于Python之Await 協(xié)議的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Python Await 協(xié)議內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
pyenv安裝Python出現(xiàn)clang版本沖突的優(yōu)雅解決方法
最近在用 pyenv 安裝 Python 3.13 時(shí),突然遇到經(jīng)典報(bào)錯(cuò): configure: error: C compiler cannot create executables,下面我們就來排查一下錯(cuò)誤原因并解決吧2026-03-03
聊聊Pytorch torch.cat與torch.stack的區(qū)別
這篇文章主要介紹了Pytorch torch.cat與torch.stack的區(qū)別說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05
靈活運(yùn)用Python 枚舉類來實(shí)現(xiàn)設(shè)計(jì)狀態(tài)碼信息
在python中枚舉是一種類(Enum,IntEnum),存放在enum模塊中。枚舉類型可以給一組標(biāo)簽賦予一組特定的值,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
用python實(shí)現(xiàn)英文字母和相應(yīng)序數(shù)轉(zhuǎn)換的方法
這篇文章主要介紹了用python實(shí)現(xiàn)英文字母和相應(yīng)序數(shù)轉(zhuǎn)換的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
對(duì)Python實(shí)現(xiàn)簡(jiǎn)單的API接口實(shí)例講解
今天小編就為大家分享一篇對(duì)Python實(shí)現(xiàn)簡(jiǎn)單的API接口實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-12-12
使用python操作lmdb對(duì)數(shù)據(jù)讀取的實(shí)例
這篇文章主要介紹了使用python操作lmdb對(duì)數(shù)據(jù)讀取的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12

