On Sun, Oct 24, 2021 at 01:16:02PM +1100, Chris Angelico wrote:
> What I'm more often seeing is cases that are less obviously a
> late-binding, but where the sentinel is replaced with the "real" value
> at the point where it's used, rather than up the top of the function.
Got any examples you can share?
And is it really a problem if we delay the late-binding to the point
where the value is actually needed? Here's a toy example:
# Using only early binding.
def function(spam, eggs=None, cheese=None):
if eggs is None:
eggs = cheap_default()
# do stuff using eggs
...
if condition:
return result
if cheese is None:
cheese = expensive_default()
# do stuff using cheese
...
return result
The cheese parameter only gets used if the processing of spam with eggs
fails to give a result. But if cheese is used, the default is expensive.
Is it really a problem if we delay evaluating that default to the point
where it is needed?
So this would be another example where automatic late-binding wouldn't
be used. If the default is very expensive, I would stick to manual late-
binding using None, and only evaluate it as needed.
Maybe this is an argument for some sort of thunk, as in Algol, which is
only evaluated at need. Then we could just write:
# Assume late-binding with thunks.
def function(spam, eggs=cheap_default(), cheese=expensive_default()):
# do stuff using eggs
...
if condition:
return result
# do stuff using cheese
...
return result
and the thunks `cheap_default()` and `expensive_default()` will only be
evaluated *if they are actually needed*, rather than automatically
when the function is called.
To be clear about the semantics, let me illustrate. I am deliberately
not using any extra syntax for late-binding.
# early binding (the status quo)
def func(arg=expression): ...
The expression is evaluated when the def statement is run and the func
object is created.
# late binding (minus any extra syntax)
def func(arg=expression): ...
The expression is evaluated eagerly when the function is called, if and
only if the parameter arg has not been given a value by the caller.
# late binding with thunk
def func(arg=expression): ...
The expression is evaluated only if and when the body of the function
attempts to use the value of arg, if the caller has not provided a
value. So if the function looks like this:
# late binding with a thunk that delays execution until needed
def func(flag, arg=1/0):
if flag:
print("Boom!")
return arg
return None
then func(True) will print Boom! and then raise ZeroDivisionError, and
func(False) will happily return None.
I have no idea whether thunk-like functionality is workable in Python's
execution model without slowing down every object reference, but if it
is possible, there could be other really nice use-cases beyond just
function defaults.
--
Steve
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/NW63MNKO7JFQLTP7LTSJQP7W5JB72DGN/
Code of Conduct: http://python.org/psf/codeofconduct/