-
Notifications
You must be signed in to change notification settings - Fork 174
Description
Reported by @alandonovan
This program prints each argument in the call to f as it is evaluated.
def id(x): print(x) return x def f(*args, **kwargs): print(args, kwargs) f(id(1), id(2), x=id(3), *[id(4)], y=id(5), **dict(z=id(6)))Its results vary across all implementations:
Python2:
1 2 3 5 4 6(*args and **kwargs evaluated last)
Python3:1 2 4 3 5 6(positional args evaluated before named args)
Starlark-in-Java:1 2 3 4 5 6(lexical order)
Starlark-in-Go: crashes (github.com/google/skylark/issues/135)The spec currently says nothing about argument evaluation order. The Starlark-in-Java semantics are the cleanest of the three but are the most complicated and least efficient to implement in a compiler, which is why the Python compilers do what they do. The problem with the Java semantics is that it requires the compiler to generate code for a sequence of positional arguments, named arguments, an optional *args, more named arguments, and an optional **kwargs, and to provide the callee with a map of the terrain. By contrast, both of the Python approaches are simple to compile: Python2 always passes *args and *kwargs at the end, and Python3 always pushes the *args list before the first named.
One way to finesse the problem without loss of generality would be to specify Python2 semantics but to statically forbid named arguments after *args, such as y=id(5) in the example. (This mirrors the static check on the def statement, which requires that *args and **kwargs come last.