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


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

Differences creating tuples and collections.namedtuples

Started byJohn Reid <johnbaronreid@gmail.com>
First post2013-02-18 03:47 -0800
Last post2013-02-19 09:36 +0000
Articles 20 on this page of 33 — 11 participants

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


Contents

  Differences creating tuples and collections.namedtuples John Reid <johnbaronreid@gmail.com> - 2013-02-18 03:47 -0800
    Re: Differences creating tuples and collections.namedtuples Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-02-18 12:03 +0000
    Re: Differences creating tuples and collections.namedtuples Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-02-18 12:05 +0000
    Re: Differences creating tuples and collections.namedtuples Dave Angel <davea@davea.name> - 2013-02-18 07:11 -0500
    Re: Differences creating tuples and collections.namedtuples John Reid <johnbaronreid@gmail.com> - 2013-02-18 13:49 +0000
    Re: Differences creating tuples and collections.namedtuples John Reid <johnbaronreid@gmail.com> - 2013-02-18 13:51 +0000
    Re: Differences creating tuples and collections.namedtuples John Reid <j.reid@mail.cryst.bbk.ac.uk> - 2013-02-18 14:09 +0000
      Re: Differences creating tuples and collections.namedtuples raymond.hettinger@gmail.com - 2013-02-18 23:48 -0800
        Re: Differences creating tuples and collections.namedtuples Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-02-19 08:06 +0000
        Re: Differences creating tuples and collections.namedtuples Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-02-19 08:57 +0000
        Re: Differences creating tuples and collections.namedtuples Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-02-19 08:06 +0000
        Re: Differences creating tuples and collections.namedtuples Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-02-19 08:05 +0000
      Re: Differences creating tuples and collections.namedtuples raymond.hettinger@gmail.com - 2013-02-18 23:48 -0800
    Re: Differences creating tuples and collections.namedtuples Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-02-18 14:15 +0000
    Re: Differences creating tuples and collections.namedtuples John Reid <johnbaronreid@gmail.com> - 2013-02-18 14:18 +0000
    Re: Differences creating tuples and collections.namedtuples Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-02-18 14:12 +0000
    Re: Differences creating tuples and collections.namedtuples John Reid <j.reid@mail.cryst.bbk.ac.uk> - 2013-02-18 14:23 +0000
    Re: Differences creating tuples and collections.namedtuples Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-02-18 14:53 +0000
    Re: Differences creating tuples and collections.namedtuples John Reid <j.reid@mail.cryst.bbk.ac.uk> - 2013-02-18 15:07 +0000
    Re: Differences creating tuples and collections.namedtuples Terry Reedy <tjreedy@udel.edu> - 2013-02-18 16:28 -0500
      Re: Differences creating tuples and collections.namedtuples Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-02-19 11:18 +1100
        Re: Differences creating tuples and collections.namedtuples Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-02-19 01:43 +0000
          Re: Differences creating tuples and collections.namedtuples Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-02-19 14:06 +1100
            Re: Differences creating tuples and collections.namedtuples Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2013-02-19 21:27 +1300
        Re: Differences creating tuples and collections.namedtuples Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2013-02-19 20:54 +1300
        Re: Differences creating tuples and collections.namedtuples John Reid <j.reid@mail.cryst.bbk.ac.uk> - 2013-02-19 09:30 +0000
        Re: Differences creating tuples and collections.namedtuples Terry Reedy <tjreedy@udel.edu> - 2013-02-19 22:38 -0500
          Re: Differences creating tuples and collections.namedtuples Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-02-22 10:38 +0000
        Re: Differences creating tuples and collections.namedtuples Chris Angelico <rosuav@gmail.com> - 2013-02-20 17:50 +1100
          Re: Differences creating tuples and collections.namedtuples Roy Smith <roy@panix.com> - 2013-02-20 09:09 -0500
      Re: Differences creating tuples and collections.namedtuples Roy Smith <roy@panix.com> - 2013-02-18 20:11 -0500
    Re: Differences creating tuples and collections.namedtuples alex23 <wuwei23@gmail.com> - 2013-02-18 17:47 -0800
      Re: Differences creating tuples and collections.namedtuples John Reid <j.reid@mail.cryst.bbk.ac.uk> - 2013-02-19 09:36 +0000

