desugar
desugar copied to clipboard
Unravelling Python source code
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
obj.attr➠builtins.getattr(obj, "attr")(includingobject.__getattribute__())a + b➠operator.__add__(a, b)a - b➠operator.__sub__(a, b)a * b➠operator.__mul__(a, b)a @ b➠operator.__matmul__(a, b)a / b➠operator.__truediv__(a, b)a // b➠operator.__floordiv__(a, b)a % b➠operator.__mod__(a, b)a ** b➠operator.__pow__(a, b)a << b➠operator.__lshift__(a, b)a >> b➠operator.__rshift__(a, b)a & b➠operator.__and__(a, b)a ^ b➠operator.__xor__(a, b)a | b➠operator.__or__(a, b)a += b➠a = operator.__iadd__(a, b)a -= b➠a = operator.__isub__(a, b)a *= b➠a = operator.__imul__(a, b)a @= b➠a = operator.__imatmul__(a, b)a /= b➠a = operator.__itruediv__(a, b)a //= b➠a = operator.__ifloordiv__(a, b)a %= b➠a = operator.__imod__(a, b)a **= b➠a = operator.__ipow__(a, b)a <<= b➠a = operator.__ilshift__(a, b)a >>= b➠a = operator.__irshift__(a, b)a &= b➠a = operator.__iand__(a, b)a ^= b➠a = operator.__ixor__(a, b)a |= b➠a = operator.__ior__(a, b)~ a➠operator.__invert__(a)- a➠operator.__neg__(a)+ a➠operator.__pos__(a)a == b➠operator.__eq__(a, b)(includingobject.__eq__())a != b➠operator.__ne__(a, b)(includingobject.__ne__())a < b➠operator.__lt__(a, b)a <= b➠operator.__le__(a, b)a > b➠operator.__gt__(a, b)a >= b➠operator.__ge__(a, b)a is b➠operator.is_(a, b)a is not b➠operator.is_not(a, b)not a➠operator.not_(a)a in b➠operator.__contains__(b, a)a not in b➠operator.not_(operator.__contains__(b, a))a or b➠_temp if (_temp := a) else ba and b➠_temp if not (_temp := a) else bimport a.b➠a = __import__('a.b', globals(), locals())import a.b as c➠c = __import__('a', globals(), locals(), ['b'], 0).bfrom .a import b➠b = __import__('a', globals(), locals(), ['b'], 1).bfrom .a import b as c➠c = __import__('a', globals(), locals(), ['b'], 1).bassert ...➠ see below (post)for ...➠ see below (includingbuiltins.iter()andbuiltins.next())pass➠"pass"with ...➠ see below (post)async def ...➠ see below (post)await ...➠desugar.builtins._await(...)async for➠ see below (includingbuiltins.aiter()andbuiltins.anext())async with➠ see below (post)(c for b in a)➠ see below (post)[c for b in a]➠list(c for b in a){c for b in a}➠set(c for b in a){c: d for b in a}➠dict((c, d) for b in a)[a, b]➠list((a, b))(includes iterable unpacking){a, b}➠set((a, b))(includes iterable unpacking)(a, b)) ➠(lambda *args: args)(a, b)(includes iterable unpacking){a: b, c: d}) ➠dict(((a, b), (c, d)))(include dictionary unpacking)@decorator➠ see below (post)break➠ see below (post)continue➠ see below (post)elseclause onwhile➠ see below (post)elifandelseclauses onif➠ see below (post)elseclause ontry➠ see below (post)finallyclause ontry➠ see below (post)raise A from B➠ see below (post)x[A, B]➠type(x).__getitem__(x, (A, B))x[A, B] = C➠type(x).__setitem__(x, (A, B), C)del x[A, B]➠type(x).__delitem__(x, (A, B))A:B:C➠slice(A, B, C)4+3j➠complex(4, 3)True➠bool(1)False➠bool(0)None➠ see below (post)b"ABC"➠bytes([65, 66, 67])"ABC"➠bytes([65, 66, 67]).decode("utf-8")...➠Ellipsisclass A: ...➠ see below (post).;` ➠ newline plus proper indentationif ...: ...➠ see below (post)a := bsee the postlambda a: b➠ see below (post)global A; A = 42➠getattr(dict, "__setitem__")(globals(), "A", 42)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
Keywords
Taken from the keyword module.
Nothing; all unravelled!
Expressions
Statements
Tokens
Taken from the token module.