[Zope-Perl] Calling python functions with keyword arguments from perl

Gisle Aas gisle@ActiveState.com
15 Aug 2000 11:50:22 +0200


Currently there is no way to call a python function with keyword
arguments from perl.  I think we need some nice/easy way of doing just
that.

Yesterday, I tried to translate a DTML method that contained the
following call:

   <dtml-call expr="photoArchive.manage_addImage(id='',
                                                 file=file,
                                                 title=photo_title)">

It would have been nice if this could simply have been turned into:

   $self->{photoArchive}->manage_addImage(id    => '',
                                          file  => $file,
                                          title => $photo_title);

I ended up greping the source to find the signature of
manage_addImage() and wrote it using positional arguments only:

   $self->{f1}->manage_addImage("", $file, $photo_title);

The main problem is that it is not possible to know if "=>" or "," is
used in the argument lists inside the called function.  At least not
until perl6 comes along and make => a pair operator or something :-)

The basic support for keyword arguments can be added by implementing:

  Python::apply($CALLABLE, \@POSITIONAL_ARGUMENTS, \%KEYWORD_ARGUMENTS)

Currently we only support PyObject_CallObject() interface.

But it is not very nice to always have to say:

  apply(getattr($self->{photoArchive}, "manage_addImage"), [],
                { id => '', file => $file, title => $photo_title });

One suggestion could be to introduce a rule which says that if the
last argument to a python function is a hash, then that hash contains
the keyword arguments.  Then we could say:

   $self->{photoArchive}->manage_addImage({id    => '',
                                           file  => $file,
                                           title => $photo_title});

or in general:

   $obj->foo($pos1, $pos2, { key1 => $val1, key2 => $val2 });

It is not too cluttered, but you might get surprises in cases where
you did not intend to pass any keyword arguments and the last
positional argument just happened to be a hash reference.  You can
protect yourself by appending an empty hash to the argument list in
this case:

   $obj->foo(@args, {})

Other potential interfaces I could think of include:

  * Use some specific object to wrap the keyword arguments.  It looks
    uglier than the plain hash, will be slower, but will be safe from
    surprises.

       $obj->foo($pos1, $pos2, KW( key1 => $val1, key2 => $val2 ));

  * Use some special marker object inside the argument list to signal
    where the keywords begin:

       $obj->foo($pos1, $pos2, $KW, key1 => $val1, key2 => $val2);

    We would then have to scan the argument to locate this marker.
    It is also kind of ugly.

  * Use leading dashes on keywords:

       $obj->foo($pos1, $pos2, -key1 => $val1, -key2 => $val2);

    Not too bad, but what if you want to pass plain strings with
    leading dashes as positional arguments?

  * Tell people to use apply() :-)

       apply(getattr($obj, "foo"), [$pos1, $pos2], { key1 => $val1, key2 => $val2 });

Any other ideas or preferences for what interface to choose?

Regards,
Gisle