Page 1 of 2  [1] 2  Next page →


#39082 — Differences creating tuples and collections.namedtuples

FromJohn Reid <johnbaronreid@gmail.com>
Date2013-02-18 03:47 -0800
SubjectDifferences creating tuples and collections.namedtuples
Message-ID<7a40a426-baa9-46f8-8f9d-59ba32b044f3@googlegroups.com>
Hi,

I was hoping namedtuples could be used as replacements for tuples in all instances. There seem to be some differences between how tuples and namedtuples are created. For example with a tuple I can do:

a=tuple([1,2,3])

with namedtuples I get a TypeError:

from collections import namedtuple
B=namedtuple('B', 'x y z')
b=B([1,2,3])

TypeError: __new__() takes exactly 4 arguments (2 given)
> <ipython-input-23-d1da2ef851fb>(3)<module>()
      1 from collections import namedtuple
      2 B=namedtuple('B', 'x y z')
----> 3 b=B([1,2,3])

I'm seeing this problem because of the following code in IPython:

def canSequence(obj):
    if isinstance(obj, (list, tuple)):
        t = type(obj)
        return t([can(i) for i in obj])
    else:
        return obj

where obj is a namedtuple and t([can(i) for i in obj]) fails with the TypeError. See http://article.gmane.org/gmane.comp.python.ipython.user/10270 for more info.

Is this a problem with namedtuples, ipython or just a feature?

Thanks,
John.

[toc] | [next] | [standalone]


#39083

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-02-18 12:03 +0000
Message-ID<mailman.1934.1361189017.2939.python-list@python.org>
In reply to#39082
On 18 February 2013 11:47, John Reid <johnbaronreid@gmail.com> wrote:
> Hi,
>
> I was hoping namedtuples could be used as replacements for tuples in all instances.

namedtuples are not really intended to serves as tuples anywhere. They
are intended to provide lightweight, immutable, hashable objects with
*named* (rather than numbered) values.

> There seem to be some differences between how tuples and namedtuples are created. For example with a tuple I can do:
>
> a=tuple([1,2,3])
>
> with namedtuples I get a TypeError:
>
> from collections import namedtuple
> B=namedtuple('B', 'x y z')
> b=B([1,2,3])

For a namedtuple you need to unpack the arguments

b = B(*[1, 2, 3])

or

b = B(1, 2, 3)

>
> TypeError: __new__() takes exactly 4 arguments (2 given)
>> <ipython-input-23-d1da2ef851fb>(3)<module>()
>       1 from collections import namedtuple
>       2 B=namedtuple('B', 'x y z')
> ----> 3 b=B([1,2,3])
>
> I'm seeing this problem because of the following code in IPython:
>
> def canSequence(obj):
>     if isinstance(obj, (list, tuple)):
>         t = type(obj)
>         return t([can(i) for i in obj])
>     else:
>         return obj

What is the point of the code above? If obj is a list or a tuple you
create a new list or tuple with the same data and then return it
otherwise you just return the object. What about:

def canSequence(obj):
    return obj

Or is it that you want to copy the object (but only when it is a tuple
or list). Then how about

def canSequence(obj):
    if isinstance(obj, (list, tuple)):
        return obj[:]
    else:
        return obj

Note that this turns namedtuples into tuples. It might be better to
catch TypeError rather than special casing the types:

def canSequence(obj):
    try:
        return obj[:]
    except TypeError:
        return obj

Or perhaps it would be better to use the copy module (assuming that
the purpose is to copy the object).

>
> where obj is a namedtuple and t([can(i) for i in obj]) fails with the TypeError. See http://article.gmane.org/gmane.comp.python.ipython.user/10270 for more info.
>
> Is this a problem with namedtuples, ipython or just a feature?

