N
Nick Coghlan
Mike said:Personally, I'd love a language feature that let you create a function
that didn't evaluate arguments until they were actually used - lazy
evaluation. That lets you write the C ?: operator as a function, for
a start.
The basic idea is to just specify that those arguments must be zero-argument
callables, and only call them if you actually need them.
The rest of this message is something that just occured to me that could make
that style 'prettier' (if lambda looks as ugly in function calls to you as it
does to me). It's completely untested, though
First, some utility functions to convert values and functions with arguments to
a lazily evaluable function:
def lazy(x, *args, **kwds):
"""Executes x(*args, **kwds) when called"""
if args or kwds:
return lambda : x(*args, **kwds)
else:
return x # No arguments, so x must be callable by itself
def lazyval(x):
"""Allows passing a normal value as a deferred argument"""
return lambda : x
def lazycall(x, *args, **kwds):
"""Executes x(*args, **kwds)() when called"""
return lambda : x(*args, **kwds)()
For literals, their constructor provides a zero-argument callable equivalent:
[] -> list
(,) -> tuple
{} -> dict
0 -> int
"" -> str
0L -> long
And the operator module provides a way to delay most operations:
import operator
lazy(operator.mul, x, y) # Delayed x * y
lazy(operator.itemgetter(i), x) # Delayed x
lazy(operator.attrgetter("a"), x) # Delayed x.a
lazycall(lazy(operator.attrgetter("a"), x)) # Delayed x.a()
(That last example is why I added lazycall() to the utility functions)
Then you can write a function called 'select':
def select(selector, *args, **kwds):
if kwds:
return kwds[selector]()
else:
return args[selector]()
And one called 'either' (since 'if' is taken and using 'select' would get the
true case and the false case back to front):
def either(pred, true_case, false_case):
if pred:
return true_case()
else:
return false_case()
And use them as follows:
select(selector, list, lazyval(mylist), lazy(eval, expr, globals(), locals()))
select(selector, c1 = list, c2 = lazyval(mylist), c3 = lazy(myfunc, a, b, c))
either(condition, guarded_operation, lazyval(default_case))
Huh. I think I like the idea of lazy() much better than I like the current PEP
312. There must be something wrong with this idea that I'm missing. . .
Cheers,
Nick.