The bi-directional conversion between Prolog and Python terms is 
summarized in the table below. For compatibility with Prolog 
implementations without native dicts we support converting the
{k1:v1, k2:v2, ...} to dicts. Note that {k1:v1, k2:v2} 
is syntactic sugar for {}(','(:(k1,v1), :(k2,v2))). We 
allow for embedding this in a py(Term) such that, with py 
defined as prefix operator, py{k1:v1, k2:v2} is 
both valid syntax as SWI-Prolog dict as as ISO Prolog compliant term and 
both are translated into the same Python dict. Note that {} 
translates to a Python string, while py({}) translates into 
an empty Python dict.
By default we translate Python strings into Prolog atoms. Given we 
support strings, this is somewhat dubious. There are two reasons for 
this choice. One is the pragmatic reason that Python uses strings both 
for identifiers and arbitrary text. Ideally we'd have the first 
translated to Prolog atoms and the latter to Prolog strings, but, 
because we do not know which strings act as identifier and which as just 
text, this is not possible. The second is to improve compatibility with 
Prolog systems that do not support strings. Note that py_call/3 
and py_iter/3 
provide the option
py_string_as(Type) to obtain strings in an alternative 
format, where Type is one of atom, string, codes 
or chars.
| Prolog | Python | Notes | |
| Variable | ⟶ | - | (instantiation error) | 
| Integer | ⟺ | int | Supports big integers | 
| Rational | ⟺ | fractions.Fraction() | |
| Float | ⟺ | float | |
| @(none) | ⟺ | None | |
| @(true) | ⟺ | True | |
| @(false) | ⟺ | False | |
| Atom | ⟵ | enum.Enum() | Name of Enum instance | 
| Atom | ⟺ | String | Depending 
on py_string_asoption | 
| String | ⟶ | String | |
| string(Text) | ⟶ | String | Text is an atom, string, code- or char list | 
| #(Term) | ⟶ | String | stringify using write_canonical/1 if not atomic | 
| prolog(Term) | ⟶ | janus.Term() | Represents any Prolog term | 
| Term | ⟵ | janus.Term() | |
| List | ⟶ | List | |
| List | ⟵ | Sequence | |
| List | ⟵ | Iterator | Note that a Python Generator is an Iterator | 
| py_set(List) | ⟺ | Set | |
| -() | ⟺ | () | Python empty Tuple | 
| -(a,b, ... ) | ⟺ | (a,b, ... ) | Python Tuples. Note that a Prolog pair A-Bmaps to a Python (binary) tuple. | 
| Dict | ⟺ | Dict | Default for SWI-Prolog | 
| {k:v, ...} | ⟺ | Dict | Compatibility 
when using py_dict_as( | 
| py({}) | ⟵ | {} | Empty 
dict when using py_dict_as( | 
| {k:v, ...} | ⟶ | Dict | Compatibility (see above) | 
| py({k:v, ...}) | ⟶ | Dict | Compatibility (see above) | 
| eval(Term) | ⟶ | Object | Evaluate Term as first argument of py_call/2 | 
| py_objblob | ⟺ | Object | Used for any Python object not above | 
| Compound | ⟶ | - | for any term not above (type error) | 
The interface supports unbounded integers and rational numbers. Large integers (> 64 bits) are converted using a hexadecimal string as intermediate. SWI-Prolog rational numbers are mapped to the Python class fractions:Fraction.1Currently, mapping rational numbers to fractions uses a string as intermediate representation and may thus be slow.
The conversion #(Term) allows passing anything as a Python string. If
Term is an atom or string, this is the same as passing the 
atom or string. Any other Prolog term is converted as defined by
write_canonical/1. 
The conversion prolog(Term) creates an instance of janus.Term(). 
This class encapsulates a copy of an arbitrary Prolog term. The 
SWI-Prolog implementation uses the
PL_record() and PL_recorded() functions to store and 
retrieve the term. Term may be any Prolog term, including blobs,
attributed variables. Cycles and subterm sharing in
Term are preserved. Internally, janus.Term() 
is used to represent Prolog exeptions that are raised during the 
execution of
janus.query_once() or janus.query().
Python Tuples are array-like objects and thus map best to a Prolog 
compound term. There are two problems with this. One is that few systems 
support compound terms with arity zero, e.g., f and many 
systems have a limit on the arity of compound terms. Using 
Prolog comma lists, e.g., (a,b,c) does not 
implement array semantics, cannot represent empty tuples and cannot 
disambiguate tuples with one element from the element itself. We settled 
with compound terms using the -