I think that it is a problem with the canSequence function.


Oscar

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


#39084

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-02-18 12:05 +0000
Message-ID<mailman.1935.1361189141.2939.python-list@python.org>
In reply to#39082
On 18 February 2013 12:03, Oscar Benjamin <oscar.j.benjamin@gmail.com> wrote:
> On 18 February 2013 11:47, John Reid <johnbaronreid@gmail.com> wrote:
>> I'm seeing this problem because of the following code in IPython:
>>
>> def canSequence(obj):
>>     if isinstance(obj, (list, tuple)):
>>         t = type(obj)
>>         return t([can(i) for i in obj])
>>     else:
>>         return obj
>
> What is the point of the code above? If obj is a list or a tuple you
> create a new list or tuple with the same data and then return it
> otherwise you just return the object. What about:

Sorry, I didn't read this properly. I see that you want apply can() to
all the elements. What is the reason for wanting to preserve the type
of the sequence?


Oscar

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


#39085

FromDave Angel <davea@davea.name>
Date2013-02-18 07:11 -0500
Message-ID<mailman.1936.1361189497.2939.python-list@python.org>
In reply to#39082
On 02/18/2013 06:47 AM, John Reid wrote:
> Hi,
>
> I was hoping namedtuples could be used as replacements for tuples in all instances. There seem to be some differences between how tuples and namedtuples are created. For example with a tuple I can do:
>
> a=tuple([1,2,3])
>
> with namedtuples I get a TypeError:
>
> from collections import namedtuple
> B=namedtuple('B', 'x y z')
> b=B([1,2,3])

You are passing a single list to the constructor, but you specified that 
the namedtuple was to have 3 items.  So you need two more.

>
> TypeError: __new__() takes exactly 4 arguments (2 given)
>> <ipython-input-23-d1da2ef851fb>(3)<module>()
>        1 from collections import namedtuple
>        2 B=namedtuple('B', 'x y z')
> ----> 3 b=B([1,2,3])
>
> I'm seeing this problem because of the following code in IPython:
>
> def canSequence(obj):
>      if isinstance(obj, (list, tuple)):
>          t = type(obj)
>          return t([can(i) for i in obj])
>      else:
>          return obj
>
> where obj is a namedtuple and t([can(i) for i in obj]) fails with the TypeError. See http://article.gmane.org/gmane.comp.python.ipython.user/10270 for more info.
>
> Is this a problem with namedtuples, ipython or just a feature?
>
> Thanks,
> John.
>

If you want one item (list or tuple) to act like 3 separate arguments, 
you could use the "*" operator:

b = B( *[1,2,3] )

or in your canSequence function, if you want a namedTuple
           return t(*[can(i) for i in obj])



-- 
DaveA

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


#39090

FromJohn Reid <johnbaronreid@gmail.com>
Date2013-02-18 13:49 +0000
Message-ID<mailman.1939.1361195360.2939.python-list@python.org>
In reply to#39082
On 18/02/13 12:05, Oscar Benjamin wrote:
> On 18 February 2013 12:03, Oscar Benjamin <oscar.j.benjamin@gmail.com> wrote:
>> On 18 February 2013 11:47, John Reid <johnbaronreid@gmail.com> wrote:
>>> I'm seeing this problem because of the following code in IPython:
>>>
>>> def canSequence(obj):
>>>     if isinstance(obj, (list, tuple)):
>>>         t = type(obj)
>>>         return t([can(i) for i in obj])
>>>     else:
>>>         return obj
>> What is the point of the code above? If obj is a list or a tuple you
>> create a new list or tuple with the same data and then return it
>> otherwise you just return the object. What about:
> Sorry, I didn't read this properly. I see that you want apply can() to
> all the elements. What is the reason for wanting to preserve the type
> of the sequence?
>
>
Well like I said it is not me that wants to do this. It is part of the
code in IPython for sending messages between clients and engines.

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


#39091

FromJohn Reid <johnbaronreid@gmail.com>
Date2013-02-18 13:51 +0000
Message-ID<mailman.1940.1361196430.2939.python-list@python.org>
In reply to#39082
On 18/02/13 12:03, Oscar Benjamin wrote:
> On 18 February 2013 11:47, John Reid <johnbaronreid@gmail.com> wrote:
>> Hi,
>>
>> I was hoping namedtuples could be used as replacements for tuples in all instances.
> namedtuples are not really intended to serves as tuples anywhere. They
> are intended to provide lightweight, immutable, hashable objects with
> *named* (rather than numbered) values.
If they are not supposed to be tuples then calling them namedtuples and
inheriting from tuple seems a little odd.

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


#39092

FromJohn Reid <j.reid@mail.cryst.bbk.ac.uk>
Date2013-02-18 14:09 +0000
Message-ID<mailman.1942.1361196573.2939.python-list@python.org>
In reply to#39082
On 18/02/13 12:11, Dave Angel wrote:
> On 02/18/2013 06:47 AM, John Reid wrote:
>> Hi,
>>
>> I was hoping namedtuples could be used as replacements for tuples in
>> all instances. There seem to be some differences between how tuples
>> and namedtuples are created. For example with a tuple I can do:
>>
>> a=tuple([1,2,3])
>>
>> with namedtuples I get a TypeError:
>>
>> from collections import namedtuple
>> B=namedtuple('B', 'x y z')
>> b=B([1,2,3])
> 
> You are passing a single list to the constructor, but you specified that
> the namedtuple was to have 3 items.  So you need two more.

I'm aware how to construct the namedtuple and the tuple. My point was
that they use different syntaxes for the same operation and this seems
to break ipython. I was wondering if this is a necessary design feature
or perhaps just an oversight on the part of the namedtuple author or
ipython developers.

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


#39188

Fromraymond.hettinger@gmail.com
Date2013-02-18 23:48 -0800
Message-ID<cdf1f2f4-98e8-4456-9b48-ab6fb3aef845@googlegroups.com>
In reply to#39092
On Monday, February 18, 2013 6:09:16 AM UTC-8, John Reid wrote:
> I'm aware how to construct the namedtuple and the tuple. My point was
> that they use different syntaxes for the same operation and this seems
> to break ipython. I was wondering if this is a necessary design feature
> or perhaps just an oversight on the part of the namedtuple author or
> ipython developers.

It was not an oversight on the part of the namedtuple author.
It was a deliberate design decision to improve usability for
named tuple's primary use case.

Consider a namedtuple such as:

     Person = namedtuple('Person', ['name', 'rank', 'serial_number'])

With the current signature, instances can be created like this:

    p = Person('Guido', 'BDFL', 1)

If instead, the __new__ signature matched that of regular tuples,
you would need to write:

   p = Person(('Guido', 'BDFL', 1))

The double parens are awkward.  You would lose tooltips that prompt you for Person(name, rank, serial_number).  You would lose the ability to use keyword arguments such as Person(rank='BDFL', serial_number=1, name='Guido') or Person(**d).  The repr for the namedtuple would lose its eval(repr(t)) roundtrip property.  

If your starting point is an existing iterable such as s=['Guido', 'BDFL', 1], you have a couple of choices:   p=Person(*s) or p=Person._make(s).  The latter form was put it to help avoid unpacking and repacking the arguments.   


Raymond

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


#39197

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-02-19 08:06 +0000
Message-ID<512332a1$0$29881$c3e8da3$5496439d@news.astraweb.com>
In reply to#39188
On Mon, 18 Feb 2013 23:48:46 -0800, raymond.hettinger wrote:

[...]
> If your starting point is an existing iterable such as s=['Guido',
> 'BDFL', 1], you have a couple of choices:   p=Person(*s) or
> p=Person._make(s).  The latter form was put it to help avoid unpacking
> and repacking the arguments.


It might not be obvious to the casual reader, but despite the leading 
underscore, _make is part of the public API for namedtuple:

http://docs.python.org/2/library/collections.html#collections.namedtuple



-- 
Steven

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


#39198

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-02-19 08:57 +0000
Message-ID<51233e75$0$21906$c3e8da3$76491128@news.astraweb.com>
In reply to#39188
Pardon me for the double-post, if any, my news client appears to have 
eaten my first reply.

On Mon, 18 Feb 2013 23:48:46 -0800, raymond.hettinger wrote:

[...]
> If your starting point is an existing iterable such as s=['Guido',
> 'BDFL', 1], you have a couple of choices:   p=Person(*s) or
> p=Person._make(s).  The latter form was put it to help avoid unpacking
> and repacking the arguments.


It might not be obvious to the casual reader, but despite the leading 
underscore, _make is part of the public API for namedtuple:

http://docs.python.org/2/library/collections.html#collections.namedtuple



-- 
Steven

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


#39199

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-02-19 08:06 +0000
Message-ID<51233282$0$21921$c3e8da3$76491128@news.astraweb.com>
In reply to#39188
On Mon, 18 Feb 2013 23:48:46 -0800, raymond.hettinger wrote:

[...]
> If your starting point is an existing iterable such as s=['Guido',
> 'BDFL', 1], you have a couple of choices:   p=Person(*s) or
> p=Person._make(s).  The latter form was put it to help avoid unpacking
> and repacking the arguments.


It might not be obvious to the casual reader, but despite the leading 
underscore, _make is part of the public API for namedtuple:

http://docs.python.org/2/library/collections.html#collections.namedtuple



-- 
Steven

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


#39201

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-02-19 08:05 +0000
Message-ID<51233263$0$21762$c3e8da3$76491128@news.astraweb.com>
In reply to#39188
On Mon, 18 Feb 2013 23:48:46 -0800, raymond.hettinger wrote:

[...]
> If your starting point is an existing iterable such as s=['Guido',
> 'BDFL', 1], you have a couple of choices:   p=Person(*s) or
> p=Person._make(s).  The latter form was put it to help avoid unpacking
> and repacking the arguments.


It might not be obvious to the casual reader, but despite the leading 
underscore, _make is part of the public API for namedtuple:

http://docs.python.org/2/library/collections.html#collections.namedtuple



-- 
Steven

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


#39190

Fromraymond.hettinger@gmail.com
Date2013-02-18 23:48 -0800
Message-ID<mailman.2007.1361260822.2939.python-list@python.org>
In reply to#39092
On Monday, February 18, 2013 6:09:16 AM UTC-8, John Reid wrote:
> I'm aware how to construct the namedtuple and the tuple. My point was
> that they use different syntaxes for the same operation and this seems
> to break ipython. I was wondering if this is a necessary design feature
> or perhaps just an oversight on the part of the namedtuple author or
> ipython developers.

It was not an oversight on the part of the namedtuple author.
It was a deliberate design decision to improve usability for
named tuple's primary use case.

Consider a namedtuple such as:

     Person = namedtuple('Person', ['name', 'rank', 'serial_number'])

With the current signature, instances can be created like this:

    p = Person('Guido', 'BDFL', 1)

If instead, the __new__ signature matched that of regular tuples,
you would need to write:

   p = Person(('Guido', 'BDFL', 1))

The double parens are awkward.  You would lose tooltips that prompt you for Person(name, rank, serial_number).  You would lose the ability to use keyword arguments such as Person(rank='BDFL', serial_number=1, name='Guido') or Person(**d).  The repr for the namedtuple would lose its eval(repr(t)) roundtrip property.  

If your starting point is an existing iterable such as s=['Guido', 'BDFL', 1], you have a couple of choices:   p=Person(*s) or p=Person._make(s).  The latter form was put it to help avoid unpacking and repacking the arguments.   


