On 02/28/2014 09:46 PM, Steven D'Aprano wrote:
On Fri, Feb 28, 2014 at 11:17:18AM -0600, Ron Adam wrote:
Starting new thread because this bike has a different shape and color.
Yesterday I was thinking that just making the keyword lambda assignable like True, False, and None, would be enough.
You can't assign to True, False or None. (You can assign to True and False in Python 2, but shouldn't.)
I meant it the other way around.
For example... def is not assignable to anything..
D = def # won't work
T = True # works F = False N = None
L = lambda # won't work
lambda isn't an object like True, False, and None.
This morning I thought we could have in a functions definition something, like "*", and "**", to take an expression. Similar to Nicks idea with =:, but more general.
The idea is to have "***" used in def mean to take "any" call expression and not evaluate it until *** is used on it.
A function call that captures an expression may be tricky to do. Here's one approach that requires sugar when a function defined with "***" is called.
I think it would be useful to have a way to delay execution of an expression, that is to say, have a way to capture an expression for later evaluation, something more lightweight than a function, but I don't think that limiting it to inside function calls is the right approach.
The expressing part isn't limited to inside function calls.. Or wouldn't be if it was a doable idea.
Something perhaps like a thunk might be appropriate? We can*almost* do that now, since Python has a compile function:
thunk = compile("x + 3", "", "eval") # much later eval(thunk)
def thunk(***expr): return expr
def do thunks(*args): for expr in args: ***expr
start = t = time() update_timer = thunk(t = time()) show_timer = thunk(print(t-start)) show_status = thunk(do_thunks(upate_timer, show_timer))
Then as you do things, possibly in different functions as well.
... ***show_status # update t, and prints elapsed time. ... ***show_status ... ***show_status ...
Yes, it could be done with lambda too.
Here's where it differs...
So if we have this, where obj is nested expressions.
While 1: try: obj = ***obj except TypeError: break
Then the result of the obj expression, could be a callable without any conflict. Only delayed expressions would be expressed.
This was one of the properties I was looking for.
Some problems with that approach:
- You have to write the expression as a string, which means you lose any
possibility of syntax highlighting.
- The temptation is to pass some arbitrary untrusted string, which leads
to serious security implications. The argument here should be limited to an actual expression, not a string containing an expression which might have come from who knows where.
- It should be as lightweight as possible. The actual compilation of the
expression should occur at compile-time, not run-time. That implies some sort of syntax for making thunks, rather than a function call.
- Likewise actually evaluating the thunk should be really lightweight,
which may rule out a function call to eval.
- How should scoping work? I can see use-cases for flat scoping, static
scoping, dynamic scoping, and the ability to optionally provide custom globals and locals, but I have no idea how practical any of them would be or what syntax they should use.
That's where the idea I mentioned in another response to this thread comes in. Separating the namespace constructing from the code part of a function in a well defined way.
If that can be done... also pie in the sky. Then we could also evaluate an expression in a previously defined namespace. It's hypothetical, so supply your own syntax for it.
The compiler will still compile the code, so most of the work is still done at compile time. But we have these useful pieces we can take apart and put back together again. (without calling eval, or exec.)
BTW, you can do that now, but it's very hard to get right.
All of this is pie-in-the-sky at the moment, and not a serious proposal for Python 3.5.
Agree. Cheers, Ron