Module for executing Python3 code and accessing Python libraries from Perl 6.
Note that this library is largely based on the Inline::Python.
First, import necessary modules and get a reference to the _main_ module.
use Inline::Python3;
use Inline::Python3::PyModule;
# initialize the environment
start-python;
my $main = PyModule('__main__');
Let's start from some simple code:
say $main.run('5', :eval);
say $main.run("Python"', :eval);
The keyword "eval" asks the python interpreter to calculate a simple expression and return its value.
You can also use the keyword "file", which means several statements. No keyword is OK, which defaults to the "file".
Then, let's define a simple function in python world:
$main.run(q:to/PYTHON/);
def plus_int(a, b):
return a + b
PYTHON
Then you can call it in perl6 code like this:
$main.plus_int(2, 1);
Note that you cannot directly call a function/method whose name conflicts with that of any method of the perl6 class "Any". For example, if you define a function/method with the name "sum", then you cannot do this: $main.sum(x, y). The perl6 compiler will treat it as a method call of the class "Any".
There exists a way to bypass the problem:
say $main<sum>(1, 2);
Note that "$main.sum(...)" is invoking a function defined in $main, while "$main<sum>" is accessing a $main's attribute, which is a callable object.
Here follows a bit more complex example:
$main.run(q:to/PYTHON/);
class Foo:
def __init__(self, value):
self.value = value
def some_method(self, a, b):
return a + b
@staticmethod
def some_static_method():
return 666
def dump_foo(foo):
return foo.value
PYTHON
You can instantiate the python class like this:
my $foo = $main.Foo(1);
Accessing its attribute or method is quite easy:
say $foo.value
say $main.Foo(1).value;
say $main.Foo(1).some_method(3, 1);
say $main<Foo>.some_static_method;
say $main.dump_foo($main.Foo(6))
So far, all functions and class are defined in the _main_ module. But you can use other modules too.
my $string = PyModule('string');
Then you can use the string module happily:
say $string.capwords('foo bar')
You may also use python's operators:
use Inline::Python3::PyOperators;
my $pyobject = ... ;
my $pylist = ... ;
say $pyobject ?in $pylist;
Basically, unary python operators start with ??
while binary ones start with ?
. There are a few of exceptions. See the comments in PyOperator.pm6.
See more usage in t/*.t files.
Following is a runnable example, which use keras to train a cnn on the mnist dataset.
The code is based on the example from keras document.
#! /usr/bin/env perl6
use Inline::Python3;
use Inline::Python3::PyModule;
start-python;
sub np { PyModule('numpy') }
sub keras { PyModule('keras') }
my $batch-size = 128;
my $num-classes = 10;
my $epochs = 12;
my @image-dim = do {
keras.backend.image_data_format eq 'channels_first' ??
(1, 28, 28) !! (28, 28, 1)
}
my ($train, $test) = keras.datasets.mnist.load_data.list.map: -> $/ {
np.true_divide($0.reshape($0.shape[0], |@image-dim).astype('float32'), 255),
keras.utils.to_categorical($1, $num-classes)
}
my $inputs = keras.layers.Input(shape => @image-dim);
my $outputs = do given PyModule('keras.layers') {
$inputs
==> .Conv2D(32, (3, 3), :activation<relu>)()
==> .Conv2D(64, (3, 3), :activation<relu>)()
==> .MaxPooling2D(pool_size => (2,2))()
==> .Dropout(0.25)()
==> .Flatten()()
==> .Dense(128, :activation<relu>)()
==> .Dropout(0.5)()
==> .Dense($num-classes, :activation<softmax>)()
}
given keras.models.Model(:$inputs, :$outputs) {
.compile(
loss => keras.losses<categorical_crossentropy>,
optimizer => keras.optimizers.Adadelta,
metrics => ['accuracy']
);
.fit(
|$train, batch_size => $batch-size,
epochs => $epochs, verbose => 1,
validation_data => $test
);
.evaluate(|$test, verbose => 0);
}
You will need a Python built with the -fPIC option (position independent code). Most distributions build their Python that way.
You can choose which python to be used by settinng the environment variable PYTHON_CONFIG to the path to python3.*-config. If you don't specify one, the builder will use the first result of shell command 'locate python3-config'.
With a python in your path, then build:
perl6 configure.pl6
make test
# Sorry, I don't know how to implement the "make install" :(
make install
Or you can use the zef:
zef install .
Note that at present this library cannot be built with python interpreter provided by anaconda.