Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #83443 > unrolled thread

Why does argparse return None instead of [] if an append action isn't used?

Started byAdam Funk <a24061@ducksburg.com>
First post2015-01-09 14:44 +0000
Last post2015-01-26 13:43 +0000
Articles 14 — 8 participants

Back to article view | Back to comp.lang.python


Contents

  Why does argparse return None instead of [] if an append action isn't used? Adam Funk <a24061@ducksburg.com> - 2015-01-09 14:44 +0000
    Re: Why does argparse return None instead of [] if an append action isn't used? Skip Montanaro <skip.montanaro@gmail.com> - 2015-01-09 08:57 -0600
      Re: Why does argparse return None instead of [] if an append action isn't used? Adam Funk <a24061@ducksburg.com> - 2015-01-09 15:25 +0000
    Re: Why does argparse return None instead of [] if an append action isn't used? Ned Batchelder <ned@nedbatchelder.com> - 2015-01-09 10:12 -0500
      Re: Why does argparse return None instead of [] if an append action isn't used? Adam Funk <a24061@ducksburg.com> - 2015-01-26 13:43 +0000
        Re: Why does argparse return None instead of [] if an append action isn't used? Peter Otten <__peter__@web.de> - 2015-01-26 15:04 +0100
          Re: Why does argparse return None instead of [] if an append action isn't used? Adam Funk <a24061@ducksburg.com> - 2015-01-26 15:50 +0000
            Re: Why does argparse return None instead of [] if an append action isn't used? Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-26 09:13 -0700
              Re: Why does argparse return None instead of [] if an append action isn't used? Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2015-01-26 18:29 +0200
                Re: Why does argparse return None instead of [] if an append action isn't used? Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-01-26 17:18 +0000
                Re: Why does argparse return None instead of [] if an append action isn't used? Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-26 11:23 -0700
                Re: Why does argparse return None instead of [] if an append action isn't used? Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-26 11:26 -0700
    Re: Why does argparse return None instead of [] if an append action isn't used? Wolfgang Maier <wolfgang.maier@biologie.uni-freiburg.de> - 2015-01-09 16:50 +0100
      Re: Why does argparse return None instead of [] if an append action isn't used? Adam Funk <a24061@ducksburg.com> - 2015-01-26 13:43 +0000

#83443 — Why does argparse return None instead of [] if an append action isn't used?

FromAdam Funk <a24061@ducksburg.com>
Date2015-01-09 14:44 +0000
SubjectWhy does argparse return None instead of [] if an append action isn't used?
Message-ID<l265obxc6d.ln2@news.ducksburg.com>
I noticed in use that if an option with the 'append' action isn't
used, argparse assigns None to it rather than an empty list, &
confirmed this interactively:

