An expression template library for building "quick lambdas", like
5 + _1.
Any expression involving a placeholder (
_3), or a value
wrapped by the
_ function, becomes a function. For example, all of the
function calls below print out 3:
from quicklambda import * add1 = _1 + 1 print(add1(2)) add1 = 1 + _1 print(add1(2)) add1 = _2 + 1 print(add1(None, 2)) add = _1 + _2 print(add(1, 2)) add = _(1) + 2 print(add()) add1 = _(add)(_1, 1) print(add1(2))
_3 are placeholders that take on the value of
the first, second, and third arguments when the lambda expression
function is eventually called. (Extending this beyond 3 would be
trivial, but how often will you need it?)
There is currently no syntax for keyword placeholders, mostly because I haven't thought of anything good.
_ is a function that turns any value into a placeholder for
_(foo) takes on the value of
foo when the
lambda expression is eventually called. This is primarily useful
to handle cases where placeholder operator overloading doesn't
work, as described below, or where you have no placeholders
(e.g., because you're building a lambda expression with no
It should also be possible to wrap an expression with _ to turn it into a placeholder (which you would mainly do to build complex call expressions), but this generally does not work in the current version.
Because the name
_ is useless in the interactive prompt (each
time you execute an expression statement,
_ is rebound to the
value), it's also available as
_v. Which is hideous, but I
haven't thought of anything better yet.
_(foo) stores the value of
foo, not the
This should be fixable by either passing the name as a string, or by
using a different function (named what?) that uses frame hacks to
find the name of its argument, but both of those have major flaws,
so I haven't implemented either yet. If you want a function with
a mutable closure, you'll have to use
with the default value hack), not a lambda expression.
Works with a placeholder on the left. Does not work with a
placeholder on the right (even if there's also a placeholder on the
_1.foo is a function, but
foo._1 is not, and the
_(foo)._1 trick used elsewhere will not help, and neither is
_1._2. (This might be fixable; I haven't thought it through.)
Note that this includes methods as well as data attributes, but
the function returns the method, it doesn't call it. So,
_1.meth(obj) is often not what you want, but it's what you get.
(There may be some syntax that makes sense here, but I'm not sure
what it is.)
-_1 is a function.
not: Does not work (because it effectively calls
Special methods below).
^: Work, in both
directions, except that a few types do not work on the left side.
_1 + 1,
1 + _1, and
_1 + _2 are all functions. Note that
-=, etc. cannot be used, because they are not expressions.
>: Work, in both directions, with
slightly different types that don't work on the left side. Also,
1 < _1 becomes
_1 > 1, and so on.
>>: Work with the placeholder on the left. So
_1 << 1
is a function, but
1 << _1 is not. (Use
_(1) << _1.) Note that
>>= cannot be used, because they are not expressions.
: Works with the placeholder on the left. So
_1 is a
arr[_1] is not. (Use
_(arr)[_1].) Slicing works,
but a placeholder used as the start or step of a slice does not
_1[:_2] is fine, but
_1[_2:] is not). (This may be a
peculiarity of CPython, and it might change in a later version.)
Note that the set and del versions
_1 = 2 and
del _1 do
not work because they are not expressions.
(): Works with the placeholder on the left. So
_1(1) is a
foo(_1) is not. (Use
_(foo)(_1).) Certain special
functions work differently; see Special Functions below. Note that
call expressions can be confusing, because calling a placeholder
creates a function, but calling an expression made with a placeholder
calls the function. (To make a call expression function out of an
expression function, you have to wrap it in
_, which can easily
become unreadable very quickly.) Also, remember that if you wanted
foo(_1) you can usually just use
foo directly (but of course
foo(1, _1) would be a nice way to create quick partials).
in: Does not work, because the return value is forcibly converted
is: Does not work, because it's not overridable.
abs(_1) is a function.
iter: Do not work, because
they require a return value of a specific type. (Note that
len not working means that any lambda expression is considered
True in a boolean context.)
repr: Do not work, because that would cause infinite
recursion trying to print a lambda expression.
__index__: Works, but there's no function to call it with.
Any special functions defined by other stdlib modules (like
__reduce__) or third-party modules have not been
In most cases, lack of support for a special function is not a
problem, as you can
_-wrap them--or, of course, just use the
Any expression that works with a placeholder should usually also
work with an expression function, except the special case of call
expressions. And you can always handle the cases that don't with
However, this generally does not work in the current version.
If there are any missing operators, finding and adding them is an obvious goal.
Making complex expressions work, automatically and in the
_function, is on the queue.
Keyword placeholders and a better name for
_vare just waiting for me to come up with something that looks nice.
Wrapping names/closures instead of only values needs both a nice-looking syntax and an implementation that's not as horrible as the one I wrote when I last attempted this a few years ago.
The first version of this module auto-generated all of the ugly stuff in the wrapper-maker functions. I'd like to factor out the repetition if possible, or go back to the auto-generated code if not.
I think the three classes can be collapsed into two.