In Peter Norvig's Lisp interpreter written in Python (http://norvig.com/lispy.html), he defines Lisp's eval
as follows:
def eval(x, env=global_env):
"Evaluate an expression in an environment."
if isa(x, Symbol): # variable reference
return env.find(x)[x]
elif not isa(x, list): # constant literal
return x
elif x[0] == 'quote': # (quote exp)
(_, exp) = x
return exp
elif x[0] == 'if': # (if test conseq alt)
(_, test, conseq, alt) = x
return eval((conseq if eval(test, env) else alt), env)
elif x[0] == 'set!': # (set! var exp)
(_, var, exp) = x
env.find(var)[var] = eval(exp, env)
elif x[0] == 'define': # (define var exp)
(_, var, exp) = x
env[var] = eval(exp, env)
elif x[0] == 'lambda': # (lambda (var*) exp)
(_, vars, exp) = x
return lambda *args: eval(exp, Env(vars, args, env))
elif x[0] == 'begin': # (begin exp*)
for exp in x[1:]:
val = eval(exp, env)
return val
else: # (proc exp*)
exps = [eval(exp, env) for exp in x]
proc = exps.pop(0)
return proc(*exps)
isa = isinstance
Symbol = str
This line in particular interests me:
return proc(*exps)
What is the asterisk in from of exps
doing exactly?
It is used to pass a variable number of arguments to a function, it is mostly used to pass a non-key argument and variable-length argument list.
It means that parameter(s) that comes after * are keyword only parameters. Consider the following: def test(delay, result=None, *, loop=None): print(delay, result, loop)
A single star means that the variable 'a' will be a tuple of extra parameters that were supplied to the function. The double star means the variable 'kw' will be a variable-size dictionary of extra parameters that were supplied with keywords.
Python has a special syntax, * (single asterisk) and ** (double asterisks), that lets you pass a variable number of arguments to a function. By convention, these are written as *args and **kwargs , but only the asterisks are important; you could equally write *vars and **vars to achieve the same result.
it unpacks the arguments
function(1,2,3) == function(*[1,2,3])
it makes it easy to use variables to pass in to functions
args = [1,2,3]
func(*args) #much nicer than func(args[0],args[1],args[2],...)
Single asterisk in before a seqable object unpacks it, like Joran showed:
In [1]: def f(*args): return args
In [2]: f(1,2,3)
Out[2]: (1, 2, 3)
In [3]: f(*[1,2,3,4])
Out[3]: (1, 2, 3, 4)
(Note a third application for *
: in function definition an asterisk indicates a variable length list of arguments, all are being packed into one list, args
, in In [1]
)
Also worth noting is that a double asterisk (**
) does a dictionary unpacking:
In [5]: def g(foo=None, bar=42): return foo,bar
In [6]: g()
Out[6]: (None, 42)
In [7]: g(*[1,2])
Out[7]: (1, 2)
In [8]: g(**{'foo': 'FOO', 'bar': 'BAR'})
Out[8]: ('FOO', 'BAR')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With