#v+
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='append')
_AppendAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('--bar', action='append')
_AppendAction(option_strings=['--bar'], dest='bar', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args('--foo 1 --foo 2'.split())
Namespace(bar=None, foo=['1', '2'])
#v-

This makes it a bit more trouble to use:

  if options.bar:
     for b in options:bar
        do_stuff(b)

instead of

  for b in options.bar
     do_stuff(b)

which is (of course) what I was doing when I discovered the None.  Is
there any benefit to the user from this, or is it just an "accident"
of the way argparse is written?


-- 
The history of the world is the history of a privileged few.
                                            --- Henry Miller

[toc] | [next] | [standalone]


#83444

FromSkip Montanaro <skip.montanaro@gmail.com>
Date2015-01-09 08:57 -0600
Message-ID<mailman.17527.1420815432.18130.python-list@python.org>
In reply to#83443
> I noticed in use that if an option with the 'append' action isn't
> used, argparse assigns None to it rather than an empty list, &
> confirmed this interactively:

I don't use argparse (or optparse), being a getopt Luddite myself, but
can you set the default for an action in the add_argument call?

Skip

[toc] | [prev] | [next] | [standalone]


#83451

FromAdam Funk <a24061@ducksburg.com>
Date2015-01-09 15:25 +0000
Message-ID<7h85obxhje.ln2@news.ducksburg.com>
In reply to#83444
On 2015-01-09, Skip Montanaro wrote:

>> I noticed in use that if an option with the 'append' action isn't
>> used, argparse assigns None to it rather than an empty list, &
>> confirmed this interactively:
>
> I don't use argparse (or optparse), being a getopt Luddite myself, but
> can you set the default for an action in the add_argument call?

Well, duh!  That works, thanks.  (I can't explain why I didn't think
of that.)


>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='append',default=[])
_AppendAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=[], type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('--bar', action='append',default=[])
_AppendAction(option_strings=['--bar'], dest='bar', nargs=None, const=None, default=[], type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args('--foo 1 --foo 2'.split())
Namespace(bar=[], foo=['1', '2'])
>>> parser.parse_args('--foo 1 --bar 2'.split())
Namespace(bar=['2'], foo=['1'])
>>> parser.parse_args([])
Namespace(bar=[], foo=[])





-- 
Slade was the coolest band in England. They were the kind of guys
that would push your car out of a ditch.         --- Alice Cooper

[toc] | [prev] | [next] | [standalone]


#83449

FromNed Batchelder <ned@nedbatchelder.com>
Date2015-01-09 10:12 -0500
Message-ID<mailman.17529.1420816664.18130.python-list@python.org>
In reply to#83443
On 1/9/15 9:44 AM, Adam Funk wrote:
> This makes it a bit more trouble to use:
>
>    if options.bar:
>       for b in options:bar
>          do_stuff(b)
>
> instead of
>
>    for b in options.bar
>       do_stuff(b)

This doesn't answer why the value defaults to None, and some people may 
recoil at it, but I've used:

     for b in options.bar or ():
         do_stuff(b)

-- 
Ned Batchelder, http://nedbatchelder.com

[toc] | [prev] | [next] | [standalone]


#84598

FromAdam Funk <a24061@ducksburg.com>
Date2015-01-26 13:43 +0000
Message-ID<8tshpbxjvv.ln2@news.ducksburg.com>
In reply to#83449
On 2015-01-09, Ned Batchelder wrote:

> On 1/9/15 9:44 AM, Adam Funk wrote:
>> This makes it a bit more trouble to use:
>>
>>    if options.bar:
>>       for b in options:bar
>>          do_stuff(b)
>>
>> instead of
>>
>>    for b in options.bar
>>       do_stuff(b)
>
> This doesn't answer why the value defaults to None, and some people may 
> recoil at it, but I've used:
>
>      for b in options.bar or ():
>          do_stuff(b)

Do you mean "for b in options.bar or []:" ?


-- 
War is God's way of teaching Americans geography.
                                 [Ambrose Bierce]

[toc] | [prev] | [next] | [standalone]


#84600

FromPeter Otten <__peter__@web.de>
Date2015-01-26 15:04 +0100
Message-ID<mailman.18148.1422281105.18130.python-list@python.org>
In reply to#84598
Adam Funk wrote:

> On 2015-01-09, Ned Batchelder wrote:
> 
>> On 1/9/15 9:44 AM, Adam Funk wrote:
>>> This makes it a bit more trouble to use:
>>>
>>>    if options.bar:
>>>       for b in options:bar
>>>          do_stuff(b)
>>>
>>> instead of
>>>
>>>    for b in options.bar
>>>       do_stuff(b)
>>
>> This doesn't answer why the value defaults to None, and some people may
>> recoil at it, but I've used:
>>
>>      for b in options.bar or ():
>>          do_stuff(b)
> 
> Do you mean "for b in options.bar or []:" ?

Doesn't matter; in the context of a for loop any empty iterable would do.

[toc] | [prev] | [next] | [standalone]


#84605

FromAdam Funk <a24061@ducksburg.com>
Date2015-01-26 15:50 +0000
Message-ID<ta4ipbx9j3.ln2@news.ducksburg.com>
In reply to#84600
On 2015-01-26, Peter Otten wrote:

> Adam Funk wrote:
>
>> On 2015-01-09, Ned Batchelder wrote:
>> 
>>> On 1/9/15 9:44 AM, Adam Funk wrote:
>>>> This makes it a bit more trouble to use:
>>>>
>>>>    if options.bar:
>>>>       for b in options:bar
>>>>          do_stuff(b)
>>>>
>>>> instead of
>>>>
>>>>    for b in options.bar
>>>>       do_stuff(b)
>>>
>>> This doesn't answer why the value defaults to None, and some people may
>>> recoil at it, but I've used:
>>>
>>>      for b in options.bar or ():
>>>          do_stuff(b)
>> 
>> Do you mean "for b in options.bar or []:" ?
>
> Doesn't matter; in the context of a for loop any empty iterable would do.

Of course it would.  Doh!


-- 
A recent study conducted by Harvard University found that the average
American walks about 900 miles a year. Another study by the AMA found
that Americans drink, on average, 22 gallons of alcohol a year. This
means, on average, Americans get about 41 miles to the gallon.
                 http://www.cartalk.com/content/average-americans-mpg

[toc] | [prev] | [next] | [standalone]


#84606

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-01-26 09:13 -0700
Message-ID<mailman.18151.1422288861.18130.python-list@python.org>
In reply to#84605
On Mon, Jan 26, 2015 at 8:50 AM, Adam Funk <a24061@ducksburg.com> wrote:
> On 2015-01-26, Peter Otten wrote:
>
>> Adam Funk wrote:
>>
>>> On 2015-01-09, Ned Batchelder wrote:
>>>>      for b in options.bar or ():
>>>>          do_stuff(b)
>>>
>>> Do you mean "for b in options.bar or []:" ?
>>
>> Doesn't matter; in the context of a for loop any empty iterable would do.
>
> Of course it would.  Doh!

Stylistically, I generally prefer the empty list for this. The empty
tuple might be a little faster since it's a singleton and doesn't need
to be constructed at runtime, but that's clearly a micro-optimization,
and I think the list more accurately conveys the intention of
"something to be iterated over". Although tuples are iterable, I don't
often use them for that purpose.

[toc] | [prev] | [next] | [standalone]


#84607

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2015-01-26 18:29 +0200
Message-ID<qotioft4iao.fsf@ruuvi.it.helsinki.fi>
In reply to#84606
Ian Kelly writes:
> On Mon, Jan 26, 2015 at 8:50 AM, Adam Funk wrote:
> > On 2015-01-26, Peter Otten wrote:
> >
> >> Adam Funk wrote:
> >>
> >>> On 2015-01-09, Ned Batchelder wrote:
> >>>>      for b in options.bar or ():
> >>>>          do_stuff(b)
> >>>
> >>> Do you mean "for b in options.bar or []:" ?
> >>
> >> Doesn't matter; in the context of a for loop any empty iterable
> >> would do.
> >
> > Of course it would.  Doh!
> 
> Stylistically, I generally prefer the empty list for this. The empty
> tuple might be a little faster since it's a singleton and doesn't
> need to be constructed at runtime, but that's clearly a
> micro-optimization, and I think the list more accurately conveys the
> intention of "something to be iterated over". Although tuples are
> iterable, I don't often use them for that purpose.

I've used tuples to convey the intention of immutability, as opposed
to using lists. For all I know, collecting a generator (from groupby)
into a tuple might be slower than collecting it into a list. I have no
intention to measure this. The programs have been fast enough for me.

[toc] | [prev] | [next] | [standalone]


#84611

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2015-01-26 17:18 +0000
Message-ID<mailman.18153.1422292702.18130.python-list@python.org>
In reply to#84607
On 26/01/2015 16:29, Jussi Piitulainen wrote:
>
> I've used tuples to convey the intention of immutability, as opposed
> to using lists. For all I know, collecting a generator (from groupby)
> into a tuple might be slower than collecting it into a list. I have no
> intention to measure this. The programs have been fast enough for me.
>

IIRC, and probably from this list, creating tuples is way faster than 
creating lists, but accessing items is slower.  Can anybody confirm this 
for us?

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#84614

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-01-26 11:23 -0700
Message-ID<mailman.18155.1422296665.18130.python-list@python.org>
In reply to#84607
On Mon, Jan 26, 2015 at 10:18 AM, Mark Lawrence <breamoreboy@yahoo.co.uk> wrote:
> IIRC, and probably from this list, creating tuples is way faster than
> creating lists, but accessing items is slower.  Can anybody confirm this for
> us?

The first seems to be true as long as the tuples are small.

$ python3 -m timeit 't = (1000, 2000, 3000)'
100000000 loops, best of 3: 0.0147 usec per loop
$ python3 -m timeit 't = [1000, 2000, 3000]'
10000000 loops, best of 3: 0.0678 usec per loop
$ python3 -m timeit 't = tuple(range(10000))'
10000 loops, best of 3: 183 usec per loop
$ python3 -m timeit 't = list(range(10000))'
10000 loops, best of 3: 174 usec per loop
$ python3 -m timeit 't = tuple(range(10000000))'
10 loops, best of 3: 323 msec per loop
$ python3 -m timeit 't = list(range(10000000))'
10 loops, best of 3: 306 msec per loop

This is probably a result of the use of freelists to avoid
reallocating the tuple objects, though. I don't see any substantial
difference in access time:

$ python3 -m timeit -s 't = tuple(range(10000))' 't[5000]'
10000000 loops, best of 3: 0.0316 usec per loop
$ python3 -m timeit -s 't = list(range(10000))' 't[5000]'
10000000 loops, best of 3: 0.0318 usec per loop
$ python3 -m timeit -s 't = tuple(range(10000))' 'for x in t: pass'
10000 loops, best of 3: 112 usec per loop
$ python3 -m timeit -s 't = list(range(10000))' 'for x in t: pass'
10000 loops, best of 3: 113 usec per loop

[toc] | [prev] | [next] | [standalone]


#84615

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-01-26 11:26 -0700
Message-ID<mailman.18156.1422296837.18130.python-list@python.org>
In reply to#84607
On Mon, Jan 26, 2015 at 11:23 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> $ python3 -m timeit 't = (1000, 2000, 3000)'
> 100000000 loops, best of 3: 0.0147 usec per loop
> $ python3 -m timeit 't = [1000, 2000, 3000]'
> 10000000 loops, best of 3: 0.0678 usec per loop
> $ python3 -m timeit 't = tuple(range(10000))'
> 10000 loops, best of 3: 183 usec per loop
> $ python3 -m timeit 't = list(range(10000))'
> 10000 loops, best of 3: 174 usec per loop
> $ python3 -m timeit 't = tuple(range(10000000))'
> 10 loops, best of 3: 323 msec per loop
> $ python3 -m timeit 't = list(range(10000000))'
> 10 loops, best of 3: 306 msec per loop
>
> This is probably a result of the use of freelists to avoid
> reallocating the tuple objects, though. I don't see any substantial
> difference in access time:

Whoops. Actually it's a result of the 3-element tuple being a constant
in the code object. If we use the constructor, the difference mostly
goes away.

$ python3 -m timeit 't = tuple(range(1000, 4000, 1000))'
1000000 loops, best of 3: 0.559 usec per loop
$ python3 -m timeit 't = list(range(1000, 4000, 1000))'
1000000 loops, best of 3: 0.585 usec per loop

[toc] | [prev] | [next] | [standalone]


#83453

FromWolfgang Maier <wolfgang.maier@biologie.uni-freiburg.de>
Date2015-01-09 16:50 +0100
Message-ID<mailman.17532.1420818709.18130.python-list@python.org>
In reply to#83443
On 01/09/2015 03:44 PM, Adam Funk wrote:
> I noticed in use that if an option with the 'append' action isn't
> used, argparse assigns None to it rather than an empty list, &
> confirmed this interactively:
>
> #v+
>>>> import argparse
>>>> parser = argparse.ArgumentParser()
>>>> parser.add_argument('--foo', action='append')
> _AppendAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>>> parser.add_argument('--bar', action='append')
> _AppendAction(option_strings=['--bar'], dest='bar', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>>> parser.parse_args('--foo 1 --foo 2'.split())
> Namespace(bar=None, foo=['1', '2'])
> #v-
>

Isn't that the exact behaviour documented here:

https://docs.python.org/3/library/argparse.html#default

where it says that the default for the default argument is None ?

I think Skip is right: you should be able to just add

default = []

to your arguments in the add_argument call.

Wolfgang

[toc] | [prev] | [next] | [standalone]


#84599

FromAdam Funk <a24061@ducksburg.com>
Date2015-01-26 13:43 +0000
Message-ID<msshpbxjvv.ln2@news.ducksburg.com>
In reply to#83453
On 2015-01-09, Wolfgang Maier wrote:

> On 01/09/2015 03:44 PM, Adam Funk wrote:
>> I noticed in use that if an option with the 'append' action isn't
>> used, argparse assigns None to it rather than an empty list, &
>> confirmed this interactively:
>>
>> #v+
>>>>> import argparse
>>>>> parser = argparse.ArgumentParser()
>>>>> parser.add_argument('--foo', action='append')
>> _AppendAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>>>> parser.add_argument('--bar', action='append')
>> _AppendAction(option_strings=['--bar'], dest='bar', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>>>> parser.parse_args('--foo 1 --foo 2'.split())
>> Namespace(bar=None, foo=['1', '2'])
>> #v-
>>
>
> Isn't that the exact behaviour documented here:
>
> https://docs.python.org/3/library/argparse.html#default
>
> where it says that the default for the default argument is None ?
>
> I think Skip is right: you should be able to just add
>
> default = []
>
> to your arguments in the add_argument call.

Yes, it works.


-- 
Master Foo said: "A man who mistakes secrets for knowledge is like
a man who, seeking light, hugs a candle so closely that he smothers
it and burns his hand."                            --- Eric Raymond

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web