Предположим, у меня есть класс, который используется для выполнения операций ввода-вывода:
class CommunicationStack:
def __init__(self, socket):
self.socket = socket
def sync_get_data(self):
...
def sync_send_data(self):
...
async def async_get_data(self):
...
async def async_send_data(self):
...
Как вы можете видеть, он имеет вариант синхронизации и асинхронности для тех же операций, но было бы немного неудобно писатьasync_get_data
или sync_get_data
вручную.Я ищу умный способ иметь такой же интерфейс, как
def get_data(self):
... # call sync variant or return an awaitable, depending on caller type
def send_data(self):
... # call sync variant or return an awaitable, depending on caller type
, чтобы его можно было удобно использовать, например:
stack = CommunicationStack(...)
def thread_procedure():
data = stack.get_data() # get_data returns data
async def task_procedure():
data = await stack.get_data() # get_data returns an awaitable
Я считаю, что это можно сделать каким-то хитрым способом сосмотры или некоторая черная магия :
def is_caller_coroutine():
return sys._getframe(2).f_code.co_flags & 0x380
, чтобы проверить, является ли вызывающая функция сопрограммой или функцией, но это кажется плохим дизайном, чтобы портить кишки питона.
Вопрос в том, как правильно выбрать подходящий вариант?Или есть лучший способ спроектировать все, например, с использованием адаптеров или разработкой двух независимых классов AsyncCommunicationStack
и SyncCommunicationStack
?