It works pretty much the same as query_once(). It return a Python iterator. Each element of this iterator is a dict, just like the one returned by query_once(). So, to get all Y for a certain X in p(X,Y), use
for d in janus.query("p(X,Y)", {'X':x}):
print(d['Y'])
Or, if you want all Ys in a list
>>> [d['Y'] for d in janus.query("p(X,Y)", {'X':1})]
['a', 'b']
Why not? Note that the number of answer to a Prolog query may be huge or even infinite. Using a loop you can aggregate/filter/… them one by one and if you are satisfied (you don’t want any more), you can use break
.
The returned object refers to a non-deterministic Prolog query that you can consume only once. Note that you generally do not want to assign the iterator to something as that will avoid it being finalized. The __del__()
method of the iterator terminates the Prolog query. Failure to do so easily leaves Prolog in an inconsistent state. So, use it in list comprehension or as
for d in janus.query(...):
<process d>
<optionally break if you do not want all answers>
It provides an interface that allows doing some simple things easier (for the Python coder) and faster. E.g. to get the Y from p(X,Y) again, we can do
>>> janus.apply_once("user", "p", 1)
"a"
Or
>>> [*janus.apply("user", "p", 1)]
["a", "b"]
It is simpler because it returns only a single value, so we do not need a dict. The price is that you need a predicate that can accept N input arguments as arguments 1…N that receive the Prolog values that result from the default Python → Prolog data conversion and the predicate must produce exactly one output argument that is the last and suitable for conversion to Python data. In general that means you’ll often have to define a Prolog predicate that massages input and output to suit the needs at the Python side. Given that though, calling it from Python is easier and the overhead is about 5 times smaller (+/- 300K calls/sec for query_once() and 1.5M calls/sec for apply_once(), doing something really trivial).