Implicit lambdas with placeholder notation and code generation
Project description
Implicit lambdas
This package adds support for implicit lambdas, so you can write map(_ + 5, a_list) instead of map(lambda x: x + 5, a_list).
The code uses Python 3.7 features for brevity. The package could easily be made to work with earlier version. Please submit an issue if there is need.
Implicit lambdas are implemented using code generation. They are as fast as regular lambdas when running python with -O to enable optimizations.
--------------------------------------------- benchmark: 3 tests -----------------------------------
Name (time in ns) Mean StdDev Median OPS (Mops/s)
----------------------------------------------------------------------------------------------------
test_normal_lambda 196.3468 (1.01) 140.7775 (2.32) 166.9600 (1.0) 5.0930 (0.99)
test_il_lambda 196.6705 (1.01) 113.9049 (1.88) 171.6000 (1.03) 5.0846 (0.99)
test_op_chain 195.0673 (1.0) 60.6268 (1.0) 176.2300 (1.06) 5.1264 (1.0)
----------------------------------------------------------------------------------------------------
il_lambda uses implicit lambdas. normal_lambda uses a regular lambda. op_chain uses functools.partial and the operator module.
Without -O, lambdas with a more verbose repr are created:
assert repr(_ + 5) == "<LambdaDSL: lambda x: (x + 5) @ {}>"
This results in up to 20% slower execution for very simple expressions. (A new type is created on the fly to hold the expression and resolving a call using a custom __call__ is sufficient to incur such a penalty.)
For more complex expressions, the overhead will become negligible.
Python expressions are fully wrapped, including index operations [] (using __getitem__), member access (using __getattribute__) and any calls (__calls). This results in great flexibility.
To disambiguate between calls within the lambda and calling a lambda, implicit lambdas have to be explicitly converted into a callable/regular Python lambda.
to_lambda turns an implicit lambda expression into a Python lambda.
auto_lambda adds support for implicit lambdas to existing functions that take callables.
Wrapped versions of builtin, functools and itertools are provided out-of-the-box.
Installation
To install using pip, use:
pip install implicit_lambda
To run the tests, use:
python setup.py test
Example
To enable implicit lambdas, import placeholder symbols as needed and import wrapped builtin functions to use implicit lambdas interchangably with regular ones.
Usually, to_lambda and other helper functions don't need to be called.
from implicit_lambda import _, x, y, to_lambda
from implicit_lambda.builtins import map
Implicit lambda provides wrappers around all common builtins.
a_list = list(range(10))
mapped_list = map(_ + 2, a_list)
assert list(mapped_list) == list(range(2, 12))
There are also wrappers that turn builtins into lazy functions. A wrapped function provides a ._ version that can be used within an implicit lambda.
mapper = to_lambda(map._(x + 2, _))
mapped_list = mapper(a_list)
assert list(mapped_list) == list(range(2, 12))
Implicit lambdas supports nested expressions
mapped_list = map((_ << 3) * 3 - 23 * _ + 2, a_list)
assert list(mapped_list) == list(range(2, 12))
More useful reprs are available in debug mode (just don't use -O when running python):
another_lambda = to_lambda((_ << 3) * 3 - 23 * _ + 2)
assert repr(another_lambda) == "<lambda x: ((((x << 3) * 3) - (23 * x)) + 2) @ {}>"
or:
assert (repr((_ << 3) * 3 - 23 * _ + 2) ==
"<LambdaDSL: lambda x: ((((x << 3) * 3) - (23 * x)) + 2) @ {}>)"
Implicit lambdas support multiple arguments, too:
assert to_lambda(x * y)(5, 3) == 15
Performance measurement
Run
python -O -m pytest -k test_performance --benchmark-warmup=on --benchmark-autosave --benchmark-disable-gc
Advanced features
Some operators are not supported directly because returning LambdaDSL would not work (__bool__, __contains__) or it could cause issues (__repr__).
There are wrapped builtins (bool._ and repr._) that can be used instead, or helper functions like contains and not_contains that are exported from implicit_lambda.
Additionally, implicit_lambda supports custom arg_resolvers that map placeholders to lambda function arguments. By default, strict_resolver is used. There is also from_allowed_signatures, which picks the first argument signature that contains all used placeholder arguments, and flexible_args, which supports more than a required number of arguments and a custom partial ordering of placeholders in the case of conflicts.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file implicit_lambda-0.4.1.tar.gz.
File metadata
- Download URL: implicit_lambda-0.4.1.tar.gz
- Upload date:
- Size: 22.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4a918ce90b82804fcccc5d9060a0831e5fa73320c7d76298167436b240a09c5
|
|
| MD5 |
a60971af37e6c7b063e7473681b62d5d
|
|
| BLAKE2b-256 |
84da1f139052ab3f91f69ac7d30255e875975fe99028f6fc8621b81cb7a6e9ca
|
File details
Details for the file implicit_lambda-0.4.1-py3-none-any.whl.
File metadata
- Download URL: implicit_lambda-0.4.1-py3-none-any.whl
- Upload date:
- Size: 24.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be064a1b1fdbc9247d36421175c8e9b028112f88f532485bf5c265d347049d22
|
|
| MD5 |
8384ac58cf2c6c10381100c24d1548d3
|
|
| BLAKE2b-256 |
797ab9b38eaee17e34366b7e1e0c124abd04a5da200fdcc21a0f59ef0e5dd1e4
|