Python constants to arguments

A quick snippet to convert any primitive type constant in a Python main module to program arguments. E.g., if I have main.py with

FEATURE_SELECTION = True
NUMBER_OF_ROWS = 100
 
def main():
  # rest of program

and I want to trivially and automatically parse command line arguments to replace the constants, which is really a bad idea for a variety of reasons, an automatic argparser can generate this:

$ python main.py --help
usage: main.py [-h] [--number-of-rows NUMBER_OF_ROWS]
               [--feature-selection FEATURE_SELECTION]
 
optional arguments:
  -h, --help            show this help message and exit
  --number-of-rows NUMBER_OF_ROWS
                        Auto-generated constant (int). (default: 100)
  --feature-selection FEATURE_SELECTION
                        Auto-generated constant (bool). (default: True)

The following snippet can be appended to a main module to hackily replace the constants!

import argparse
parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter)
# update global constants with args
map(lambda kv: parser.add_argument('--%s' % kv[0].lower().replace('_', '-'), default=kv[1], type=type(kv[1]) if type(kv[1]) != bool else str,
                                   help='Auto-generated constant (%s).' % type(kv[1]).__name__, dest=kv[0]),
    filter(lambda kv: kv[0] == kv[0].upper() and type(kv[1]) in (int, bool), globals().iteritems()))
args = parser.parse_args()
globals().update(((k, eval(v) if type(v) == str else v) for k, v in vars(args).iteritems() if k == k.upper()))

And now, I can do:

$ python main.py --number-of-rows=10

without ever having to add logic specific to constants; I can just add constants and the flags are auto-generated.

Just be wary this is incredibly bad practice due to monkey patching and insecure due to the use of eval(). However for quick scripts, I find it to be effective.

Leave a Reply