如何执行函数列表并将数据传递给使用 asyncio 调用的适当函数

1 python asynchronous python-asyncio

我以前使用的是 requests,但后来我转向 aiohttp + asyncio 来并行运行帐户,但是我在将逻辑放在脑海中时遇到了困难。

class Faked(object):
    def __init__(self):
        self.database = sqlite3.connect('credentials.db')

    async def query_login(self, email):
        print(email)
        cur = self.database.cursor()
        sql_q = """SELECT * from user WHERE email='{0}'""".format(email)
        users = cur.execute(sql_q)
        row = users.fetchone()
        if row is None:
            raise errors.ToineyError('No user was found with email: ' + email + ' in database!')

        self.logger().debug("Logging into account '{0}'!".format(row[0]))
        call_func = await self._api.login(data={'email': row[0],
                                                'password': row[1],
                                                'deviceId': row[2],
                                                'aaid': row[3]})
        return await call_func

    async def send_friend_request(self, uid):
        return await self._api.send_friend_request(uid)


def main(funcs, data=None):
    """
   todo: fill
  :rtype: object
  """
    tasks = []
    if isinstance(funcs, list):
        for func in funcs:
            tasks.append(func)
    else:
        tasks.append(funcs)
    print(tasks)
    loop = asyncio.get_event_loop()
    results = loop.run_until_complete(asyncio.gather(*tasks))
    for result in results:
        print(result)
    return results


if __name__ == '__main__':  # for testing purposes mostly
    emails = ['email@hotmail.com', 'email@outlook.com', 'email@gmail.com']
Run Code Online (Sandbox Code Playgroud)

我本质上只是想知道如何对多个函数进行排队,在本例中是 query_login 和 send_friend_request,同时还将正确的数据传递给所述函数,假设我会同时在社交媒体应用程序上运行三个帐户,这真的让我难以置信,尽管我有使事情变得过于复杂的倾向,但任何帮助将不胜感激。

Ale*_*ers 5

Python 的设计目的是通过解包运算符 * 或使用 lambda 来使这一过程变得相当容易。该线程中有几个很好的答案可以满足您的需求:

在Python中将带有参数的函数传递给另一个函数?

让我们来看看它。

callstack = [] # initialize a list to serve as our stack.
     # See also collections.deque for a queue.
Run Code Online (Sandbox Code Playgroud)

然后我们可以定义我们的函数:

def somefunc(a, b, c): 
    do stuff...
Run Code Online (Sandbox Code Playgroud)

然后将调用添加到堆栈,并将参数作为列表。

args = [a, b, c]
callstack.append((somefunc, args)) # append a tuple with the function
            # and its arguments list.

# calls the next item in the callstack
def call_next(callstack):
    func, args = callstack.pop() # unpack our tuple
    func(*args) # calls the func with the args unpacked
Run Code Online (Sandbox Code Playgroud)

* 运算符解压列表并按顺序将它们作为参数提供。您还可以使用双星运算符 (**) 解压关键字参数。

def call_next(callstack):
    func, args, kwargs = callstack.pop() # unpack our tuple
    func(*args, **kwargs) # calls the func with both args and kwargs unpacked.
Run Code Online (Sandbox Code Playgroud)

另一种方法是只创建一个 lambda。

def add(a, b):
    return a + b

callstack = []

callstack.append(lambda: add(1, 2))
callstack.pop()() # pops the lambda function, then calls the lambda function, 
                  # which just calls the function as you specified it.
Run Code Online (Sandbox Code Playgroud)

瞧!所有功劳都归功于其他线程的作者。这里有一个问题:如果您将对象作为参数传递,它将作为引用传递。请小心,因为您可以在堆栈中调用该对象之前对其进行修改。

def add(a, b, c):
    return a + b + c

badlist = [1,2,3]
callstack.append((somefunc, badlist))
badlist = [2, 4, 6]
callstack.append((somefunc, badlist))

while len(callstack) > 0:
    print(call_next(callstack))

# Prints:
12
12
Run Code Online (Sandbox Code Playgroud)

您可以在 *args 版本中使用以下方法解决此问题:

# make a shallow copy and pass that to the stack instead.
callstack.append((somefunc, list(badlist))) 
Run Code Online (Sandbox Code Playgroud)

在 lambda 函数中,整个事物在调用时进行评估,因此即使通常不是引用的事物也会表现得像引用。上述技巧不起作用,因此在创建 lambda 之前根据需要进行任何复制。