Skip to content

Latest commit

 

History

History
644 lines (514 loc) · 22.8 KB

README.md

File metadata and controls

644 lines (514 loc) · 22.8 KB

desugar

Unravelling Python's syntactic sugar source code.

There are accompanying blog posts to go with all of the code in this repository.

Unravelled syntax

  1. obj.attrbuiltins.getattr(obj, "attr") (including object.__getattribute__())
  2. a + boperator.__add__(a, b)
  3. a - boperator.__sub__(a, b)
  4. a * boperator.__mul__(a, b)
  5. a @ boperator.__matmul__(a, b)
  6. a / boperator.__truediv__(a, b)
  7. a // boperator.__floordiv__(a, b)
  8. a % boperator.__mod__(a, b)
  9. a ** boperator.__pow__(a, b)
  10. a << boperator.__lshift__(a, b)
  11. a >> boperator.__rshift__(a, b)
  12. a & boperator.__and__(a, b)
  13. a ^ boperator.__xor__(a, b)
  14. a | boperator.__or__(a, b)
  15. a += ba = operator.__iadd__(a, b)
  16. a -= ba = operator.__isub__(a, b)
  17. a *= ba = operator.__imul__(a, b)
  18. a @= ba = operator.__imatmul__(a, b)
  19. a /= ba = operator.__itruediv__(a, b)
  20. a //= ba = operator.__ifloordiv__(a, b)
  21. a %= ba = operator.__imod__(a, b)
  22. a **= ba = operator.__ipow__(a, b)
  23. a <<= ba = operator.__ilshift__(a, b)
  24. a >>= ba = operator.__irshift__(a, b)
  25. a &= ba = operator.__iand__(a, b)
  26. a ^= ba = operator.__ixor__(a, b)
  27. a |= ba = operator.__ior__(a, b)
  28. ~ aoperator.__invert__(a)
  29. - aoperator.__neg__(a)
  30. + aoperator.__pos__(a)
  31. a == boperator.__eq__(a, b) (including object.__eq__())
  32. a != boperator.__ne__(a, b) (including object.__ne__())
  33. a < boperator.__lt__(a, b)
  34. a <= boperator.__le__(a, b)
  35. a > boperator.__gt__(a, b)
  36. a >= boperator.__ge__(a, b)
  37. a is boperator.is_(a, b)
  38. a is not boperator.is_not(a, b)
  39. not aoperator.not_(a)
  40. a in boperator.__contains__(b, a)
  41. a not in boperator.not_(operator.__contains__(b, a))
  42. a or b_temp if (_temp := a) else b
  43. a and b_temp if not (_temp := a) else b
  44. import a.ba = __import__('a.b', globals(), locals())
  45. import a.b as cc = __import__('a', globals(), locals(), ['b'], 0).b
  46. from .a import bb = __import__('a', globals(), locals(), ['b'], 1).b
  47. from .a import b as cc = __import__('a', globals(), locals(), ['b'], 1).b
  48. assert ... ➠ see below (post)
  49. for ... ➠ see below (including builtins.iter() and builtins.next())
  50. pass"pass"
  51. with ... ➠ see below (post)
  52. async def ... ➠ see below (post)
  53. await ...desugar.builtins._await(...)
  54. async for ➠ see below (including builtins.aiter() and builtins.anext())
  55. async with ➠ see below (post)
  56. (c for b in a) ➠ see below (post)
  57. [c for b in a]list(c for b in a)
  58. {c for b in a}set(c for b in a)
  59. {c: d for b in a}dict((c, d) for b in a)
  60. [a, b]list((a, b)) (includes iterable unpacking)
  61. {a, b}set((a, b)) (includes iterable unpacking)
  62. (a, b)) ➠ (lambda *args: args)(a, b) (includes iterable unpacking)
  63. {a: b, c: d}) ➠ dict(((a, b), (c, d))) (include dictionary unpacking)
  64. @decorator ➠ see below (post)
  65. break ➠ see below (post)
  66. continue ➠ see below (post)
  67. else clause on while ➠ see below (post)
  68. elif and else clauses on if ➠ see below (post)
  69. else clause on try ➠ see below (post)
  70. finally clause on try ➠ see below (post)
  71. raise A from B ➠ see below (post)
  72. x[A, B]type(x).__getitem__(x, (A, B))
  73. x[A, B] = Ctype(x).__setitem__(x, (A, B), C)
  74. del x[A, B]type(x).__delitem__(x, (A, B))
  75. A:B:Cslice(A, B, C)
  76. 4+3jcomplex(4, 3)
  77. Truebool(1)
  78. Falsebool(0)
  79. None ➠ see below (post)
  80. b"ABC"bytes([65, 66, 67])
  81. "ABC"bytes([65, 66, 67]).decode("utf-8")
  82. ...Ellipsis
  83. class A: ... ➠ see below (post) . ;` ➠ newline plus proper indentation
  84. if ...: ... ➠ see below (post)
  85. a := b see the post
  86. lambda a: b ➠ see below (post)
  87. global A; A = 42getattr(dict, "__setitem__")(globals(), "A", 42)
  88. del A ➠ see below (post)

assert ...

With message

assert a, b

if __debug__:
    if not a:
        raise AssertionError(b)

Without a message

assert a

if __debug__:
    if not a:
        raise AssertionError

for ...

Without else

for a in b:
    c

_iter = iter(b)
while True:
    try:
        a = next(_iter)
    except StopIteration:
        break
    else:
        c
del _iter

With else

for a in b:
    c
else:
    d

_iter = iter(b)
_looping = True
while _looping:
    try:
        a = next(_iter)
    except StopIteration:
        _looping = False
        continue
    else:
        c
else:
    d
del _iter, _looping

with ...

with a as b:
    c

_enter = type(a).__enter__
_exit = type(a).__exit__
b = _enter(a)

try:
    c
except:
    if not _exit(a, *sys.exc_info()):
        raise
else:
    _exit(a, None, None, None)

async def ...

async def spam():
    ...

@types.coroutine
def spam():
    ...

async for ...

Without else

async for a in b:
    c

_iter = aiter(b)
while True:
    try:
        a = await anext(_iter)
    except StopAsyncIteration:
        break
    else:
        c
del _iter

With else

async for a in b:
    c
else:
    d

_iter = aiter(b)
_looping = True
while _looping:
    try:
        a = await anext(_iter)
    except StopAsyncIteration:
        _looping = False
        continue
    else:
        c
else:
    d
del _iter, _looping

async with ...

async with a as b:
    c

_enter = type(a).__aenter__
_exit = type(a).__aexit__
b = await _enter(a)

try:
    c
except:
    if not await _exit(a, *sys.exc_info()):
        raise
else:
    await _exit(a, None, None, None)

(c for b in a)

(c for b in a)

def _gen_exp(_leftmost_iterable):
    for b in _leftmost_iterable:
        yield c

_gen_exp(a)

@decorator

@decorator
def func():
    ...

def func():
    ...

_temp_func_name = func
del func

func = decorator(_temp_func_name)

break

while x:
    break

class _BreakStatement(Exception):
    pass

try:
    while x:
        raise _BreakStatement
except BreakStatement:
    pass

continue

while x:
    continue

class _ContinueStatement(Exception):
    pass

while x:
    try:
        raise _ContinueStatement
    except ContinueStatement:
        pass

else clause on a loop

while x:
    break
else:
    ...

class _BreakStatement(Exception):
    pass

try:
    while x:
        raise _BreakStatement
except _BreakStatement:
    pass
else:
    ...

if

if A:
    B

class _Done(Exception):
    pass

try:
    while A:
        B
        raise _Done
except _Done:
    pass

elif/else on an if statement

if A:
    B
elif C:
    D
else:
    E

_B_ran = _D_ran = False
if A:
    _B_ran = True
    B
if not _B_ran and C:
    _D_ran = True
    D
if not (_B_ran or _D_ran):
    E

try

else

try:
    A
except:
    B
else:
    C

_A_finished = False
try:
    A
    _A_finished = True
except:
    B
if _A_finished:
    C

finally

try:
    A
except Exception:
    B
finally:
    C

try:
    try:
        A
    except Exception:
        B
except BaseException:
    C
    raise
C

raise A from B

raise A from B

_raise = A
if isinstance(_raise, type) and issubclass(_raise, BaseException):
        _raise = _raise()
elif not isinstance(_raise, BaseException):
    raise TypeError("exceptions must derive from BaseException")

_from = B
if isinstance(_from, type) and issubclass(_from, BaseException):
        _from = _from()
if _from is not None:
    _raise.__cause__ = _from

raise _raise

None

None

def _None():
    pass

_None()

class

class Example(SuperClass):
  """Docstring."""
  a: int = 3
  def c(self): return 42

def _exec_Example(_ns):
    _temp_ns = {}

    _temp_ns["__module__"] = _ns["__module__"] = __name__
    _temp_ns[__"qualname__"] = _ns["__qualname__"] = "Example"
    _temp_ns["__doc__"] = _ns["__doc__"] = """Docstring."""
    _temp_ns["__annotations__"] = _ns["__annotations__"] = {"a": int}

    _temp_ns["a"] = _ns["a"] = 3

    def _method_c(self):
        return 42
    _method_c.__name__ = "c"
    _method_c.__qualname__ = "Example.c"
    temp_ns["c"] = _ns["c"] = _method_c
    del _method_c

def _class_Example():
    # Resolving MRO entries.
    bases = types.resolve_bases((SuperClass, ))
    # Determining the appropriate metaclass **and**
    # preparing the class namespace.
    meta, ns, kwds = types.prepare_class("Example", bases)
    # Executing the class body.
    _exec_Example(ns)
    # Creating the class object.
    cls = meta("Example", bases, ns)
    ## Class decorators, if there were any.
    ## Make the namespace read-only.
    cls.__dict__ = read_only_proxy(ns)

    return cls

 Example = _class_Example()

lambda

lambda A: B

def _lambda(A):
    return B
_lambda.__name__ = "<lambda>"

del

del A

Local

_DELETED = object()

# `del A`
A = _DELETED
# Referencing `A`
if A is _DELETED:
    raise UnboundLocalError("cannot access local variable 'A' where it is not associated with a value")

Global

try:
    gettattr(globals(), "__delitem__")("A")
except KeyError:
    raise NameError("name 'A' is not defined")

Syntax that can't be unravelled

Summary post

Keywords

Taken from the keyword module.

Nothing; all unravelled!

Expressions

  1. yield

Statements

  1. def

  2. nonlocal

  3. return

  4. try/except

  5. while

Tokens

Taken from the token module.

  1. =

  2. () for calls

  3. ,

Literals

  1. Integers