2

In my python3 code, I have a series of functions into which I want to insert some common code. This code must set the same set of local variables within each function.

To better explain, consider the following function ...

def arbtrary_function(arg0, arg1):
    ### I want these local variables set ...
    localvar0  = some_function_of(arg0)
    localvar1  = some_other_function_of(arg0)
    # ... 18 more similar settings ...
    localvar20 = yet_another_function_of(arg0)
    ### End of local variable settings
    # The rest of the function's code will use
    # these local variables.

I want to begin a number of functions with this same code block.

I have tried doing this with a decorator, but I haven't been able to figure out how the decorator can set local variable values within the function that it is decorating.

If python3 had something like the C-preprocessor's macro facility, I could do this:

### Somehow define a "macro" with those 21 lines of common code ...
somehow_define_macro COMMON_CODE(ARG):
    localvar0  = some_function_of(ARG)
    localvar1  = some_other_function_of(ARG)
    # ... 18 more similar settings ...
    localvar20 = yet_another_function_of(ARG)

... and then, I could do this in each of the many functions into which I'd like to insert this common code:

def arbtrary_function(arg0, arg1):
    COMMON_CODE(arg0)

But, of course, python doesn't have this C-preprocessor functionality.

I tried to do this with a function that accepts its caller's locals() dictionary as an argument. Even though the function makes changes to that supplied locals() dictionary, those changes don't make any new local variables available to the caller after the function returns. For example:

def modifylocals(loc, arg):
    loc['localvar0'] = some_function_of(arg)
    # ... etc. ...

def arbitrary_function(arg0, arg1):
    modifylocals(locals(), arg0)
    # The following properly prints the new value of localvar0
    # that was set within locals() ...
    print('value in locals() of localvar0: {}' \
        .format(locals().get('localvar0', 'NOT SET')))
    # However, the localvar0 local variable does not get created
    # within my function. The following prints 'DOES NOT EXIST' ...
    try:
        print('value of localvar0: {}'.format(localvar0))
    except:
        print('DOES NOT EXIST')

I know I could also do the following, but then, I would have to change each function that calls the setmylocals() function if I ever want that function to set more or fewer local variables ...

def setmylocals(arg):
    localvar0  = some_function_of(arg)
    # ... etc. ...
    localvar20 = yet_another_function_of(arg)
    return (localvar0, ... etc. ..., localvar20)

def arbitrary_function(arg0, arg1):
    localvar0, ..., localvar20 = setmylocals(arg0)

Does anyone know of a way I can implement this particular C-preprocessor-like functionality in python3?

PS: I know that if I refactor all the functions that use these local variables to use dictionary entries instead of the local variables in question, then this becomes a straightforward task. However, the functions I want to modify already exist in a large code base, and I don't want to refactor all of those functions. Being able to optionally pre-set local variable values in this "C-preprocessor-like" manner involves much less work and will have much less impact on the existing code base.

In other words, I could do this, but I don't want to ...

def setvariables(arg):
    retval = {}
    retval['localvar0'] = some_function_of(arg)
    # ... etc. ...
    return retval

def arbitrary_function(arg0, arg1):
    vars = setvariables(arg0)
    # ... and then change the rest of the code to use
    # `vars['localvar0']` instead of `localvar0`, etc.
    # However, I want to avoid all this refactoring
    # of the existing code.

PPS: This discussion states that what I'm looking for is impossible: Modifying locals in Python

But hope springs eternal. Does anyone know of any procedure for doing what I want?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
HippoMan
  • 2,119
  • 2
  • 25
  • 48
  • I thought of an approach that might work. I could extend importer and write my own `loader.get_data` as described in __PEP 302__ (https://www.python.org/dev/peps/pep-0302/). That modified method would feed any file-based python code through the __filepp__ processor (http://www-users.york.ac.uk/%7Edm26/filepp/) or something similar. I will work on this and report back here later. – HippoMan Nov 05 '17 at 19:38
  • Sounds you are dealing with some large legacy code. If you can not refactor the old code, adding another layer like the above most likely will make things worse – especially in the long run, when the next programmer come along and needs to update the code you are considering. Given that 'Explicit is better than implicit' I would strongly suggest you go with the setmylocals variation. Working with a dict of function versions and the unpacking generalizations (PEP448) should get you a long way. When it comes to Python 'import this' is often good to reflect on. – FredrikHedman Nov 05 '17 at 21:27
  • Thank you. I didn't know about the PEP 448 unpacking generalizations. That's probably the best compromise. I'll post my solution here in a little while. – HippoMan Nov 05 '17 at 23:10

0 Answers0