Skip to content

Instantly share code, notes, and snippets.

@rinarakaki
Last active November 22, 2018 13:58
Show Gist options
  • Save rinarakaki/cdabceaedbdb498d99802a76cc08b549 to your computer and use it in GitHub Desktop.
Save rinarakaki/cdabceaedbdb498d99802a76cc08b549 to your computer and use it in GitHub Desktop.
How to integrate "as" semantics over "import", "with" and "try/except" statements (in a backward incompatible way)

I bring a strong proposal that is prematurely rejected but indeed the most likely to be accepted to our community. That is to select as spelling not :=, and modify with and except semantics at the same time. For that, we need to investigate what will be derived from the change throughly and here are the results.

Note

This alternative has already been out of consideration, PEP 572 says, but is still here because many Python developers are wondering if as spelling can go and there are few discussions about the way of modifing the two semantics. Even PEP 572 shows little attension to this possibility.

as semantics

https://docs.python.org/3/reference/grammar.html

Current as semantics is not consistent (or is in a way that it is defined depending on each statement).

TODO

= assignment statement

# not independently defined
expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
                     ('=' (yield_expr|testlist_star_expr))*)
annassign: ':' test ['=' test]

import statement

import_stmt: import_name | import_from
import_name: 'import' dotted_as_names
# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
              'import' ('*' | '(' import_as_names ')' | import_as_names))
import_as_name: NAME ['as' NAME]
dotted_as_name: dotted_name ['as' NAME]
import_as_names: import_as_name (',' import_as_name)* [',']
dotted_as_names: dotted_as_name (',' dotted_as_name)*
dotted_name: NAME ('.' NAME)*

with statement

with_stmt: 'with' with_item (',' with_item)*  ':' suite
with_item: test ['as' expr]

except clause

except_clause: 'except' [test ['as' NAME]]

as assignment expression

# This
STATEMENT(EXPR_0 as NAME_0, EXPR_1 as NAME_2, ..., EXPR_n as NAME_n)

# can always be replaced by
NAME_0 = EXPR_0
NAME_1 = EXPR_1
...
NAME_n = EXPR_n
STATEMENT(NAME_0, NAME_1, ..., NAME_n)  # TODO STATEMENT(EXPR_0, EXPR_1, ..., EXPR_n) is better?

# except `import` statement since it's special originally which means no `EXPR` cannot be the left hand of `as` in its statement but simply `NAME`: `import NAME_0 as NAME_1`

# This interpretation above is valid no matter how `EXPR_i` uses `NAME_j` (i > j).

# When you write
EXPR as NAME_0, NAME_1

# it's interpreted as
(EXPR as NAME_0), NAME_1

# You can do unpacking by this
EXPR as (NAME_0, NAME_1)

# `EXPR as NAME` itself can be `EXPR` and it returns just `EXPR` in `EXPR as NAME` which means you can write
((EXPR as NAME_0) as NAME_1) ... as NAME_n

# or simply like this even at the top level since it's determininable.
EXPR as NAME_0 as NAME_1 ... as NAME_n

NAME_0 = EXPR as NAME_1 ... as NAME_n

# Also you can write
f(x=EXPR as NAME)

# since this is valid and `EXPR as NAME` can be `EXPR`.
f(x=EXPR)

# And also this is passible.
if (EXPR as NAME).method(): ...

# The `EXPR` in `EXPR as NAME` is matched as long as possible which means
if 0 < 1 as x: ...

# is interpreted as
if (0 < 1) as x: ...

# not
if 0 < (1 as x): ...

# but also `EXPR` is separated by `,` which means
EXPR_0, EXPR_1 as NAME

# is interpreted as
EXPR_0, (EXPR_1 as NAME)

# rather than
(EXPR_0, EXPR_1) as NAME

# TODO even when used `as` assignment expression in list comprehension,
# you can apply the same rules above first by putting it to `for` loop form.

# There is no equivalence to type annotation and augmented assignment.

= assignment statement

TODO

  • Mutable / imutable objects and call by object mechanism

import statement

TODO The statements below should be allowed?

import NAME_0 as NAME_1

import NAME_0 as NAME_1.NAME_2

import NAME_0 as NAME_1[n]

from MODULE import NAME_0 as *NAME_1  # when NAME_0 is iterable

with statement

  • with statement will no longer responsible for passing returned value from __enter__ to the right hand of as in its statement and merely call __enter__ when enter the statement and __exit__ when exit from it.
  • Context manager can be renamed simply to context since it will no longer be manager but context itself. Context object has status of the context and encapsulates it.

except clause

  • except statement will no longer responsible for passing instance of the right hand of as in its statement.
  • Exceptions must be instanciated and also it must be confirmed otherwise except statement could rewrite the class globally.

Convert := expression into as one

TODO Converter to be provided.

Reference implementation

WIP https://github.com/rnarkk/cpython/tree/asae

Standard libraries by Victor Stinner

https://twitter.com/victorstinner/status/1014988580282912770?s=21

Before PEP 572

while True:
    line = fp.readline()
    if not line:
        break
    m = define_rx.match(line)
    if m:
        n, v = m.group(1, 2)
        try:
            v = int(v)
        except ValueError:
            pass
        vars[n] = v
    else:
        m = undef_rx.match(line)
        if m:
            vars[m.group(1)] = 0
    return vars

After PEP 572 (as version)

while fp.readline() as line:
    if define_rx.match(line) as m:
        n, v = m.group(1, 2)
        try:
            v = int(v)
        except ValueError:
            pass
        vars[n] = v
    elif undef_rx.match(line) as m:
        vars[m.group(1)] = 0
    return vars

After PEP 572 (:= version)

while (line := fp.readline()):
    if (m := define_rx.match(line)):
        n, v = m.group(1, 2)
        try:
            v = int(v)
        except ValueError:
            pass
        vars[n] = v
    elif (m := undef_rx.match(line)):
        vars[m.group(1)] = 0
    return vars
@rinarakaki
Copy link
Author

@rinarakaki
Copy link
Author

rinarakaki commented Nov 11, 2018

'as' should be scoped? How about import module as mod?

@rinarakaki
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment