【问题标题】:How to call a async function contained in a class?如何调用类中包含的异步函数?
【发布时间】:2017-02-02 17:59:14
【问题描述】:

基于this answer,我想在一个类中构建一个异步 websoket 客户端,该类将从另一个文件导入:

#!/usr/bin/env python3

import sys, json
import asyncio
from websockets import connect

class EchoWebsocket:
    def __await__(self):
        # see: https://stackoverflow.com/a/33420721/1113207
        return self._async_init().__await__()

    async def _async_init(self):
        self._conn = connect('wss://ws.binaryws.com/websockets/v3')
        self.websocket = await self._conn.__aenter__()
        return self

    async def close(self):
        await self._conn.__aexit__(*sys.exc_info())

    async def send(self, message):
        await self.websocket.send(message)

    async def receive(self):
        return await self.websocket.recv()

class mtest:
    async def start(self):
        try:
            self.wws = await EchoWebsocket()
        finally:
            await self.wws.close()

    async def get_ticks(self):
        await self.wws.send(json.dumps({'ticks_history': 'R_50', 'end': 'latest', 'count': 1}))
        return await self.wws.receive()

if __name__ == '__main__':
    a = mtest()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(a.start())

我将它导入main.py,其中有以下内容:

from testws import *

a = mtest()
print (a.get_ticks())
print ("this will be printed after the ticks")

但它检索到以下错误:

root@ubupc1:/home/dinocob# python3 test.py
<coroutine object hello.get_ticks at 0x7f13190a9200>
test.py:42: RuntimeWarning: coroutine 'mtest.get_ticks' was never awaited
  print (a.get_ticks())
this will be printed after the ticks

这里发生了什么?如果 mtest.get_ticks 在 def 的开头有 async 字样,为什么我无法访问它?

【问题讨论】:

  • 调用时需要使用await
  • 通过这种方式调用函数时出现语法错误:foo = await a.get_ticks()...
  • 你不能在协程之外使用await。如果您尝试在另一个协程之外执行协程,则需要使用事件循环来安排它(例如,loop.run_until_complete(a.get_ticks()))。
  • 好的,但是我如何将 get_ticks 的返回值设置为变量?请你给我一个你在说什么的工作例子,好吗? :)
  • foo = loop.run_until_complete(a.get_ticks())

标签: python websocket python-asyncio


【解决方案1】:

我终于找到了正确的方法(特别感谢@dirn

#!/usr/bin/env python3

import sys, json
import asyncio
from websockets import connect

class EchoWebsocket:
    async def __aenter__(self):
        self._conn = connect('wss://ws.binaryws.com/websockets/v3')
        self.websocket = await self._conn.__aenter__()        
        return self

    async def __aexit__(self, *args, **kwargs):
        await self._conn.__aexit__(*args, **kwargs)

    async def send(self, message):
        await self.websocket.send(message)

    async def receive(self):
        return await self.websocket.recv()

class mtest:
    def __init__(self):
        self.wws = EchoWebsocket()
        self.loop = asyncio.get_event_loop()

    def get_ticks(self):
        return self.loop.run_until_complete(self.__async__get_ticks())

    async def __async__get_ticks(self):
        async with self.wws as echo:
            await echo.send(json.dumps({'ticks_history': 'R_50', 'end': 'latest', 'count': 1}))
            return await echo.receive()

这在 main.py 中:

from testws import *

a = mtest()

foo = a.get_ticks()
print (foo)

print ("async works like a charm!")

foo = a.get_ticks()
print (foo)

这是输出:

root@ubupc1:/home/dinocob# python3 test.py
{"count": 1, "end": "latest", "ticks_history": "R_50"}
async works like a charm!
{"count": 1, "end": "latest", "ticks_history": "R_50"}

欢迎任何改进它的提示! ;)

【讨论】:

    【解决方案2】:

    你的问题和答案都很棒! 他们帮了我很多!

    根据您的代码,我能够创建以下类, 更好地满足我的需要:

    import asyncio
    from websockets import connect
    
    class TestClient:
        def __init__(self, URL):
            self.URL = URL
            self.conn = None
            self.loop = asyncio.get_event_loop()
    
        async def send(self, message):
            if self.conn == None:
                self.conn = await connect(self.URL)
            await self.conn.send(message)
    
        async def receive(self):
            return await self.conn.recv()
    
        def ping(self):
            return self.loop.run_until_complete(self._ping())
    
        async def _ping(self):
            await self.send("Hello World")
            return await self.receive()
    
    test = TestClient("wss://echo.websocket.org")
    print(test.ping())
    

    【讨论】:

    • run_until_complete 不会阻止你的运行循环吗?在这种情况下效果很好,但似乎使用 asyncio 需要承诺
    猜你喜欢
    • 1970-01-01
    • 2019-01-27
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    相关资源
    最近更新 更多