C
Carl Banks
Bengt said:Well, according to the argument, we would be dealing with an
optimizing compiler, so presumably the compiler would see a name
DEFAULT_LIST and simply compile a call-time binding of param to
whatever DEFAULT_LIST was bound to, and not bother further. It could
notice that the DEFAULT_LIST binding was still undisturbed, and that
it was to an immutable tuple with no mutable elements, which ISTM is
effectively a constant, but that analysis would be irrelevant, since
the semantics would be copying pre-existing binding (which is pretty
optimized anyway).
The dict literal looks to me to be made up entirely of immutable
keys and values, so the value of that literal expression seems to me
to be a constant. If you had call time evaluation, you would be
evaluating that expression each time, and the result would be a
fresh mutable dict with that constant initial value each time. ISTM
that could be optimized as
param=private_dict_compile_time_created_from_literal.copy(). OTOH,
if you used a pre-computed binding like DEFAULT_LIST, and wrote
SHARED_DICT = {'1': 'A', '2': 'B', '3': 'C', '4': 'D'}
def func(param=SHARED_DICT):
pass
then at def-time the compiler would not see the literal, but rather
a name bound to a mutable dict instance. The call-time effect would
be to bind param to whatever SHARED_DICT happened to be bound to,
just like for DEFAULT_LIST. But the semantics, given analysis that
showed no change to the SHARED_DICT _binding_ before the func call,
would be to share a single mutable dict instance. This is unlike the
semantics of
def func(param={'1': 'A', '2': 'B', '3': 'C', '4': 'D'}):
pass
which implies a fresh mutable dict instance bound to param, with the
same initial value (thus "constant" in a shallow sense at least,
which in this case is fully constant).
Good analysis.
I'd worry a bit about the meaning of names used in initialization expressions
if their values are to be looked up at call time. E.g., do you really want
a = 2
def foo(x=a): print 'x =', x
...
...
a = 'eh?'
foo()
to print 'eh?' By the time you are past a lot of ...'s, ISTM the
code intent is not so clear. But you can make dynamic access to the
current a as a default explicit by
class Defer(object):
def __init__(self, lam): self.lam = lam
def foo(x=Defer(lambda:a)):
if isinstance(x, Defer): x=x.lam()
print 'x =', x
The semantics are different. I'd prefer to have the best of both
worlds and be able to do both, as now, though I might not object to
some nice syntactic sugar along the lines suggested by OP Stian
S?iland. E.g., short spelling for the above Defer effect:
def foo(x:a): print 'x =', x
All good points; doing something like this always seems to have
further repurcussions.