Raymond

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


#39093

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-02-18 14:15 +0000
Message-ID<mailman.1943.1361196973.2939.python-list@python.org>
In reply to#39082
On 18 February 2013 14:09, John Reid <j.reid@mail.cryst.bbk.ac.uk> wrote:
> On 18/02/13 12:11, Dave Angel wrote:
>> On 02/18/2013 06:47 AM, John Reid wrote:
>>> Hi,
>>>
>>> I was hoping namedtuples could be used as replacements for tuples in
>>> all instances. There seem to be some differences between how tuples
>>> and namedtuples are created. For example with a tuple I can do:
>>>
>>> a=tuple([1,2,3])
>>>
>>> with namedtuples I get a TypeError:
>>>
>>> from collections import namedtuple
>>> B=namedtuple('B', 'x y z')
>>> b=B([1,2,3])
>>
>> You are passing a single list to the constructor, but you specified that
>> the namedtuple was to have 3 items.  So you need two more.
>
> I'm aware how to construct the namedtuple and the tuple. My point was
> that they use different syntaxes for the same operation and this seems
> to break ipython. I was wondering if this is a necessary design feature
> or perhaps just an oversight on the part of the namedtuple author or
> ipython developers.

I would say that depending on isinstance(obj, tuple) was the error. I
can't offer a suggestion as you haven't clarified what the purpose of
this code in canSequence() is or what constraints it is expected to
satisfy.


Oscar

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


#39094

FromJohn Reid <johnbaronreid@gmail.com>
Date2013-02-18 14:18 +0000
Message-ID<mailman.1944.1361197131.2939.python-list@python.org>
In reply to#39082
On 18/02/13 14:12, Oscar Benjamin wrote:
> On 18 February 2013 13:51, John Reid <johnbaronreid@gmail.com> wrote:
>> On 18/02/13 12:03, Oscar Benjamin wrote:
>>> On 18 February 2013 11:47, John Reid <johnbaronreid@gmail.com> wrote:
>>>> Hi,
>>>>
>>>> I was hoping namedtuples could be used as replacements for tuples in all instances.
>>> namedtuples are not really intended to serves as tuples anywhere. They
>>> are intended to provide lightweight, immutable, hashable objects with
>>> *named* (rather than numbered) values.
>> If they are not supposed to be tuples then calling them namedtuples and
>> inheriting from tuple seems a little odd.
> You can use namedtuple instances in places that expect tuples.
> Inheriting from tuples enables them to be all the things I said:
> lightweight, immutable and hashable. The type object itself has a
> different interface for the constructor, though.
>
>
Then I can't use them in every place I use tuples. For example IPython
relies upon the type's interface for the constructor as part of a
serialization mechanism.

I wonder why they have a different interface. It seems to restrict their
usability. No doubt there were other factors involved in the design of
the interface.

John.

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


#39095

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-02-18 14:12 +0000
Message-ID<mailman.1945.1361197214.2939.python-list@python.org>
In reply to#39082
On 18 February 2013 13:51, John Reid <johnbaronreid@gmail.com> wrote:
> On 18/02/13 12:03, Oscar Benjamin wrote:
>> On 18 February 2013 11:47, John Reid <johnbaronreid@gmail.com> wrote:
>>> Hi,
>>>
>>> I was hoping namedtuples could be used as replacements for tuples in all instances.
>> namedtuples are not really intended to serves as tuples anywhere. They
>> are intended to provide lightweight, immutable, hashable objects with
>> *named* (rather than numbered) values.
>
> If they are not supposed to be tuples then calling them namedtuples and
> inheriting from tuple seems a little odd.

You can use namedtuple instances in places that expect tuples.
Inheriting from tuples enables them to be all the things I said:
lightweight, immutable and hashable. The type object itself has a
different interface for the constructor, though.


Oscar

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


#39096

