The OP wants to do this MyData.objects.filter[id>1]
.
Let's face it.
The problem is Python is greedy [eagerly evaluates expressions], not lazy like Haskell.
Watch David Beazley - Lambda Calculus from the Ground Up - PyCon 2019 for mind-bending λ thing.
Python evaluates id > 1
before calling filter
. If we can stop the evaluation for now, we can pass the expression
unevaluated to the filter
function.
But we can delay expression evaluation until required if we enclose the expression in a function. That's the idea.
The function interface would be filter[lambda: id > 1]
if we could implement it. This interface will be super versatile because any Python expression can be passed and abused.
The implementation;
if we invoke the lambda or any other function with the expression id > 1
, Python looks up the name id
in the local, enclosing, global
scope or builtins
depending on the context where the function is invoked.
If we can introduce an object with the name id
somewhere in the look-up path before Python finds id
in the builtins
we can redefine the semantics of the expression.
I'm gonna do it with eval
which evaluates expressions in the given context.
DATA = [
{'id': 1, 'name': 'brad', 'color':'red'},
{'id': 2, 'name': 'sylvia', 'color':'blue'},
]
def myfilter[a_lambda]:
return filter[lambda obj: eval[a_lambda.__code__, obj.copy[]],
DATA]
I pass a dict.copy
to eval
because eval
modifies it's globals
object.
See it in action in the context of Model
class
In [1]: class Data[Model]:
...: name = str[]
...: id = int[]
...: color = str[]
...:
In [2]: Data.objects.create[**{"id": 1, "name": "brad", "color": "red"}]
In [3]: Data.objects.create[**{"id": 2, "name": "sylvia", "color": "blue"}]
In [4]: Data.objects.create[**{"id": 3, "name": "paul", "color": "red"}]
In [5]: Data.objects.create[**{"id": 4, "name": "brandon", "color": "yello"}]
In [6]: Data.objects.create[**{"id": 5, "name": "martin", "color": "green"}]
In [7]: Data.objects.create[**{"id": 6, "name": "annie", "color": "gray"}]
In [8]: pprint[[vars[obj] for obj in Data.objects.filter[lambda: id == 1]]]
[{'color': 'red', 'id': 1, 'name': 'brad'}]
In [9]: pprint[[vars[obj] for obj in Data.objects.filter[lambda: 1