lambda binding upon call is causing issue in my generated code

69 Views Asked by At

As the author of Pythonizer, I'm translating some perl code to python that defines a function FETCH in 2 different packages in the same source file, like:

package Env;
sub FETCH {...}
package Env::Array;
sub FETCH {...}

and my generated code needs to insert a special library call (perllib.tie_call) that handles the 'tie' operation at runtime. Here is a sample of my generated code for the above:

builtins.__PACKAGE__ = "Env"
def FETCH(*_args):
    ...
Env.FETCH = lambda *_args, **_kwargs: perllib.tie_call(FETCH, _args, _kwargs)

builtins.__PACKAGE__ = "Env.Array"
def FETCH(*_args):
    ...
Env.Array.FETCH = lambda *_args, **_kwargs: perllib.tie_call(FETCH, _args, _kwargs)

What is happening, when I call Env.FETCH, it's invoking the second def FETCH, as that's the current one defined. I need to invoke the first FETCH for Env.FETCH and the second FETCH for Env.Array.FETCH. How can I modify my generated code to do that? In the situation that I don't need to sneak in a perllib.tie_call, my generated code is:

builtins.__PACKAGE__ = "Env"
def FETCH(*_args):
    ...
Env.FETCH = FETCH

builtins.__PACKAGE__ = "Env.Array"
def FETCH(*_args):
    ...
Env.Array.FETCH = FETCH

which works as expected. With the lambda, the evaluation of FETCH gets delayed and the last one defined is being picked up. I need it to pick up the FETCH defined just above it instead.

1

There are 1 best solutions below

1
snoopyjc On

Here is how I figured out how to fix it. Thanks @python_user for helping me brainstorm a solution!! Since I'm also the author of perllib, the library for Pythonizer, I added a new function to it add_tie_call, defined as follows:

def add_tie_call(func):
    """Add a call to _tie_call for functions defined in a tie package"""
    def tie_call_func(*args, **kwargs):
        return _tie_call(func, args, kwargs)
    return tie_call_func

Then I changed lambda lines to read:

Env.FETCH = perllib.add_tie_call(FETCH)
...
Env.Array.FETCH = perllib.add_tie_call(FETCH)

and now my test case passes:

$ ./runit -P issue_s304
==================== issue_s304.pl ====================
issue_s304.pl - test passed!
issue_s304.py - test passed!
pythonizer 1 tests PASSED!