FromJohn Reid <j.reid@mail.cryst.bbk.ac.uk>
Date2013-02-18 14:23 +0000
Message-ID<mailman.1946.1361197396.2939.python-list@python.org>
In reply to#39082

On 18/02/13 14:15, Oscar Benjamin wrote:
> On 18 February 2013 14:09, John Reid <j.reid@mail.cryst.bbk.ac.uk> wrote:
>> On 18/02/13 12:11, Dave Angel wrote:
>>> On 02/18/2013 06:47 AM, John Reid wrote:
>>>> Hi,
>>>>
>>>> I was hoping namedtuples could be used as replacements for tuples in
>>>> all instances. There seem to be some differences between how tuples
>>>> and namedtuples are created. For example with a tuple I can do:
>>>>
>>>> a=tuple([1,2,3])
>>>>
>>>> with namedtuples I get a TypeError:
>>>>
>>>> from collections import namedtuple
>>>> B=namedtuple('B', 'x y z')
>>>> b=B([1,2,3])
>>>
>>> You are passing a single list to the constructor, but you specified that
>>> the namedtuple was to have 3 items.  So you need two more.
>>
>> I'm aware how to construct the namedtuple and the tuple. My point was
>> that they use different syntaxes for the same operation and this seems
>> to break ipython. I was wondering if this is a necessary design feature
>> or perhaps just an oversight on the part of the namedtuple author or
>> ipython developers.
> 
> I would say that depending on isinstance(obj, tuple) was the error. I
> can't offer a suggestion as you haven't clarified what the purpose of
> this code in canSequence() is or what constraints it is expected to
> satisfy.
> 

Like I said it is not my code. I'm hoping the IPython developers can
help me out here. That said it would be nice to know the rationale for
namedtuple.__new__ to have a different signature to tuple.__new__. I'm
guessing namedtuple._make has a similar interface to tuple.__new__. Does
anyone know what the rationale was for this design?

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


#39099

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-02-18 14:53 +0000
Message-ID<mailman.1949.1361199242.2939.python-list@python.org>
In reply to#39082
On 18 February 2013 14:23, John Reid <j.reid@mail.cryst.bbk.ac.uk> wrote:
[snip]
> That said it would be nice to know the rationale for
> namedtuple.__new__ to have a different signature to tuple.__new__. I'm
> guessing namedtuple._make has a similar interface to tuple.__new__. Does
> anyone know what the rationale was for this design?

Because namedtuples use names for the arguments in the constructor:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', 'x y')
>>> p1 = Point(x=2, y=3)
>>> p1
Point(x=2, y=3)
>>> p1.x
2


Oscar

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


#39100

