I am trying to define an object master
whose attribute/method decide
can be called with an expression ex
, but evaluation of that expression is postponed until some logic in decide
asks for it (and it may even not do so). So, in code like this:
master.decide(ex)
it should be possible for ex
to remain unevaluated if the logic in decide
says so. In the code, ex
stands for "arbitrary expression supplied by the client of my library." It can be as simple as 1 + 2
(where I wouldn't really care about lazy evaluation) to as complex as do_http_request().delete_record_from_database()
(where I certainly do care).
Is such a thing possible? I am flexible on the syntax side, so if a solution exists which has to involve extra operators etc. around ex
, I can consider it. But I would like ex
to remain an expression.
I was thinking about (ab)using short-circuiting operators like and
and or
, but there doesn't seem to be a way to make those return something other than a boolean value.
The best I could come up with is wrapping ex
in a lambda:
master.decide(lambda: ex)
def decide(ex):
if decide_to_do_it():
result = ex()
somehow_use(result)
Or passing it as a string and using eval
:
master.decide('ex')
def decide(ex):
if decide_to_do_it():
result = eval(ex)
somehow_use(result)
(Yes, this one would have scoping issues).
Is there perhaps a magic function, trick, or something else which would allow me to keep ex
as a plain expression?
You can define a coroutine
using yield
here
def decide():
ex=yield()
if ex:
result = ex()
somehow_use(result)
master=decide()
next(master)
master.send(ex1)
master.send(ex2)
You can pass a callable, just a function without arguments that is called when the expression needs to be evaluated.
Your lambda is one way to make such a callable, but you could just as easily pass a normal function or an instance method or whatever.
That's is the perfectly normal way to do it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With