[英]Possible to run async function using exec?
我正在嘗試從 exec 調用異步 function,我希望它可以像這樣工作:
def test():
print("test")
exec('def test2():\n print("test")\ntest2()')
test()
Output:
test
test
因此,在 exec 中定義的 function 能夠調用自身,但是我們不能在 asyncio 中執行以下操作:
async def test():
print("test")
exec('async def test2():\n print("test")\nawait test2()')
我們不能在 function 之外使用 await ,也不能從正在運行的循環中調用另一個循環:
async def test():
print("test")
exec('async def test2():\n print("test")\nasyncio.run(test2())')
這個問題有什么解決辦法嗎?
不可能。 您將需要某種能夠暫停其自身執行的“異步exec
”,並且 Python 的語法需要支持異步 function 定義之外的await
。 沒有它,當需要暫停時, exec
就無法將控制權返回給事件循環。
Andrej Kesely 的回答不起作用。 它實際上並不運行協程。 它只安排協程稍后運行。
您可以將當前運行循環作為exec()
全局參數:
import asyncio
async def test():
print("test")
loop = asyncio.get_running_loop()
exec('async def test2():\n print("test2")\nloop.create_task(test2())', {'loop': loop})
asyncio.run(test())
印刷:
test
test2
編輯:要異步運行,您可以從exec()
返回 awaitable :
import asyncio
async def some_other_task():
await asyncio.sleep(1)
print('some_other_task')
async def test():
loop = asyncio.get_running_loop()
t = [None]
exec('async def test2():\n await asyncio.sleep(3);print("task in exec finished")\nt[0] = loop.create_task(test2())', {'asyncio': asyncio, 'loop': loop, 't': t})
await asyncio.gather(some_other_task(), t[0])
asyncio.run(test())
印刷:
some_other_task # <-- after 1 sec
task in exec finished # <-- after 3 sec
我需要一個項目這樣的東西,並編寫了一個異步版本的code.InteractiveConsole 。 我還想捕捉output,所以使用了twisted.conch.Manhole的一個想法
這是一個可怕的黑客。 它僅適用於以“await”開頭的異步代碼行。 我還沒有弄清楚如何處理表單x = await func()
。
import asyncio
def handle(output):
print(f"** {output}", end="")
async def nested():
return 42
async def main():
localz = {"nested": nested}
cons = AsyncConsole(handle, localz)
await cons.interact("a = 10")
await cons.interact("b = 20")
await cons.interact("def fun(a, b):")
await cons.interact(" return a + b")
await cons.interact("")
await cons.interact("fun(a, b)")
await cons.interact("await nested()")
del localz['__builtins__']
print(f"l: {localz}")
asyncio.run(main())
Output:
** >>> a = 10
** >>> b = 20
** >>> def fun(a, b):
** ... return a + b
** ...
** >>> fun(a, b)
30
** >>> await nested()
42
l: {'nested': <function nested at 0x100ab0820>, 'a': 10, 'b': 20, 'fun': <function fun at 0x101059480>, '_': 42}
異步控制台:
import string
import code
import sys
import io
class AsyncConsole(code.InteractiveConsole):
def __init__(self, handler, locals: dict = None, filename="<console>"):
super().__init__(locals, filename)
self.handler = handler
self.filename = filename
self.output = io.StringIO()
self.prompt1 = ">>> "
self.prompt2 = "... "
self.prompt = self.prompt1
self.is_async = False
async def runcode(self, code):
orighook, sys.displayhook = sys.displayhook, self.displayhook
try:
origout, sys.stdout = sys.stdout, self.output
try:
exec(code, self.locals)
if self.is_async:
coro = self.locals["_"]
obj = await coro
self.locals["_"] = obj
if obj is not None:
self.write(repr(obj))
except SystemExit:
raise
except Exception:
self.showtraceback()
finally:
sys.stdout = origout
finally:
sys.displayhook = orighook
def displayhook(self, obj):
self.locals["_"] = obj
if obj is not None and not self.is_async:
self.write(repr(obj))
def write(self, data):
self.output.write(data)
async def runsource(self, source, filename="<input>", symbol="single"):
try:
code = self.compile(source, filename, symbol)
except (OverflowError, SyntaxError, ValueError):
# Case 1
self.showsyntaxerror(filename)
return False
if code is None:
# Case 2
return True
# Case 3
await self.runcode(code)
return False
async def push(self, line):
self.buffer.append(line)
source = "\n".join(self.buffer)
more = await self.runsource(source, self.filename)
if not more:
self.resetbuffer()
return more
async def interact(self, line):
self.is_async = line.startswith("await ")
self.output = io.StringIO()
self.output.write(f"{self.prompt}{line}\n")
if self.is_async:
line = line[6:]
r = await self.push(line)
self.prompt = self.prompt2 if r else self.prompt1
if not r and "_" in self.locals and self.locals["_"]:
self.output.write("\n")
self.handler(self.output.getvalue())
return self.prompt
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.