如何在Python中编写一系列承诺?

问题描述:

是否可以使用仅编写promise(或任务)的序列Python 3.6.1 Standard Library如何在Python中编写一系列承诺?

例如,序列在JavaScript承诺被写为:

const SLEEP_INTERVAL_IN_MILLISECONDS = 200; 

const alpha = function alpha (number) { 
    return new Promise(function (resolve, reject) { 
     const fulfill = function() { 
      return resolve(number + 1); 
     }; 

     return setTimeout(fulfill, SLEEP_INTERVAL_IN_MILLISECONDS); 
    }); 
}; 

const bravo = function bravo (number) { 
    return new Promise(function (resolve, reject) { 
     const fulfill = function() { 
      return resolve(Math.ceil(1000*Math.random()) + number); 
     }; 
     return setTimeout(fulfill, SLEEP_INTERVAL_IN_MILLISECONDS); 
    }); 
}; 

const charlie = function charlie (number) { 
    return new Promise(function (resolve, reject) { 
     return (number%2 == 0) ? reject(number) : resolve(number); 
    }); 
}; 

function run() { 
    return Promise.resolve(42) 
     .then(alpha) 
     .then(bravo) 
     .then(charlie) 
     .then((number) => { 
      console.log('success: ' + number) 
     }) 
     .catch((error) => { 
      console.log('error: ' + error); 
     }); 
} 

run(); 

每个功能also returns a Promise和异步处理结果,将得到解决/由紧随其后的承诺拒绝。

我知道库,如promises-2.01basyncio 3.4.3,我正在寻找Python STL解决方案。因此,如果我需要导入非STL库,我宁愿使用RxPython代替。

下面是使用ASYNCIO和async/await synthax一个类似的计划:

import asyncio 
import random 

async def alpha(x): 
    await asyncio.sleep(0.2) 
    return x + 1 

async def bravo(x): 
    await asyncio.sleep(0.2) 
    return random.randint(0, 1000) + x 

async def charlie(x): 
    if x % 2 == 0: 
     return x 
    raise ValueError(x, 'is odd') 

async def run(): 
    try: 
     number = await charlie(await bravo(await alpha(42))) 
    except ValueError as exc: 
     print('error:', exc.args[0]) 
    else: 
     print('success:', number) 

if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(run()) 
    loop.close() 

编辑:如果你有兴趣的反应流,你可以考虑使用aiostream

这里有一个简单的例子:

import asyncio 
from aiostream import stream, pipe 

async def main(): 
    # This stream computes 11² + 13² in 1.5 second 
    xs = (
     stream.count(interval=0.1)  # Count from zero every 0.1 s 
     | pipe.skip(10)     # Skip the first 10 numbers 
     | pipe.take(5)     # Take the following 5 
     | pipe.filter(lambda x: x % 2) # Keep odd numbers 
     | pipe.map(lambda x: x ** 2) # Square the results 
     | pipe.accumulate()    # Add the numbers together 
    ) 
    print('11² + 13² = ', await xs) 

if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(main()) 
    loop.close() 

更多的例子在documentation

+0

酷!唯一不好的部分是伸缩方法调用。希望能够写出更类似于JS承诺序列或反应可观察流的东西。但是这个已经解决了我的问题:-) –

+1

@JPVentura是的,这一行有点长,但你可以通过使用额外的变量来分割它。 asyncio没有管道语法,因为它尝试尽可能地接近同步编程。另外,请参阅我关于反应流的编辑。 – Vincent

尽管您正在寻找的功能(Future)在Python 3.5及更高版本中可用,但您运气好,Python 3.4及以上版本包括asyncio

从您自己的关于asyncio的链接:“此版本仅与Python 3.3相关,它不包含stdlib中的asyncio。”

例子:

import asyncio 


async def some_coroutine(): 
    await asyncio.sleep(1) 
    return 'done' 


def process_result(future): 
    print('Task returned:', future.result()) 


loop = asyncio.get_event_loop() 
task = loop.create_task(some_coroutine()) 
task.add_done_callback(process_result) 
loop.run_until_complete() 
+0

你如何将以前的JS例子翻译成使用Future的Python 3.5? –