FromJohn Reid <j.reid@mail.cryst.bbk.ac.uk>
Date2013-02-18 15:07 +0000
Message-ID<mailman.1951.1361200036.2939.python-list@python.org>
In reply to#39082
On 18/02/13 14:53, Oscar Benjamin wrote:
> On 18 February 2013 14:23, John Reid <j.reid@mail.cryst.bbk.ac.uk> wrote:
> [snip]
>> That said it would be nice to know the rationale for
>> namedtuple.__new__ to have a different signature to tuple.__new__. I'm
>> guessing namedtuple._make has a similar interface to tuple.__new__. Does
>> anyone know what the rationale was for this design?
> 
> Because namedtuples use names for the arguments in the constructor:
> 
>>>> from collections import namedtuple
>>>> Point = namedtuple('Point', 'x y')
>>>> p1 = Point(x=2, y=3)
>>>> p1
> Point(x=2, y=3)
>>>> p1.x
> 2
> 
That's a good point. I haven't used __new__ much before but wouldn't
something like this __new__() cater for both uses? (Example taken from
namedtuple docs
http://docs.python.org/2/library/collections.html#collections.namedtuple).

>>> Point = namedtuple('Point', ['x', 'y'], verbose=True)
class Point(tuple):
    'Point(x, y)'

    __slots__ = ()

    _fields = ('x', 'y')

    def __new__(_cls, *args, **kwds):
        'Create a new instance of Point(x, y)'
        if args:
            return _tuple.__new__(_cls, args)
        else:
            return _tuple.__new__(_cls, (kwds[f] for f in _fields))

    ...


Perhaps I could subclass namedtuple so that my namedtuples have the
correct signature for __new__.

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


#39130

FromTerry Reedy <tjreedy@udel.edu>
Date2013-02-18 16:28 -0500
Message-ID<mailman.1972.1361222953.2939.python-list@python.org>
In reply to#39082
On 2/18/2013 6:47 AM, John Reid wrote:

> I was hoping namedtuples could be used as replacements for tuples
 >  in all instances.

This is a mistake in the following two senses. First, tuple is a class 
with instances while namedtuple is a class factory that produces 
classes. (One could think of namedtuple as a metaclass, but it was not 
implemented that way.) Second, a tuple instance can have any length and 
different instances can have different lengths. On the other hand, all 
instances of a particular namedtuple class have a fixed length. This 
affects their initialization. So does the fact that Oscar mentioned, 
that fields can be initialized by name.

 > There seem to be some differences between how tuples and namedtuples
 > are created. For example with a tuple I can do:
>
> a=tuple([1,2,3])

But no sensible person would ever do that, since it creates an 
unnecessary list and is equivalent to

a = 1,2,3

The actual api is tuple(iterable). I presume you know that, but it gets 
to the question you ask about 'why the difference?'. The only reason to 
use an explicit tuple() call is when you already have an iterable, 
possibly of unknown length, rather than the individual field objects. In 
the latter case, one should use a display.

> with namedtuples I get a TypeError:
>
> from collections import namedtuple
> B=namedtuple('B', 'x y z')
> b=B([1,2,3])

There is no namedtuple B display, so one *must* use an explicit call 
with the proper number of args. The simplest possibility is B(val0, 
val1, val2). Initializaing a namedtuple from an iterable is unusual, and 
hence gets the longer syntax. In other words, the typical use case for a 
namedtuple class is to replace statements that have tuple display.

     return a, b, c
to
     return B(a, b, c)

or
     x = a, b, c
to
     x = B(a, b, c)

It is much less common to change tuple(iterable) to B(iterable).

> def canSequence(obj):
>      if isinstance(obj, (list, tuple)):
>          t = type(obj)
>          return t([can(i) for i in obj])
>      else:
>          return obj

The first return could also be written t(map(can, obj)) or, in Python 3,
t(can(i) for i in obj).

> where obj is a namedtuple and t([can(i) for i in obj]) fails with the TypeError. See http://article.gmane.org/gmane.comp.python.ipython.user/10270 for more info.
>
> Is this a problem with namedtuples, ipython or just a feature?

With canSequence. If isinstance was available and the above were written 
before list and tuple could be subclassed, canSequence was sensible when 
written. But as Oscar said, it is now a mistake for canSequence to 
assume that all subclasses of list and tuple have the same 
initialization api.

In fact, one reason to subclass a class is to change the initialization 
api. For instance, before python 3, range was a function that returned a 
list. If lists had always been able to be subclasses, it might instead 
have been written as a list subclass that attached the start, stop, and 
step values, like so:

# python 3
class rangelist(list):
      def __init__(self, *args):
           r = range(*args)
           self.extend(r)
           self.start = r.start
           self.stop = r.stop
           self.step = r.step

r10 = rangelist(10)
print(r10, r10.start, r10.stop, r10.step)
 >>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 0 10 1

However, define can() and canSequence(r10) will raise a TypeError, just 
as with a namedtuple B instance.

TypeError: 'list' object cannot be interpreted as an integer

So, while your question about the namedtuple api is a legitimate one, 
your problem with canSequence is not really about namedtuples, but about 
canSequence making a bad assumption.

-- 
Terry Jan Reedy

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


Page 1 of 2  [1] 2  Next page →

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


csiph-web