What is the Python equivalent of a Promise from JavaScript?

Question:

I am trying to understand what would be the best code structure or a design pattern that would do the following:

Have a function named get_data that would start up a socket connection and will start waiting for a specific socket event that would return some data. Once it gets the data, only then the get_data function should be returned.

So in JS it would be very simple like this:

(Keep in mind that this code snippet is an example, it’s not meant to be a working code)

const getData = async ()=>{
  return new Promise((resolve, reject)=>{
    const socket = socket()
    socket.on("message", (data)=>{
      resolve(data)
    })
    socket.connect("localhost")
  });
}

const parseData = async () => {
  const data = await getData()
  // do something with the data
}

With Python however, I have absolutely no idea how to achieve the same result.

How would I translate it to Python? What strategy would be used here?

The only way I could think of right now is like this:

def get_data():
  socket = socket()
  my_data = None

  @socket.event
  def message(data):
    nonlocal my_data
    my_data = data

  socket.connect("localhost")
  
  while not my_data:
    time.sleep(0.3)
  
  socket.disconnect()
  return my_data

def parse_data():
  data = get_data()
  # do something with the data
Asked By: BobTheSatan

||

Answers:

If you want to convert a callback-based API into an async API, you’re probably looking for asyncio.Future.

Modifying your strawman code a bit:

import asyncio

def get_data():
    # create a future
    future = asyncio.Future()

    # create a socket
    socket = socket()

    # connect callbacks
    @socket.on("message")
    def on_message(data):
        future.set_result(data)

    @socket.on("error")
    def on_error(error):
        future.set_exception(error)

    # create a background task that will communicate with the socket
    # and invoke the callbacks
    @asyncio.create_task
    async def communicate():
        socket.connect('localhost')
        socket.communicate()

    # return the future
    return future

Calling get_data will return an object you can await on just like async function calls:

async def parse_data():
    data = await get_data()
    # process further
Answered By: user3840170
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.