Await outside function как исправить

Hello I am new to python and am trying to work with a Dark Sky python API made by Detrous. When I run the demo code I am presented with an error: forecast = await darksky.get_forecast( ...

Hello I am new to python and am trying to work with a Dark Sky python API made by Detrous. When I run the demo code I am presented with an error:

forecast = await darksky.get_forecast(
              ^
SyntaxError: 'await' outside function

this error results from:

forecast = await darksky.get_forecast(
    latitude, longitude,
    extend=False, # default `False`
    lang=languages.ENGLISH, # default `ENGLISH`
    units=units.AUTO, # default `auto`
    exclude=[weather.MINUTELY, weather.ALERTS] # default `[]`
)

I am not too sure how to resolve this issue and am using python 3.

Thanks

asked Oct 19, 2019 at 6:19

NameIsMarcus's user avatar

3

I think this answer will be useful for people who search the same question as me.
To use async functions in synchronous context you can use event loop. You can write it from scratch for education purposes.
You can start from this answer
https://stackoverflow.com/a/51116910/14154287
And continue education with David Beazley books.

But developers of asyncio already did this for you.

import asyncio

loop = asyncio.get_event_loop()
forecast = loop.run_until_complete(darksky.get_forecast(...<here place arguments>...))
loop.close()

answered Sep 17, 2020 at 18:28

terehpp's user avatar

terehppterehpp

2213 silver badges7 bronze badges

1

The await keyword can be used only in asynchronous functions and methods. You can read more on asynchronous code to understand why.

The solution, without having any details about what you want to accomplish and how, is to use darksky = DarkSky(API_KEY) instead of darksky = DarkSkyAsync(API_KEY).

answered Oct 19, 2019 at 8:02

Krasen Penchev's user avatar

Опять-же есть у меня код евента.
Пишет ошибку: SyntaxError: await outside function.

# Event
@bot.event
async def on_message(message):
    await bot.process_commands(message)
    if message.author.id == bot.user.id:
        return

    if message.author.id in bot.blacklisted_users:
        return

    if f"<@!{bot.user.id}>" in message.content:
        data = cogs._json.read_json('prefixes')
        if str(message.guild.id) in data:
            prefix = data[str(message.guild.id)]

if __name__ == '__main__':
    for file in os.listdir(cwd+"/cogs"):
        if file.endswith(".py") and not file.startswith("_"):
            bot.load_extension(f"cogs.{file[:-3]}")

            if not message.author.bot and bot.user in message.mentions:
                embed = discord.Embed(title = f'Welcome!', timestamp = message.created_at, colour = discord.Colour.from_rgb(199, 182, 219),  description = f'''
                Hi {message.author.display_name}, my name **Osidium**!
                • My prefix - `o+`
                • Write the command `o+help` to find out all my features.
                • Want to know a little about me? Write `o-about`.
                • Need help on the bot, or found a bug/error? Visit our server: [Join](https://discord.gg/tYr5xeSS79)''')
                await message.reply(embed=embed)

@ymsaputra

I run the example in PySyft/examples/tutorials/advanced/websockets-example-MNIST-parallel/Asynchronous-federated-learning-on-MNIST.ipynb. However, there is a syntax error as follows:

File «coba_fed_async.py», line 73
results = await asyncio.gather(
^
SyntaxError: ‘await’ outside function

I use Python 3.7.x. Is there any solution for this issue?

@fermat97

hi @ymsaputra did you find any solution? Hi @midokura-silvia do you have any idea? I got

results = await asyncio.gather(
                      ^
SyntaxError: invalid syntax

and I use python 3.6

@midokura-silvia

@ymsaputra await needs to be called from within a function. So in your file coba_fed_async.py your await calls need to be in a function that is marked as async.

@fermat97 this is not enough information to deduce where the syntax error is coming from.

@fermat97

@midokura-silvia I am using your code in Asynchronous-federated-learning-on-MNIST, however I don’t use as a notebook. There you have:

results = await asyncio.gather(
        *[
            rwc.fit_model_on_worker(
                worker=worker,
                traced_model=traced_model,
                batch_size=args.batch_size,
                curr_round=curr_round,
                max_nr_batches=args.federate_after_n_batches,
                lr=learning_rate,
            )
            for worker in worker_instances
        ]
    )

in this case await is used outside an async function. How didn’t you get any error?

@newne

@midokura-silvia I am using your code in Asynchronous-federated-learning-on-MNIST, however I don’t use as a notebook. There you have:

results = await asyncio.gather(
        *[
            rwc.fit_model_on_worker(
                worker=worker,
                traced_model=traced_model,
                batch_size=args.batch_size,
                curr_round=curr_round,
                max_nr_batches=args.federate_after_n_batches,
                lr=learning_rate,
            )
            for worker in worker_instances
        ]
    )

in this case await is used outside an async function. How didn’t you get any error?

I had the same error. but it worked in notebook.

@okazaki0

try to create async function and use inside the await i think it will work

@github-actions

This issue has been marked stale because it has been open 30 days with no activity. Leave a comment or remove the stale label to unmark it. Otherwise, this will be closed in 7 days.

@harshkasyap

@MusheerRepo

The syntax for using it is:

async def function_name:
Statement 1
Statement 2
.
.

asyncio.run(function_name())

Дополнил код ещё немного.

Python
1
2
3
4
5
6
7
8
9
10
11
import discord
 
class MyClient(discord.Client):
    async def on_ready(self):
        print('Logged on as {0}!'.format(self.user))
        
    async def on_message(self, message):
        await main.send('Hello') # "main" - название канала на сервере
 
client = MyClient()
client.run('NzcxMzYwMzk4NzAzOTg0NjYx.X5q_Wg.w00I702euybW-Z2AYSQp')

Теперь бот становится онлайн, никаких ошибок не выдаётся. Но вот сообщение он не отправляет. Что делать?

Добавлено через 3 часа 56 минут
Полазив интернет, исправив код, я нашёл рабочий код бота, который отправляет сообщения.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import asyncio
from discord.ext import commands
 
bot = commands.Bot(command_prefix='.')
 
async def background_task():
      time = 5 # 86400
      await asyncio.sleep(time)
      message = 'Hello'
      await bot.get_channel(id_channel).send(message)
 
async def on_ready():
    print('Bot logged as {}'.format(bot.user))
 
 
async def on_message(ctx):
    pass
 
 
token = 'token'
bot.loop.create_task(background_task())
bot.run(token)

На данный момент всё работает, также без ошибок, правда в консоль перестала выводиться информация о том что бот залогинен, но мне это не принципиально. Но бот отправляет сообщение только один раз, а надо чтобы функция background_task повторялась (т.е. чтобы каждые пять секунд отправлялось сообщение).

Добавлено через 36 минут
Возникла ещё одна проблема: у меня имеются несколько значений переменной message. Я хочу сделать так чтобы список этих самых значений располагался в другом файле. Файл создал, а как их объединить (основной файл с кодом бота и файл с списком значений), я незнаю, облазил весь интернет, не нашёл.

Содержание

  1. Python Enhancement Proposals
  2. PEP 492 – Coroutines with async and await syntax
  3. Abstract
  4. API Design and Implementation Revisions
  5. Rationale and Goals
  6. Specification
  7. New Coroutine Declaration Syntax
  8. types.coroutine()
  9. Await Expression
  10. Updated operator precedence table
  11. Examples of “await” expressions
  12. Asynchronous Context Managers and “async with”
  13. New Syntax
  14. Example
  15. Asynchronous Iterators and “async for”
  16. New Syntax
  17. Example 1
  18. Example 2
  19. Why StopAsyncIteration?
  20. Coroutine objects
  21. Differences from generators
  22. Coroutine object methods
  23. Debugging Features
  24. New Standard Library Functions
  25. New Abstract Base Classes
  26. Glossary
  27. Transition Plan
  28. Backwards Compatibility
  29. asyncio
  30. asyncio migration strategy
  31. async/await in CPython code base
  32. Grammar Updates
  33. Deprecation Plans
  34. Design Considerations
  35. PEP 3152
  36. Coroutine-generators
  37. Why “async” and “await” keywords
  38. Why “__aiter__” does not return an awaitable
  39. Importance of “async” keyword
  40. Why “async def”
  41. Why not “await for” and “await with”
  42. Why “async def” and not “def async”
  43. Why not a __future__ import
  44. Why magic methods start with “a”
  45. Why not reuse existing magic names
  46. Why not reuse existing “for” and “with” statements
  47. Comprehensions
  48. Async lambda functions
  49. Performance
  50. Overall Impact
  51. Tokenizer modifications
  52. async/await
  53. Reference Implementation
  54. List of high-level changes and new protocols
  55. Working example
  56. Acceptance
  57. Implementation
  58. References
  59. Acknowledgments
  60. Copyright

Python Enhancement Proposals

PEP 492 – Coroutines with async and await syntax

Abstract

The growth of Internet and general connectivity has triggered the proportionate need for responsive and scalable code. This proposal aims to answer that need by making writing explicitly asynchronous, concurrent Python code easier and more Pythonic.

It is proposed to make coroutines a proper standalone concept in Python, and introduce new supporting syntax. The ultimate goal is to help establish a common, easily approachable, mental model of asynchronous programming in Python and make it as close to synchronous programming as possible.

This PEP assumes that the asynchronous tasks are scheduled and coordinated by an Event Loop similar to that of stdlib module asyncio.events.AbstractEventLoop . While the PEP is not tied to any specific Event Loop implementation, it is relevant only to the kind of coroutine that uses yield as a signal to the scheduler, indicating that the coroutine will be waiting until an event (such as IO) is completed.

We believe that the changes proposed here will help keep Python relevant and competitive in a quickly growing area of asynchronous programming, as many other languages have adopted, or are planning to adopt, similar features: [2], [5], [6], [7], [8], [10].

API Design and Implementation Revisions

  1. Feedback on the initial beta release of Python 3.5 resulted in a redesign of the object model supporting this PEP to more clearly separate native coroutines from generators — rather than being a new kind of generator, native coroutines are now their own completely distinct type (implemented in [17]).

This change was implemented based primarily due to problems encountered attempting to integrate support for native coroutines into the Tornado web server (reported in [18]).

In CPython 3.5.2, the __aiter__ protocol was updated.

Before 3.5.2, __aiter__ was expected to return an awaitable resolving to an asynchronous iterator. Starting with 3.5.2, __aiter__ should return asynchronous iterators directly.

If the old protocol is used in 3.5.2, Python will raise a PendingDeprecationWarning .

In CPython 3.6, the old __aiter__ protocol will still be supported with a DeprecationWarning being raised.

In CPython 3.7, the old __aiter__ protocol will no longer be supported: a RuntimeError will be raised if __aiter__ returns anything but an asynchronous iterator.

See [19] and [20] for more details.

Rationale and Goals

Current Python supports implementing coroutines via generators (PEP 342), further enhanced by the yield from syntax introduced in PEP 380. This approach has a number of shortcomings:

  • It is easy to confuse coroutines with regular generators, since they share the same syntax; this is especially true for new developers.
  • Whether or not a function is a coroutine is determined by a presence of yield or yield from statements in its body, which can lead to unobvious errors when such statements appear in or disappear from function body during refactoring.
  • Support for asynchronous calls is limited to expressions where yield is allowed syntactically, limiting the usefulness of syntactic features, such as with and for statements.

This proposal makes coroutines a native Python language feature, and clearly separates them from generators. This removes generator/coroutine ambiguity, and makes it possible to reliably define coroutines without reliance on a specific library. This also enables linters and IDEs to improve static code analysis and refactoring.

Native coroutines and the associated new syntax features make it possible to define context manager and iteration protocols in asynchronous terms. As shown later in this proposal, the new async with statement lets Python programs perform asynchronous calls when entering and exiting a runtime context, and the new async for statement makes it possible to perform asynchronous calls in iterators.

Specification

This proposal introduces new syntax and semantics to enhance coroutine support in Python.

This specification presumes knowledge of the implementation of coroutines in Python (PEP 342 and PEP 380). Motivation for the syntax changes proposed here comes from the asyncio framework (PEP 3156) and the “Cofunctions” proposal (PEP 3152, now rejected in favor of this specification).

From this point in this document we use the word native coroutine to refer to functions declared using the new syntax. generator-based coroutine is used where necessary to refer to coroutines that are based on generator syntax. coroutine is used in contexts where both definitions are applicable.

New Coroutine Declaration Syntax

The following new syntax is used to declare a native coroutine:

Key properties of coroutines:

  • async def functions are always coroutines, even if they do not contain await expressions.
  • It is a SyntaxError to have yield or yield from expressions in an async function.
  • Internally, two new code object flags were introduced:
    • CO_COROUTINE is used to mark native coroutines (defined with new syntax).
    • CO_ITERABLE_COROUTINE is used to make generator-based coroutines compatible with native coroutines (set by types.coroutine() function).
  • Regular generators, when called, return a generator object; similarly, coroutines return a coroutine object.
  • StopIteration exceptions are not propagated out of coroutines, and are replaced with a RuntimeError . For regular generators such behavior requires a future import (see PEP 479).
  • When a native coroutine is garbage collected, a RuntimeWarning is raised if it was never awaited on (see also Debugging Features).
  • See also Coroutine objects section.

types.coroutine()

A new function coroutine(fn) is added to the types module. It allows interoperability between existing generator-based coroutines in asyncio and native coroutines introduced by this PEP:

The function applies CO_ITERABLE_COROUTINE flag to generator- function’s code object, making it return a coroutine object.

If fn is not a generator function, it is wrapped. If it returns a generator, it will be wrapped in an awaitable proxy object (see below the definition of awaitable objects).

Note, that the CO_COROUTINE flag is not applied by types.coroutine() to make it possible to separate native coroutines defined with new syntax, from generator-based coroutines.

Await Expression

The following new await expression is used to obtain a result of coroutine execution:

await , similarly to yield from , suspends execution of read_data coroutine until db.fetch awaitable completes and returns the result data.

It uses the yield from implementation with an extra step of validating its argument. await only accepts an awaitable, which can be one of:

  • A native coroutine object returned from a native coroutine function.
  • A generator-based coroutine object returned from a function decorated with types.coroutine() .
  • An object with an __await__ method returning an iterator.

Any yield from chain of calls ends with a yield . This is a fundamental mechanism of how Futures are implemented. Since, internally, coroutines are a special kind of generators, every await is suspended by a yield somewhere down the chain of await calls (please refer to PEP 3156 for a detailed explanation).

To enable this behavior for coroutines, a new magic method called __await__ is added. In asyncio, for instance, to enable Future objects in await statements, the only change is to add __await__ = __iter__ line to asyncio.Future class.

Objects with __await__ method are called Future-like objects in the rest of this PEP.

It is a TypeError if __await__ returns anything but an iterator.

  • Objects defined with CPython C API with a tp_as_async.am_await function, returning an iterator (similar to __await__ method).
  • It is a SyntaxError to use await outside of an async def function (like it is a SyntaxError to use yield outside of def function).

    It is a TypeError to pass anything other than an awaitable object to an await expression.

    Updated operator precedence table

    await keyword is defined as follows:

    where “primary” represents the most tightly bound operations of the language. Its syntax is:

    See Python Documentation [12] and Grammar Updates section of this proposal for details.

    The key await difference from yield and yield from operators is that await expressions do not require parentheses around them most of the times.

    Also, yield from allows any expression as its argument, including expressions like yield from a() + b() , that would be parsed as yield from (a() + b()) , which is almost always a bug. In general, the result of any arithmetic operation is not an awaitable object. To avoid this kind of mistakes, it was decided to make await precedence lower than [] , () , and . , but higher than ** operators.

    Operator Description
    yield x , yield from x Yield expression
    lambda Lambda expression
    if – else Conditional expression
    or Boolean OR
    and Boolean AND
    not x Boolean NOT
    in , not in , is , is not , , , > , >= , != , == Comparisons, including membership tests and identity tests
    | Bitwise OR
    ^ Bitwise XOR
    & Bitwise AND
    , >> Shifts
    + , — Addition and subtraction
    * , @ , / , // , % Multiplication, matrix multiplication, division, remainder
    +x , -x ,

    x

    Positive, negative, bitwise NOT
    ** Exponentiation
    await x Await expression
    x[index] , x[index:index] , x(arguments. ) , x.attribute Subscription, slicing, call, attribute reference
    (expressions. ) , [expressions. ] , , Binding or tuple display, list display, dictionary display, set display

    Examples of “await” expressions

    Valid syntax examples:

    Expression Will be parsed as
    if await fut: pass if (await fut): pass
    if await fut + 1: pass if (await fut) + 1: pass
    pair = await fut, ‘spam’ pair = (await fut), ‘spam’
    with await fut, open(): pass with (await fut), open(): pass
    await foo()[‘spam’].baz()() await ( foo()[‘spam’].baz()() )
    return await coro() return ( await coro() )
    res = await coro() ** 2 res = (await coro()) ** 2
    func(a1=await coro(), a2=0) func(a1=(await coro()), a2=0)
    await foo() + await bar() (await foo()) + (await bar())
    -await foo() -(await foo())

    Invalid syntax examples:

    Expression Should be written as
    await await coro() await (await coro())
    await -coro() await (-coro())

    Asynchronous Context Managers and “async with”

    An asynchronous context manager is a context manager that is able to suspend execution in its enter and exit methods.

    To make this possible, a new protocol for asynchronous context managers is proposed. Two new magic methods are added: __aenter__ and __aexit__ . Both must return an awaitable.

    An example of an asynchronous context manager:

    New Syntax

    A new statement for asynchronous context managers is proposed:

    which is semantically equivalent to:

    As with regular with statements, it is possible to specify multiple context managers in a single async with statement.

    It is an error to pass a regular context manager without __aenter__ and __aexit__ methods to async with . It is a SyntaxError to use async with outside of an async def function.

    Example

    With asynchronous context managers it is easy to implement proper database transaction managers for coroutines:

    Code that needs locking also looks lighter:

    Asynchronous Iterators and “async for”

    An asynchronous iterable is able to call asynchronous code in its iter implementation, and asynchronous iterator can call asynchronous code in its next method. To support asynchronous iteration:

    1. An object must implement an __aiter__ method (or, if defined with CPython C API, tp_as_async.am_aiter slot) returning an asynchronous iterator object.
    2. An asynchronous iterator object must implement an __anext__ method (or, if defined with CPython C API, tp_as_async.am_anext slot) returning an awaitable.
    3. To stop iteration __anext__ must raise a StopAsyncIteration exception.

    An example of asynchronous iterable:

    New Syntax

    A new statement for iterating through asynchronous iterators is proposed:

    which is semantically equivalent to:

    It is a TypeError to pass a regular iterable without __aiter__ method to async for . It is a SyntaxError to use async for outside of an async def function.

    As for with regular for statement, async for has an optional else clause.

    Example 1

    With asynchronous iteration protocol it is possible to asynchronously buffer data during iteration:

    Where cursor is an asynchronous iterator that prefetches N rows of data from a database after every N iterations.

    The following code illustrates new asynchronous iteration protocol:

    then the Cursor class can be used as follows:

    which would be equivalent to the following code:

    Example 2

    The following is a utility class that transforms a regular iterable to an asynchronous one. While this is not a very useful thing to do, the code illustrates the relationship between regular and asynchronous iterators.

    Why StopAsyncIteration?

    Coroutines are still based on generators internally. So, before PEP 479, there was no fundamental difference between

    And since PEP 479 is accepted and enabled by default for coroutines, the following example will have its StopIteration wrapped into a RuntimeError

    The only way to tell the outside code that the iteration has ended is to raise something other than StopIteration . Therefore, a new built-in exception class StopAsyncIteration was added.

    Moreover, with semantics from PEP 479, all StopIteration exceptions raised in coroutines are wrapped in RuntimeError .

    Coroutine objects

    Differences from generators

    This section applies only to native coroutines with CO_COROUTINE flag, i.e. defined with the new async def syntax.

    The behavior of existing *generator-based coroutines* in asyncio remains unchanged.

    Great effort has been made to make sure that coroutines and generators are treated as distinct concepts:

      Native coroutine objects do not implement __iter__ and __next__ methods. Therefore, they cannot be iterated over or passed to iter() , list() , tuple() and other built-ins. They also cannot be used in a for..in loop.

    An attempt to use __iter__ or __next__ on a native coroutine object will result in a TypeError .

  • Plain generators cannot yield from native coroutines: doing so will result in a TypeError .
  • generator-based coroutines (for asyncio code must be decorated with @asyncio.coroutine ) can yield from native coroutine objects.
  • inspect.isgenerator() and inspect.isgeneratorfunction() return False for native coroutine objects and native coroutine functions.
  • Coroutine object methods

    Coroutines are based on generators internally, thus they share the implementation. Similarly to generator objects, coroutines have throw() , send() and close() methods. StopIteration and GeneratorExit play the same role for coroutines (although PEP 479 is enabled by default for coroutines). See PEP 342, PEP 380, and Python Documentation [11] for details.

    throw() , send() methods for coroutines are used to push values and raise errors into Future-like objects.

    Debugging Features

    A common beginner mistake is forgetting to use yield from on coroutines:

    For debugging this kind of mistakes there is a special debug mode in asyncio, in which @coroutine decorator wraps all functions with a special object with a destructor logging a warning. Whenever a wrapped generator gets garbage collected, a detailed logging message is generated with information about where exactly the decorator function was defined, stack trace of where it was collected, etc. Wrapper object also provides a convenient __repr__ function with detailed information about the generator.

    The only problem is how to enable these debug capabilities. Since debug facilities should be a no-op in production mode, @coroutine decorator makes the decision of whether to wrap or not to wrap based on an OS environment variable PYTHONASYNCIODEBUG . This way it is possible to run asyncio programs with asyncio’s own functions instrumented. EventLoop.set_debug , a different debug facility, has no impact on @coroutine decorator’s behavior.

    With this proposal, coroutines is a native, distinct from generators, concept. In addition to a RuntimeWarning being raised on coroutines that were never awaited, it is proposed to add two new functions to the sys module: set_coroutine_wrapper and get_coroutine_wrapper . This is to enable advanced debugging facilities in asyncio and other frameworks (such as displaying where exactly coroutine was created, and a more detailed stack trace of where it was garbage collected).

    New Standard Library Functions

    • types.coroutine(gen) . See types.coroutine() section for details.
    • inspect.iscoroutine(obj) returns True if obj is a native coroutine object.
    • inspect.iscoroutinefunction(obj) returns True if obj is a native coroutine function.
    • inspect.isawaitable(obj) returns True if obj is an awaitable.
    • inspect.getcoroutinestate(coro) returns the current state of a native coroutine object (mirrors inspect.getfgeneratorstate(gen) ).
    • inspect.getcoroutinelocals(coro) returns the mapping of a native coroutine object’s local variables to their values (mirrors inspect.getgeneratorlocals(gen) ).
    • sys.set_coroutine_wrapper(wrapper) allows to intercept creation of native coroutine objects. wrapper must be either a callable that accepts one argument (a coroutine object), or None . None resets the wrapper. If called twice, the new wrapper replaces the previous one. The function is thread-specific. See Debugging Features for more details.
    • sys.get_coroutine_wrapper() returns the current wrapper object. Returns None if no wrapper was set. The function is thread-specific. See Debugging Features for more details.

    New Abstract Base Classes

    In order to allow better integration with existing frameworks (such as Tornado, see [13]) and compilers (such as Cython, see [16]), two new Abstract Base Classes (ABC) are added:

    • collections.abc.Awaitable ABC for Future-like classes, that implement __await__ method.
    • collections.abc.Coroutine ABC for coroutine objects, that implement send(value) , throw(type, exc, tb) , close() and __await__() methods.

    Note that generator-based coroutines with CO_ITERABLE_COROUTINE flag do not implement __await__ method, and therefore are not instances of collections.abc.Coroutine and collections.abc.Awaitable ABCs:

    To allow easy testing if objects support asynchronous iteration, two more ABCs are added:

    • collections.abc.AsyncIterable – tests for __aiter__ method.
    • collections.abc.AsyncIterator – tests for __aiter__ and __anext__ methods.

    Glossary

    Transition Plan

    To avoid backwards compatibility issues with async and await keywords, it was decided to modify tokenizer.c in such a way, that it:

    • recognizes async def NAME tokens combination;
    • while tokenizing async def block, it replaces ‘async’ NAME token with ASYNC , and ‘await’ NAME token with AWAIT ;
    • while tokenizing def block, it yields ‘async’ and ‘await’ NAME tokens as is.

    This approach allows for seamless combination of new syntax features (all of them available only in async functions) with any existing code.

    An example of having “async def” and “async” attribute in one piece of code:

    Backwards Compatibility

    This proposal preserves 100% backwards compatibility.

    asyncio

    asyncio module was adapted and tested to work with coroutines and new statements. Backwards compatibility is 100% preserved, i.e. all existing code will work as-is.

    The required changes are mainly:

    1. Modify @asyncio.coroutine decorator to use new types.coroutine() function.
    2. Add __await__ = __iter__ line to asyncio.Future class.
    3. Add ensure_future() as an alias for async() function. Deprecate async() function.

    asyncio migration strategy

    Because plain generators cannot yield from native coroutine objects (see Differences from generators section for more details), it is advised to make sure that all generator-based coroutines are decorated with @asyncio.coroutine before starting to use the new syntax.

    async/await in CPython code base

    There is no use of await names in CPython.

    async is mostly used by asyncio. We are addressing this by renaming async() function to ensure_future() (see asyncio section for details).

    Another use of async keyword is in Lib/xml/dom/xmlbuilder.py , to define an async = False attribute for DocumentLS class. There is no documentation or tests for it, it is not used anywhere else in CPython. It is replaced with a getter, that raises a DeprecationWarning , advising to use async_ attribute instead. ‘async’ attribute is not documented and is not used in CPython code base.

    Grammar Updates

    Grammar changes are fairly minimal:

    Deprecation Plans

    async and await names will be softly deprecated in CPython 3.5 and 3.6. In 3.7 we will transform them to proper keywords. Making async and await proper keywords before 3.7 might make it harder for people to port their code to Python 3.

    Design Considerations

    PEP 3152

    PEP 3152 by Gregory Ewing proposes a different mechanism for coroutines (called “cofunctions”). Some key points:

    1. A new keyword codef to declare a cofunction. Cofunction is always a generator, even if there is no cocall expressions inside it. Maps to async def in this proposal.
    2. A new keyword cocall to call a cofunction. Can only be used inside a cofunction. Maps to await in this proposal (with some differences, see below).
    3. It is not possible to call a cofunction without a cocall keyword.
    4. cocall grammatically requires parentheses after it:

    Differences from this proposal:

    1. There is no equivalent of __cocall__ in this PEP, which is called and its result is passed to yield from in the cocall expression. await keyword expects an awaitable object, validates the type, and executes yield from on it. Although, __await__ method is similar to __cocall__ , but is only used to define Future-like objects.
    2. await is defined in almost the same way as yield from in the grammar (it is later enforced that await can only be inside async def ). It is possible to simply write await future , whereas cocall always requires parentheses.
    3. To make asyncio work with PEP 3152 it would be required to modify @asyncio.coroutine decorator to wrap all functions in an object with a __cocall__ method, or to implement __cocall__ on generators. To call cofunctions from existing generator-based coroutines it would be required to use costart(cofunc, *args, **kwargs) built-in.
    4. Since it is impossible to call a cofunction without a cocall keyword, it automatically prevents the common mistake of forgetting to use yield from on generator-based coroutines. This proposal addresses this problem with a different approach, see Debugging Features.
    5. A shortcoming of requiring a cocall keyword to call a coroutine is that if is decided to implement coroutine-generators – coroutines with yield or async yield expressions – we wouldn’t need a cocall keyword to call them. So we’ll end up having __cocall__ and no __call__ for regular coroutines, and having __call__ and no __cocall__ for coroutine- generators.
    6. Requiring parentheses grammatically also introduces a whole lot of new problems.

    The following code:

    would look like:

    Coroutine-generators

    With async for keyword it is desirable to have a concept of a coroutine-generator – a coroutine with yield and yield from expressions. To avoid any ambiguity with regular generators, we would likely require to have an async keyword before yield , and async yield from would raise a StopAsyncIteration exception.

    While it is possible to implement coroutine-generators, we believe that they are out of scope of this proposal. It is an advanced concept that should be carefully considered and balanced, with a non-trivial changes in the implementation of current generator objects. This is a matter for a separate PEP.

    Why “async” and “await” keywords

    async/await is not a new concept in programming languages:

    • C# has it since long time ago [5];
    • proposal to add async/await in ECMAScript 7 [2]; see also Traceur project [9];
    • Facebook’s Hack/HHVM [6];
    • Google’s Dart language [7];
    • Scala [8];
    • proposal to add async/await to C++ [10];
    • and many other less popular languages.

    This is a huge benefit, as some users already have experience with async/await, and because it makes working with many languages in one project easier (Python with ECMAScript 7 for instance).

    Why “__aiter__” does not return an awaitable

    PEP 492 was accepted in CPython 3.5.0 with __aiter__ defined as a method, that was expected to return an awaitable resolving to an asynchronous iterator.

    In 3.5.2 (as PEP 492 was accepted on a provisional basis) the __aiter__ protocol was updated to return asynchronous iterators directly.

    The motivation behind this change is to make it possible to implement asynchronous generators in Python. See [19] and [20] for more details.

    Importance of “async” keyword

    While it is possible to just implement await expression and treat all functions with at least one await as coroutines, this approach makes APIs design, code refactoring and its long time support harder.

    Let’s pretend that Python only has await keyword:

    If useful() function is refactored and someone removes all await expressions from it, it would become a regular python function, and all code that depends on it, including important() would be broken. To mitigate this issue a decorator similar to @asyncio.coroutine has to be introduced.

    Why “async def”

    For some people bare async name(): pass syntax might look more appealing than async def name(): pass . It is certainly easier to type. But on the other hand, it breaks the symmetry between async def , async with and async for , where async is a modifier, stating that the statement is asynchronous. It is also more consistent with the existing grammar.

    Why not “await for” and “await with”

    async is an adjective, and hence it is a better choice for a statement qualifier keyword. await for/with would imply that something is awaiting for a completion of a for or with statement.

    Why “async def” and not “def async”

    async keyword is a statement qualifier. A good analogy to it are “static”, “public”, “unsafe” keywords from other languages. “async for” is an asynchronous “for” statement, “async with” is an asynchronous “with” statement, “async def” is an asynchronous function.

    Having “async” after the main statement keyword might introduce some confusion, like “for async item in iterator” can be read as “for each asynchronous item in iterator”.

    Having async keyword before def , with and for also makes the language grammar simpler. And “async def” better separates coroutines from regular functions visually.

    Why not a __future__ import

    Transition Plan section explains how tokenizer is modified to treat async and await as keywords only in async def blocks. Hence async def fills the role that a module level compiler declaration like from __future__ import async_await would otherwise fill.

    Why magic methods start with “a”

    New asynchronous magic methods __aiter__ , __anext__ , __aenter__ , and __aexit__ all start with the same prefix “a”. An alternative proposal is to use “async” prefix, so that __anext__ becomes __async_next__ . However, to align new magic methods with the existing ones, such as __radd__ and __iadd__ it was decided to use a shorter version.

    Why not reuse existing magic names

    An alternative idea about new asynchronous iterators and context managers was to reuse existing magic methods, by adding an async keyword to their declarations:

    This approach has the following downsides:

    • it would not be possible to create an object that works in both with and async with statements;
    • it would break backwards compatibility, as nothing prohibits from returning a Future-like objects from __enter__ and/or __exit__ in Python

    Why not reuse existing “for” and “with” statements

    The vision behind existing generator-based coroutines and this proposal is to make it easy for users to see where the code might be suspended. Making existing “for” and “with” statements to recognize asynchronous iterators and context managers will inevitably create implicit suspend points, making it harder to reason about the code.

    Comprehensions

    Syntax for asynchronous comprehensions could be provided, but this construct is outside of the scope of this PEP.

    Async lambda functions

    Syntax for asynchronous lambda functions could be provided, but this construct is outside of the scope of this PEP.

    Performance

    Overall Impact

    This proposal introduces no observable performance impact. Here is an output of python’s official set of benchmarks [4]:

    Tokenizer modifications

    There is no observable slowdown of parsing python files with the modified tokenizer: parsing of one 12Mb file ( Lib/test/test_binop.py repeated 1000 times) takes the same amount of time.

    async/await

    The following micro-benchmark was used to determine performance difference between “async” functions and generators:

    The result is that there is no observable performance difference:

    Note that depth of 19 means 1,048,575 calls.

    Reference Implementation

    The reference implementation can be found here: [3].

    List of high-level changes and new protocols

    1. New syntax for defining coroutines: async def and new await keyword.
    2. New __await__ method for Future-like objects, and new tp_as_async.am_await slot in PyTypeObject .
    3. New syntax for asynchronous context managers: async with . And associated protocol with __aenter__ and __aexit__ methods.
    4. New syntax for asynchronous iteration: async for . And associated protocol with __aiter__ , __aexit__ and new built- in exception StopAsyncIteration . New tp_as_async.am_aiter and tp_as_async.am_anext slots in PyTypeObject .
    5. New AST nodes: AsyncFunctionDef , AsyncFor , AsyncWith , Await .
    6. New functions: sys.set_coroutine_wrapper(callback) , sys.get_coroutine_wrapper() , types.coroutine(gen) , inspect.iscoroutinefunction(func) , inspect.iscoroutine(obj) , inspect.isawaitable(obj) , inspect.getcoroutinestate(coro) , and inspect.getcoroutinelocals(coro) .
    7. New CO_COROUTINE and CO_ITERABLE_COROUTINE bit flags for code objects.
    8. New ABCs: collections.abc.Awaitable , collections.abc.Coroutine , collections.abc.AsyncIterable , and collections.abc.AsyncIterator .
    9. C API changes: new PyCoro_Type (exposed to Python as types.CoroutineType ) and PyCoroObject . PyCoro_CheckExact(*o) to test if o is a native coroutine.

    While the list of changes and new things is not short, it is important to understand, that most users will not use these features directly. It is intended to be used in frameworks and libraries to provide users with convenient to use and unambiguous APIs with async def , await , async for and async with syntax.

    Working example

    All concepts proposed in this PEP are implemented [3] and can be tested.

    Acceptance

    PEP 492 was accepted by Guido, Tuesday, May 5, 2015 [14].

    Implementation

    The implementation is tracked in issue 24017 [15]. It was committed on May 11, 2015.

    References

    Acknowledgments

    I thank Guido van Rossum, Victor Stinner, Elvis Pranskevichus, Andrew Svetlov, Łukasz Langa, Greg Ewing, Stephen J. Turnbull, Jim J. Jewett, Brett Cannon, Nick Coghlan, Steven D’Aprano, Paul Moore, Nathaniel Smith, Ethan Furman, Stefan Behnel, Paul Sokolovsky, Victor Petrovykh, and many others for their feedback, ideas, edits, criticism, code reviews, and discussions around this PEP.

    Copyright

    This document has been placed in the public domain.

    Источник

    Что не так с асинхронными функциями?

    Программа, в которой кода много, а функций совсем нет — это нечитаемая простыня write-only кода. В норме программа состоит из большого числа функций, и большинство из них являются надстройками: первая запускает вторую, а та — третью и четвертую. Если с синхронными функциями все просто: поставили скобки, передали аргументы и вот он результат —, то что делать с асинхронным кодом? Ведь вместо результата асинхронная функция возвращает объект корутины. Как вызвать асинхронную функцию из другой асинхронной функции?

    Настоящая сила await

    Рассмотрим пример с часами в консоли. Это таймер, который отсчитывает секунды и в конце подает звуковой сигнал:

    import asyncio
    
    async def run_timer(secs):
    
        for secs_left in range(secs, 0, -1):
            print(f'Осталось {secs_left} сек.')
            await asyncio.sleep(1)
    
        print('Время вышло!')
        print('a')  # says beep with ASCII BEL symbol
    
    coroutine = run_timer(3)
    asyncio.run(coroutine)  # requires python 3.7
    

    Корутину coroutine запускает функция asyncio.run — внутри она вызывает метод coroutine.send(…) и делает секундные паузы, ориентируюсь по await asyncio.sleep(1). Эти две функции — run и sleep — тесно связаны между собой, работают в паре, но не по отдельности. Исключение из правил — это asyncio.sleep(0) с нулем в качестве аргумента. Она похожа на пустое значение None и не требует для своей работы asyncio.run(…). Этой особенностью мы воспользовались во вводной статье про корутины.

    Вернемся к программе. Она отсчитает 3 секунды, и затем завершит свою работу:

    Осталось 3 сек.
    Осталось 2 сек.
    Осталось 1 сек.
    Время вышло!
    

    Теперь научим программу отсчитывать минуты. Пока времени остается много, пользователю не важны секунды, ему достаточно отсчета минут:

    import asyncio
    
    async def run_five_minutes_timer():
    
        for minutes_left in range(5, 1, -1):
            print(f'Осталось {minutes_left} мин.')
            await asyncio.sleep(60)  # one minute
    
        # TODO добавить отсчет секунд, как в async def run_timer
    
        print('Время вышло!')
        print('a')  # says beep with ASCII BEL symbol
    
    coroutine = run_five_minutes_timer()
    asyncio.run(coroutine)
    

    Этот таймер отсчитает пять минут. Первые четыре минуты он спит по 60 секунд, а затем переключается на секундный отсчет. По крайней мере, так задумано, но как это сделать без копирования кода?

    И тут на сцену выходит await. Он умеет работать не только с asyncio.sleep, но и с любой другой асинхронной функцией. Код нашего таймера теперь выглядит так:

    import asyncio
    
    
    async def countdown_minutes_till_one_left(minutes):
        for minutes_left in range(minutes, 1, -1):
            print(f'Осталось {minutes_left} мин.')
            await asyncio.sleep(60)  # one minute
        print(f'Осталась 1 мин.')
    
    
    async def countdown_seconds(secs):
        for secs_left in range(secs, 0, -1):
            print(f'Осталось {secs_left} сек.')
            await asyncio.sleep(1)
    
    
    async def run_five_minutes_timer():
    
        await countdown_minutes_till_one_left(5)
        await countdown_seconds(60)
    
        print('Время вышло!')
        print('a')  # says beep with ASCII BEL symbol
    
    coroutine = run_five_minutes_timer()
    asyncio.run(coroutine)
    

    Все самое интересное происходит внутри async def run_five_minutes_timer. Эта асинхронная функция сразу же передает управление в корутину countdown_minutes_till_one_left(5) и ждет её завершения, пока та не истощится. Затем то же происходит с отсчетом секунд: управление передается в countdown_seconds(60). В итоге, до первого вызова print('Время вышло!') программа добирается целых 5 минут времени:

    Осталось 5 мин.
    Осталось 4 мин.
    Осталось 3 мин.
    Осталось 2 мин.
    Осталось 1 мин.
    Осталось 60 сек.
    Осталось 59 сек.
    …
    Осталось 3 сек.
    Осталось 2 сек.
    Осталось 1 сек.
    Время вышло!
    

    Команду await можно использовать с любой корутиной. Но обязательно помещайте await внутрь асинхронной функции:

    async def countdown_seconds(secs):
        # TODO do stuff
    
    await countdown_seconds(60)  # SyntaxError: 'await' outside function
    

    Команда await даёт нам мощный инструмент декомпозиции. С ней корутины можно вызывать так же, как обычные функции, достаточно поставить await. Возможно собрать цепочку вызовов, в которой одна корутина авейтит вторую, а та — третью и так до бесконечности.

    Чем закончится кроличья нора?

    В примере выше цепочка корутин непременно заканчивалась вызовом asynio.sleep(…) — это тоже корутина, но как она реализована внутри? В ней тоже есть await с еще одной корутиной ?

    Да, внутри asyncio.sleep тоже есть await, но авейтит он не корутину. Инструкция await умеет работать и с другими объектами. Всех вместе их называют awaitable-объектами.

    Подобно тому, как функция str(my_obj) перепоручает работу методу объекта my_obj.__str__(), так же и await my_obj передает управление методу my_obj.__await__(). Все объекты, у которых есть метод __await__, называют awaitable-объектами, и все они совместимы с await. Библиотека asyncio предоставляет большой набор таких объектов: Future, Task, Event и пр. В этой статье мы не будем вдаваться в детали, это предмет отдельной статьи. Если нужны подробности — читайте документацию по asyncio.

    Любая цепочка корутин заканчивается вызовом await для некорутины

    await vs event loop

    В программе может быть только один event loop, но много await. Возьмем функцию с таймером и запустим сразу три корутины:

    loop = asyncio.get_event_loop()
    
    # просим event loop работать с тремя корутинами
    loop.create_task(run_five_minutes_timer())
    loop.create_task(run_five_minutes_timer())
    loop.create_task(run_five_minutes_timer())
    
    # запускаем evet loop, оживают корутины
    loop.run_forever()
    

    В этой программе один event loop и он находится внутри метода loop.run_forever(). Event loop контролирует исполнение сразу трех корутин — таймеров, по-очереди вызывая их методы coroutine.send(). Так он создает иллюзию их параллельного исполнения:

    Осталось 5 мин.
    Осталось 5 мин.
    Осталось 5 мин.
    Осталось 4 мин.
    Осталось 4 мин.
    Осталось 4 мин.
    …
    

    Удивительно, но хотя первая же строка кода функции run_five_minutes_timer передает управление в другую корутину с помощью await countdown_minutes_till_one_left(5), это не мешает работе других таймеров. Они словно не замечают, что первый таймер “завис” и ждет исчерпания корутины countdown_minutes_till_one_left(5).

    Неверно воспринимать await как маленький самостоятельный event loop. Команда await больше похожа на посредника, который помогает подняться по стеку вызовов корутин и достучаться до верхнего event loop.

    Оживляет корутины только event loop, await ему помогает

    await vs loop.create_task

    С точки зрения той корутины, которую запускают, особой разницы нет. Оба варианта сработают:

    async def run_first_function():
        await run_five_minutes_timer()
        ...
    
    async def run_second_function():
        loop.create_task(run_five_minutes_timer())
        ...
    

    В обоих случаях корутина run_five_minutes_timer() запустится и начнет отсчет времени с минутными интервалом. Однако, большая разница есть для внешних функций: run_first_function и run_second_function.

    Первая — run_first_function — не сможет продолжить работу прежде, чем завершится run_five_minutes_timer(). Команда await будет исправно возвращать управление в event loop, но не в функцию run_first_function.

    Вторая — run_second_function — продолжит свое выполнение сразу после вызова loop.create_task(). Корутина run_five_minutes_timer() будет добавлена в event loop и начнет свою работу, но функция run_second_function не будет её ждать.

    Корутина где есть await блокируется до исчерпания вложенной корутины

    На этом различия между await и loop.create_task не заканчиваются, а только начинаются. Они возвращают разные результаты, они по-разному обрабатывают исключения, они могут принимать разные аргументы. Эта тема тянет на отдельную статью.

    #python #discord #discord.py

    #питон #Discord #discord.py

    Вопрос:

    Я получил ошибку во всем приведенном ниже коде. Я хотел бы обратиться за помощью в связи с этой ошибкой. Могу ли я обратиться за помощью, просмотрев приведенный ниже код?

     async def ban(ctx, member: discord.Member, *, reason: typing.Optional[str] = "사유 없음."):
        await ctx.message.delete()
        author = ctx.message.author
        embed = None
        ch = bot.get_channel(id=772349649553850368)
    
        mesge = await ctx.send("차단을 시킬까요?")
        await mesge.add_reaction('✅')
        await mesge.add_reaction('❌')
            
        def check1(reaction, user):
            return user == ctx.message.author and str(reaction.emoji) == "✅"
    
            try:
                reaction, user = await bot.wait_for("reaction_add", timeout = 30.0, check = check1)
                embed = discord.Embed(title="종합게임 커뮤니티 제재내역 - 차단", description=f'담당자 : {author.mention} n대상자 : {member.mention} n제재사유 : {reason} nn위와 같은 사유로 인해 제재처리 되었습니다.', color=0xff0000)
                embed.set_author(name=f"{str(member)}님을 서버에서 영구적으로 차단했어요.", icon_url=member.avatar_url_as(static_format='png', size=2048))
                embed.set_footer(text=f'처리 시각 - {str(now.year)}{str(now.month)}{str(now.day)} 일 | {str(now.hour)}{str(now.minute)}{str(now.second)}초 - 담당자 : {author.display_name}')
                await ch.send(embed=embed)
                await member.send(embed=embed)
                await ctx.guild.ban(member, reason=f'사유 : {reason}  -  담당자 : {author.display_name}')
        
            except asyncio.TimeoutError:
                print("Timeout")
        
        def check2(reaction, user):
            return user == ctx.message.author and str(reaction.emoji) == "❌"
    
            try:
                reaction, user = await bot.wait_for("reaction_add", timeout = 30.0, check = check2)
                await ctx.send("취소되었다")
            
            except asyncio.TimeoutError:
                print("Timeout")
     

    В приведенном выше коде появляется следующая ошибка.

     reaction, user = await bot.wait_for("reaction_add", timeout = 30.0, check = check1)
                         ^
    SyntaxError: 'await' outside async function
     

    Если вы знаете, как это исправить, пожалуйста, помогите.

    Я использовал переводчик.

    Комментарии:

    1. Вы пробовали менять def check1 на async def check1 и def check2 на async def check2 ? Я мало что сделал с async / await, но это то, что я бы попробовал в первую очередь, поскольку, похоже, именно это предлагает вам сообщение об ошибке.

    2. Я думаю, что это идентификатор. Обратите внимание, что блок try находится внутри функции check1 … вы хотите выделить этот код, чтобы он был ban включен.

    3. То же самое для check2 . вы помещаете следующую попытку внутри функции, когда она должна быть выделена на 4 пробела слева, чтобы она была частью родительской функции.

    Ответ №1:

    Python использует идентификацию для идентификации блоков кода. В вашем коде вы разместили await вызов внутри неасинхронной функции check1 . Вот пример той же проблемы:

     async def foo():
    
        def check1():
            return True
            
            baz = await bar() # improperly indented and in fact can never
                              # run because it is after the function `return`
     

    Исправление заключается в перемещении кода за пределы check1 . Это должно соответствовать приведенному выше заявлению «def».

     async def foo():
    
        def check1():
            return True
            
        baz = await bar()
     

    Ответ №2:

    Ваша проблема связана с отступом после обеих проверок.

    Я добавил # ---- here ---- , чтобы вы знали, где закончить check

     async def ban(ctx, member: discord.Member, *, reason: typing.Optional[str] = "사유 없음."):
        await ctx.message.delete()
        author = ctx.message.author
        embed = None
        ch = bot.get_channel(id=772349649553850368)
    
        mesge = await ctx.send("차단을 시킬까요?")
        await mesge.add_reaction('✅')
        await mesge.add_reaction('❌')
            
        def check1(reaction, user):
            return user == ctx.message.author and str(reaction.emoji) == "✅"
        
        # ---- here ----
        
        try:
            reaction, user = await bot.wait_for("reaction_add", timeout = 30.0, check = check1)
            embed = discord.Embed(title="종합게임 커뮤니티 제재내역 - 차단", description=f'담당자 : {author.mention} n대상자 : {member.mention} n제재사유 : {reason} nn위와 같은 사유로 인해 제재처리 되었습니다.', color=0xff0000)
            embed.set_author(name=f"{str(member)}님을 서버에서 영구적으로 차단했어요.", icon_url=member.avatar_url_as(static_format='png', size=2048))
            embed.set_footer(text=f'처리 시각 - {str(now.year)}{str(now.month)}{str(now.day)} 일 | {str(now.hour)}{str(now.minute)}{str(now.second)}초 - 담당자 : {author.display_name}')
            await ch.send(embed=embed)
            await member.send(embed=embed)
            await ctx.guild.ban(member, reason=f'사유 : {reason}  -  담당자 : {author.display_name}')
    
        except asyncio.TimeoutError:
            print("Timeout")
        
        def check2(reaction, user):
            return user == ctx.message.author and str(reaction.emoji) == "❌"
        # ---- here ----
        
        try:
            reaction, user = await bot.wait_for("reaction_add", timeout = 30.0, check = check2)
            await ctx.send("취소되었다")
        
        except asyncio.TimeoutError:
            print("Timeout")
     

    Комментарии:

    1. ни check1 того, ни check2 другого не должно быть async . Они являются простыми логическими проверками и не блокируют.

    2. Я вижу это сейчас, я думал try , что это вне его,

    3. Сначала меня это тоже зацепило. Озадачен тем, почему вы делаете try блок после возврата.

    Понравилась статья? Поделить с друзьями:
  • Avtl 104 ошибка f01
  • Avtf 104 ошибка h20
  • Avs video recorder ошибка 105
  • Avs 500p стабилизатор ошибка l
  • Avrprog error entering programming mode avr910