尚未翻译
本页面尚未翻译成中文,因此显示英文原文。 帮助翻译
optparse Module Complexity¶
The optparse module parses command-line options declared up front on an OptionParser. It is
pure Python: each registered option string is a dictionary key, and parse_args() walks the
argument list once, consuming options and their values from the front. argparse is the
documented recommendation for new applications; optparse remains supported and gives
lower-level control over how options and positional arguments interleave.
a is the argument strings handed to parse_args(), o is the options registered on the parser
(its groups included), d is the entries in the parser's defaults (one per destination, plus any
from set_defaults()), L is the long option strings registered, c is the choices of one
choice option, and h is the characters of help output. Checking a choice value costs O(c)
wherever it happens, on the command line or in a string default. Strings the caller supplies -
option strings, arguments, usage, messages - are priced at O(1) each, except that help text
counts toward h and a cluster of short flags such as -vvv costs one step per flag; a
callback's own cost is excluded.
Complexity Reference¶
OptionParser¶
| Operation | Time | Space | Notes |
|---|---|---|---|
optparse.OptionParser(usage=None, option_list=None, option_class=Option, version=None, conflict_handler='error', description=None, formatter=None, add_help_option=True, prog=None, epilog=None) |
O(o) | O(o) | Registers option_list, standard_option_list and the --help/--version options |
OptionParser.add_option(*opt_str, **attrs), OptionParser.add_option(option) |
O(1) | O(1) | Attributes are validated when the Option is built, not when it is parsed; a resolved conflict that leaves an earlier option with no strings removes it from its list in O(o) |
OptionParser.add_options(option_list) |
O(k) | O(k) | k = options added; one add_option each |
OptionParser.get_option(opt_str), OptionParser.has_option(opt_str) |
O(1) | O(1) | Exact option strings only; abbreviations are resolved by parse_args() alone |
OptionParser.remove_option(opt_str) |
O(o) | O(1) | Removes the option from its container's list by a linear scan |
OptionParser.set_default(dest, value) |
O(1) | O(1) | One dict entry |
OptionParser.set_defaults(**kwargs) |
O(k) | O(k) | k = keyword arguments |
OptionParser.get_default_values() |
O(o + d) | O(o + d) | Copies the defaults and converts each string default through its option's type checker |
OptionParser.set_usage(usage), OptionParser.set_conflict_handler(handler), OptionParser.set_description(description), OptionParser.set_process_default_values(process) |
O(1) | O(1) | Attribute updates |
OptionParser.enable_interspersed_args(), OptionParser.disable_interspersed_args() |
O(1) | O(1) | Disabled, parsing stops at the first positional argument and returns the rest untouched |
OptionParser.standard_option_list |
O(1) | O(1) | Class attribute; its options are added when each parser is built |
OptionParser.destroy() |
O(g) | O(1) | g = option groups; breaks reference cycles, after which the parser is unusable |
Parsing¶
| Operation | Time | Space | Notes |
|---|---|---|---|
OptionParser.parse_args(args=None, values=None) |
O(o + d + a²) | O(o + d + a) | Each consumed argument is removed from the front of the remaining list, which is the a² term; an abbreviated long option adds O(L) and a choice value O(c). Passing values skips the O(o + d) defaults |
Arguments left after --, or after the first positional with interspersed arguments disabled |
O(a) | O(a) | Parsing stops there; the remainder is copied into the returned list, not consumed one at a time |
OptionParser.check_values(values, args) |
O(1) | O(1) | Hook called with the result; returns its arguments unchanged unless overridden |
OptionParser.largs, OptionParser.rargs, OptionParser.values |
O(1) | O(1) | The parse's live state, for callbacks |
Option¶
| Operation | Time | Space | Notes |
|---|---|---|---|
optparse.Option(*opt_str, **attrs), optparse.make_option(*opt_str, **attrs) |
O(1) | O(1) | Raises OptionError for an invalid combination of attributes |
Option.action, Option.type, Option.dest, Option.default, Option.nargs, Option.const, Option.choices, Option.callback, Option.callback_args, Option.callback_kwargs, Option.help, Option.metavar |
O(1) | O(1) | Attributes, set from the keyword arguments |
Option.check_value(opt, value), Option.convert_value(opt, value) |
O(1) per value | O(1) per value | O(c) for choice, which scans the choices sequence |
Option.process(opt, value, values, parser), Option.take_action(action, dest, opt, value, values, parser) |
O(1) | O(1) | Plus process()'s value conversion, the callback for action='callback', and the help output for help and version; append grows one list, amortized O(1) |
Option.takes_value(), Option.get_opt_string() |
O(1) | O(1) | |
optparse.check_choice(option, opt, value), optparse.check_builtin(option, opt, value) |
O(c), O(1) | O(1) | The type checkers for choice and the numeric types |
Values¶
| Operation | Time | Space | Notes |
|---|---|---|---|
optparse.Values(defaults=None) |
O(d) | O(d) | One attribute per default |
Values.ensure_value(attr, value) |
O(1) | O(1) | Sets the attribute when it is missing or None; what append and count build on |
OptionGroup¶
| Operation | Time | Space | Notes |
|---|---|---|---|
optparse.OptionGroup(parser, title, description=None) |
O(1) | O(1) | Shares the parser's option dicts, so an option string is unique across every group |
OptionParser.add_option_group(title, description=None), OptionParser.add_option_group(group) |
O(1) | O(1) | |
OptionParser.get_option_group(opt_str) |
O(1) | O(1) | The group holding the option, or None for one on the parser itself |
OptionGroup.add_option(...), OptionGroup.set_title(title), OptionGroup.destroy() |
O(1) | O(1) | As on the parser |
optparse.OptionContainer |
O(1) | O(1) | Base class of OptionParser and OptionGroup |
Help and usage¶
| Operation | Time | Space | Notes |
|---|---|---|---|
OptionParser.format_help(formatter=None), OptionParser.print_help(file=None) |
O(o + h) | O(o + h) | The whole text is built as one string before it is written |
OptionParser.format_option_help(formatter=None) |
O(o + h) | O(o + h) | The option listing format_help() includes |
OptionParser.format_description(formatter), OptionParser.format_epilog(formatter), OptionParser.get_usage(), OptionParser.print_usage(file=None), OptionParser.get_version(), OptionParser.print_version(file=None) |
O(h) | O(h) | %prog is replaced by the program name everywhere but the epilog |
OptionParser.get_prog_name(), OptionParser.expand_prog_name(s), OptionParser.get_description() |
O(h) | O(h) | The name is prog, or the basename of sys.argv[0] |
OptionParser.error(msg) |
O(h) | O(h) | Prints the usage and msg to stderr, then raises SystemExit(2) |
OptionParser.exit(status=0, msg=None) |
O(1) | O(1) | Raises SystemExit |
optparse.HelpFormatter, optparse.IndentedHelpFormatter(indent_increment=2, max_help_position=24, width=None, short_first=1), optparse.TitledHelpFormatter(indent_increment=0, max_help_position=24, width=None, short_first=0) |
O(1) | O(1) | With width=None the width comes from $COLUMNS |
Constants and exceptions¶
| Operation | Time | Space | Notes |
|---|---|---|---|
optparse.SUPPRESS_HELP, optparse.SUPPRESS_USAGE |
O(1) | O(1) | Sentinels that leave an option out of the help, or drop the usage line |
optparse.OptParseError |
O(1) | O(1) | Base class of every exception below |
optparse.OptionError, optparse.OptionConflictError |
O(1) | O(1) | Raised while options are declared: an invalid attribute, or an option string already taken |
optparse.BadOptionError, optparse.AmbiguousOptionError, optparse.OptionValueError |
O(1) | O(1) | Raised while parsing; parse_args() turns them into error() |
Parsing a Command Line¶
Basic Option Parsing¶
Registering an option is a dictionary entry per option string, and parse_args() reads the
arguments you pass it, or sys.argv[1:] when you pass nothing.
import optparse
parser = optparse.OptionParser(prog='tool') # O(o) - only --help so far
parser.add_option('-f', '--file', dest='filename') # O(1)
parser.add_option('-v', '--verbose', action='store_true', default=False) # O(1)
parser.add_option('-n', type='int', default=1) # O(1)
options, args = parser.parse_args(['-v', '--file=in.txt', '-n', '3', 'extra']) # O(o + d + a²)
assert options.filename == 'in.txt'
assert options.verbose is True
assert options.n == 3
assert args == ['extra']
Long Argument Lists¶
Every argument parse_args() consumes is deleted from the front of the list it is still walking,
so a long list of positional arguments costs quadratic time. -- ends option processing, and the
arguments after it are handed back without being consumed; so does the first positional argument
once interspersed arguments are disabled.
import optparse
files = [f'file{i}.txt' for i in range(1_000)]
parser = optparse.OptionParser()
parser.add_option('-v', action='count', default=0)
# Mixed in with the options: every file is consumed one by one - O(a²)
options, args = parser.parse_args(['-v'] + files)
assert args == files
# After '--': parsing stops, the rest is copied - O(a)
options, args = parser.parse_args(['-v', '--'] + files)
assert args == files and options.v == 1
# Interspersed arguments disabled: parsing stops at the first positional - O(a)
parser.disable_interspersed_args() # O(1)
options, args = parser.parse_args(['-v'] + files + ['-v'])
assert options.v == 1 and args[-1] == '-v'
Abbreviated Long Options¶
An exact long option costs O(1) dictionary lookups. An abbreviation such as --verb is matched against
every registered long option string, O(L), and a prefix that fits more than one is an error.
import optparse
class RaisingParser(optparse.OptionParser):
def error(self, msg):
raise ValueError(msg)
parser = RaisingParser()
parser.add_option('--verbose', action='store_true')
parser.add_option('--version-file')
options, _ = parser.parse_args(['--verbose']) # lookup O(1) - exact match
assert options.verbose is True
options, _ = parser.parse_args(['--verb']) # lookup O(L) - scans the long options
assert options.verbose is True
try:
parser.parse_args(['--ver']) # lookup O(L) - fits both
except ValueError as error:
assert 'ambiguous option' in str(error)
else:
raise AssertionError('an ambiguous prefix was accepted')
assert parser.get_option('--verb') is None # O(1) - exact strings only
Option Types and Actions¶
Each value is converted when it is consumed. The numeric types are one conversion, and choice
scans its choices sequence, O(c). append grows one list per destination; a callback runs once
per occurrence, at its own cost.
import optparse
parser = optparse.OptionParser()
parser.add_option('--mode', type='choice', choices=['fast', 'safe']) # O(c) per value
parser.add_option('-I', dest='include', action='append') # amortized O(1) per value
parser.add_option('-q', action='count', dest='quiet') # O(1) per occurrence
seen = []
parser.add_option('--mark', action='callback', callback=lambda *args: seen.append(args[1]))
options, _ = parser.parse_args(['--mode', 'safe', '-I', 'a', '-I', 'b', '-qq', '--mark'])
assert options.mode == 'safe'
assert options.include == ['a', 'b']
assert options.quiet == 2
assert seen == ['--mark']
# A bad value is caught at declaration or parse time, not later
try:
optparse.Option('--x', type='choice') # O(1) - validated when declared
except optparse.OptionError as error:
assert 'must supply a list of choices' in str(error)
else:
raise AssertionError('a choice option without choices was accepted')
Defaults¶
Every parse_args() call without a values argument builds a fresh Values from the parser's
defaults, O(o + d). Passing your own Values skips that step and fills it in place.
import optparse
parser = optparse.OptionParser()
parser.add_option('-n', type='int', default='5') # a string default is converted
parser.set_defaults(level='info') # O(k)
defaults = parser.get_default_values() # O(o + d)
assert defaults.n == 5 and defaults.level == 'info'
values = optparse.Values({'n': 0}) # O(d)
options, _ = parser.parse_args(['-n', '7'], values=values) # skips the defaults
assert options is values and values.n == 7
assert not hasattr(values, 'level')
Option Groups¶
A group is a heading in the help output and nothing more for parsing: it shares its parser's option dictionaries, so adding to a group costs the same as adding to the parser, and an option string cannot appear in two groups.
import optparse
parser = optparse.OptionParser()
group = parser.add_option_group('Debug') # O(1)
group.add_option('--trace', action='store_true') # O(1), into the parser's dicts
assert parser.has_option('--trace') # O(1)
assert parser.get_option_group('--trace') is group # O(1)
try:
parser.add_option('--trace')
except optparse.OptionConflictError as error:
assert 'conflicting option string' in str(error)
else:
raise AssertionError('a duplicate option string was accepted')
Removing Options¶
Removing an option deletes its strings from the dictionaries in O(1), but also deletes the option from its container's list, which is a linear scan.
import optparse
parser = optparse.OptionParser()
parser.add_option('-a', '--alpha')
parser.add_option('-b', '--beta')
parser.remove_option('--alpha') # O(o)
assert not parser.has_option('-a') and not parser.has_option('--alpha')
try:
parser.remove_option('--alpha')
except ValueError as error:
assert 'no such option' in str(error)
else:
raise AssertionError('a removed option was removed again')
Help Output¶
format_help() walks every option, wraps each help string, and joins the result into one string;
print_help() writes that string in a single call. A fixed width makes the output independent of
$COLUMNS.
import io
import optparse
formatter = optparse.IndentedHelpFormatter(width=60) # O(1)
parser = optparse.OptionParser(prog='tool', usage='%prog [options] FILE', formatter=formatter)
parser.add_option('-n', type='int', default=3, help='retries [default: %default]')
text = parser.format_help() # O(o + h)
assert text.startswith('Usage: tool [options] FILE\n')
assert 'retries [default: 3]' in text
buffer = io.StringIO()
parser.print_help(buffer) # O(o + h) - one write
assert buffer.getvalue() == text
Common Patterns¶
Raising Instead of Exiting¶
parse_args() reports every bad option through error(), which exits the process. Overriding it
is the documented way to keep control.
import optparse
class RaisingParser(optparse.OptionParser):
def error(self, msg):
raise ValueError(msg)
parser = RaisingParser()
parser.add_option('-n', type='int')
try:
parser.parse_args(['-n', 'many'])
except ValueError as error:
assert "invalid integer value: 'many'" in str(error)
else:
raise AssertionError('a non-integer was accepted')
Forwarding Options to a Subcommand¶
import optparse
parser = optparse.OptionParser()
parser.add_option('-v', action='store_true')
parser.disable_interspersed_args() # stop at the subcommand
options, args = parser.parse_args(['-v', 'run', '-v', '--fast']) # O(o + d + a)
assert options.v is True
assert args == ['run', '-v', '--fast'] # left for the subcommand's own parser
Performance Best Practices¶
✅ Do:
- Put
--before a long list of positional arguments, or disable interspersed arguments, so they are copied rather than consumed one at a time - Spell long options out in scripts; an abbreviation scans every long option string
- Override
error()to raise when parsing is not the program's own command line
❌ Avoid:
- Long lists of positional arguments mixed in with options: that is the O(a²) path
- Calling
remove_option()in a loop over a large parser; each call scans the option list - Expecting
get_option()orhas_option()to accept an abbreviation
Version Notes¶
- All Python 3:
parse_args()exits the process with status 2 on a bad option or value; overrideerror()to raise instead