Python Argparse: Issue with optional arguments which are negative numbers

后端 未结 7 1996
走了就别回头了
走了就别回头了 2020-12-08 13:59

I\'m having a small issue with argparse. I have an option xlim which is the xrange of a plot. I want to be able to pass numbers like <

相关标签:
7条回答
  • 2020-12-08 14:19

    Another workaround is to pass in the argument using '=' symbol in addition to quoting the argument - i.e., --xlim="-2.3e14"

    0 讨论(0)
  • 2020-12-08 14:21

    If you specify the value for your option with an equals sign, argparse will not treat it as a separate option, even if it starts with -:

    ./blaa.py --xlim='-0.002 1e4'
    # As opposed to --xlim '-0.002 1e4'
    

    And if the value does not have spaces in it, you can drop the quotes:

    ./blaa.py --xlim=-0.002
    

    See: https://www.gnu.org/software/guile/manual/html_node/Command-Line-Format.html

    With this, there is no need to write your own type= parser or redefine the prefix character from - to @ as the accepted answer suggests.

    0 讨论(0)
  • 2020-12-08 14:27

    As already pointed out by the comments, the problem is that a - prefix is parsed as an option instead of as an argument. One way to workaround this is change the prefix used for options with prefix_chars argument:

    #!/usr/bin/python
    import argparse
    
    parser = argparse.ArgumentParser(prefix_chars='@')
    parser.add_argument('@@xlim', nargs = 2,
                      help = 'X axis limits',
                      action = 'store', type = float,
                      default = [-1.e-3, 1.e-3])
    print parser.parse_args()
    

    Example output:

    $ ./blaa.py @@xlim -2.e-3 1e4
    Namespace(xlim=[-0.002, 10000.0])
    

    Edit: Alternatively, you can keep using - as separator, pass xlim as a single value and use a function in type to implement your own parsing:

    #!/usr/bin/python
    import argparse
    
    def two_floats(value):
        values = value.split()
        if len(values) != 2:
            raise argparse.ArgumentError
        values = map(float, values)
        return values
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--xlim', 
                      help = 'X axis limits',
                      action = 'store', type=two_floats,
                      default = [-1.e-3, 1.e-3])
    print parser.parse_args()
    

    Example output:

    $ ./blaa.py --xlim "-2e-3 1e4"
    Namespace(xlim=[-0.002, 10000.0])
    
    0 讨论(0)
  • 2020-12-08 14:31

    One workaround I've found is to quote the value, but adding a space. That is,

    ./blaa.py --xlim " -2.e-3" 1e4
    

    This way argparse won't think -2.e-3 is an option name because the first character is not a hyphen-dash, but it will still be converted properly to a float because float(string) ignores spaces on the left.

    0 讨论(0)
  • 2020-12-08 14:31

    If you are up to modifying argparse.py itself, you could change the negative number matcher to handle scientific notation:

    In class _ActionsContainer.__init__()

    self._negative_number_matcher = _re.compile(r'^-(\d+\.?|\d*\.\d+)([eE][+\-]?\d+)?$')
    

    Or after creating the parser, you could set parser._negative_number_matcher to this value. This approach might have problems if you are creating groups or subparsers, but should work with a simple parser.

    0 讨论(0)
  • 2020-12-08 14:31

    Inspired by andrewfn's approach, I created a separate helper function to do the sys.argv fiddling:

    def _tweak_neg_scinot():
        import re
        import sys
        p = re.compile('-\\d*\\.?\\d*e', re.I)
        sys.argv = [' ' + a if p.match(a) else a for a in sys.argv]
    

    The regex looks for:

    • - : a negative sign
    • \\d* : zero or more digits (for oddly formatted values like -.5e-2 or -4354.5e-6)
    • \\.? : an optional period (e.g., -2e-5 is reasonable)
    • \\d* : another set of zero or more digits (for things like -2e-5 and -7.e-3)
    • e : to match the exponent marker

    re.I makes it match both -2e-5 and -2E-5. Using p.match means that it only searches from the start of each string.

    0 讨论(0)
提交回复
热议问题