I was looking at the source code for the built-in argparse._AppendAction, which implements the "append"
action, and puzzled over the way it is implemented:
def __call__(self, parser, namespace, values, option_string=None):
items = _copy.copy(_ensure_value(namespace, self.dest, []))
items.append(values)
setattr(namespace, self.dest, items)
To break it down:
_ensure_value
is like dict.setdefault
for attributes. That is, if namespace
has an attribute with the name self.dest
then it is returned, if not it is set to []
and returned._copy.copy(x)
returns just a shallow copy. When x
is a list it is exactly like list(x)
(but slower).namespace
.self.dest
attribute of namespace
is overwritten with the copy, which should cause the old list to be garbage collected.Why do it in such a roundabout and inefficient way, throwing away a whole list for each append? Why doesn't this suffice?
def __call__(self, parser, namespace, values, option_string=None):
items = _ensure_value(namespace, self.dest, [])
items.append(values)
I'm not an expert in the implementation, so (disclaimer) this is really just a guess. With this implementation, the user can pass a list as a default=...
in a call to add_argument
without it being mutated within argparse. Perhaps this type of safety was desired by the developers for one reason or another.
The inefficiency you mention really isn't a big deal. It's for parsing commandline arguments, so this function is likely only called 10's of times per program under heavy usage.
I've tested this and indeed, If I use the following script (where argparse_temp
is simply argparse.py
copied to the current directory so I can play with it):
import argparse_temp as argparse
lst = [1,2,3]
parser = argparse.ArgumentParser()
parser.add_argument('-l',default=lst,action='append')
print parser.parse_args()
print lst
This prints (when called as: python test1.py -l 4
):
Namespace(l=[1, 2, 3, '4'])
[1, 2, 3]
with argparse
as is, but:
Namespace(l=[1, 2, 3, '4'])
[1, 2, 3, '4']
with your proposed change.
If you print the action that is returned by add_argument
, you get:
_AppendAction(option_strings=['-l'], dest='l', nargs=None, const=None, default=[1, 2, 3, '4'], type=None, choices=None, help=None, metavar=None)
Which is it conceivable that argparse depends on that action elsewhere in the implementation. (Notice that default
has been mutated here as well).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With