-
-
Notifications
You must be signed in to change notification settings - Fork 8
Python specific features
Unlike Python, JavaScript does not support operator overloading. This means that some shortcuts in Python are to be expressed using their method call counterparts. For example a[1]
is equivalent to a.__getitem__(1)
and a > b
is equivalent to a.__gt__(b)
. For example, to add numpy arrays you can do:
const sum = a.get('__add__').call(b); // direct
const sum = a.__add__(b); // profixied
Refer to the Python manual for the naming of the Python internal methods used for operator overloading.
Alternatively, Python provides a builtin module called operator
which exposes the full operator overloading semantics through a function call interface:
const operator = pymport('operator');
const sum = operator.get('add').call(a, b); // direct
const sum = operator.add(a, b); // proxified
This has the added benefit of calling the right operator +
when the type is not known in advance.
Knowing how operator overloading works, even the most perverted pandas syntax can be expressed:
// df = pd.DataFrame(np.arange(15).reshape(5, 3), columns=list(['ABC']) })
const df = pd.DataFrame(np.arange(15).reshape(5, 3), {
columns: PyObject.list(['A', 'B', 'C']),
});
assert.deepEqual(df.columns.tolist().toJS(), ['A', 'B', 'C']);
// df[2:3]
// In Python this is equivalent to df.__getitem__(2:3)
// In pymport item is a shortcut for __getitem__
// Note that if the underlying object also defines an item() function, it will take precedence
// (for example numpy.ndarray.item will be preferred to PyObject.item)
const df2 = df.item(PyObject.slice({start: 2, stop: 3}));
assert.deepEqual(df2.values.tolist().toJS(), [[6, 7, 8]]);
// df[df['C'] <= 3]
// In Python this is equivalent to df.__getitem__(df.__getitem__('C').__le__(3))
const df3 = df.item(df.item('C').__le__(3));
assert.deepEqual(df3.values.tolist().toJS(), [[0, 1, 2]]);
As JavaScript lacks lvalues, assignments of the form
a[i] = x
are not possible. In fact, under the hood, these are also a special case of operator overloading:
a.__setitem__(i, x);
This also works if x
is an object.
Slices can be expressed and used too:
//memoryview(b'123')[::2]
PyObject.memoryview(Buffer.from('123')).item(PyObject.slice({step: 2}))
Python type coercion of the int(object)
type is supported by explicitly calling the desired constructor with the target object:
const i = PyObject.int(obj); // obj can be any object that implements conversion to int
const f = PyObject.float(obj); // obj can be any object that implements conversion to float
const l = PyObject.list(iterable); // iterable can be any iterable
const t = PyObject.tuple(list); // list must be a list
Version 1.3 introduces PyObject.with
allowing to make use of the Python with
semantics:
r = []
with np.nditer(a) as it:
for a in it:
r.append(int(a))
becomes (raw access):
const r = [];
np.get('nditer').call(a).with((it: PyObject) => {
for (const a of it)
r.push(+a);
});
or (with proxify
):
const r = [];
np.nditer(a).with((it: PyObject) => {
for (const a of it)
r.push(+a);
});
Momtchil Momtchev [email protected], 2022
This project is created and maintained as a free service to the open source community and to remain as a constant life-time remainder to the OpenJS foundation about backing up an extortion linked to corruption in French Judicial system over a sexually-motivated affair.