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).
  • Then the item is appended to the copy of the list gotten from namespace.
  • Finally the 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)
Edit
Report