This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: namedtuple: raise an exception when the given class name would override an existing name
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.4
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: fhaxbox66@googlemail.com, mark.dickinson, martin.panter
Priority: normal Keywords:

Created on 2014-10-06 05:10 by fhaxbox66@googlemail.com, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (5)
msg228641 - (view) Author: Leo (fhaxbox66@googlemail.com) Date: 2014-10-06 05:10
The nametuple function creates classes dynamically. The caller must provide the class name thus overriding any existing object name. 
An overridden object may be garbage-collected
or survive depending on its reference count.

While this behavior is not new to Python, I am unaware of a simple function with such an awkward side effect. 
One might consider this a feature rather than a bug
thus shifting responsibility for carefully passing suitable class names to nametuple. 
However, I believe nametuple should raise an exception
if the provided name would override an existing name. If needed, this behavior could be made 
customizable by a keyword argument override defaulting to False. 

Consequently, the caller would have to delete the object under that 
name explicitly before calling nametuple. This behavior would increase code clarity and eliminate´ a source of subtle
errors. 


The code example given below shows the survival of 
a pre-existing class due to an instance linked to it. As a consequence, two different classes with the same name exist. Only the posterior is, 
however, bound to the
__main__ namespace. The prior is no longer known to that namespace potentially breaking
remote parts of the code.
 

In [1]: from collections import namedtuple

In [2]: AB=namedtuple('AB', ('a','b'))

In [3]: ab=AB(4,9)

In [4]: type(ab)
Out[4]: __main__.AB

In [6]: AB=namedtuple('AB', ('c','d'))

In [7]: type(ab)
Out[7]: __main__.AB

In [8]: ab2=AB(16,25)

In [9]: type(ab2)
Out[9]: __main__.AB

In [10]: type(ab)
Out[10]: __main__.AB

In [11]: ab
Out[11]: AB(a=4, b=9)

In [12]: ab2
Out[12]: AB(c=16, d=25)
msg228647 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2014-10-06 08:39
IMO, this is a horrible idea.  I'd hate for creation of a `namedtuple` class to fail just because there happened to be an existing (perhaps in an as-yet uncollected garbage `namedtuple` class with the same name).  That's the kind of spooky "action at a distance" that makes debugging unnecessarily difficult.

I also think this would be pretty much impossible to implement efficiently. :-)

I'm closing this report here: this behaviour is not a bug, and the suggested exception raising is (IMO) both undesirable and unworkable in practice.  I'd suggest opening a thread on the Python mailing-list if you want to discuss the idea further; if that thread produces a focused, widely accepted proposal, feel free to re-open an issue here.
msg228649 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2014-10-06 09:50
Perhaps Leo doesn’t understand that the name passed to “namedtuple” is just an indicator for debugging etc, and it doesn’t really have to be unique or even correspond with what it is assigned to. I do remember finding it a bit odd that I had to give it a name when I first used “namedtuple”, but I guess it is because all Python function and class objects store their name internally.

>>> AB = namedtuple("Whatever", ("a", "b"))
>>> AB
<class '__main__.Whatever'>
>>> Whatever
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'Whatever' is not defined
>>> Whatever = AB
>>> Whatever
<class '__main__.Whatever'>
msg228659 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2014-10-06 11:06
Right; the underlying problem of having objects that appear to be instances of  the wrong class has nothing to do with namedtuples.  After this sequence:

>>> class A: pass
... 
>>> a = A()
>>> 
>>> class A: pass
... 

We get the following somewhat confusing results:

>>> type(a)
<class '__main__.A'>
>>> A
<class '__main__.A'>
>>> isinstance(a, A)
False

Class factories like namedtuple make it somewhat easier to run into this issue, but it's nothing really to do with namedtuple itself, and it's not something that could be "fixed" without significant language redesign.
msg228681 - (view) Author: Leo (fhaxbox66@googlemail.com) Date: 2014-10-06 13:37
The idea was based on a misunderstanding of the typename argument. I
had erroneously inferred that the namedtuple class object would be
bound to some namespace whereas the only binding is achieved by the
assignment to a local name which may be different from the typename.
And typename can probably even be an empty string.

I agree that the oddities shown in the two code examples are just an
example of a misuse of the freedom a dynamic language grants.

Rereading the docs on nametuple, I think a clarification on the
purpose and proper use of typename might be in order. Most people have
been declaring classes for many years using the class statement. This
implicitly binds the class name to the current namespace. This is why
I was mislead.

Thanks for the helpful feedback.

Leo

On 06/10/2014, Mark Dickinson <report@bugs.python.org> wrote:
>
> Mark Dickinson added the comment:
>
> Right; the underlying problem of having objects that appear to be instances
> of  the wrong class has nothing to do with namedtuples.  After this
> sequence:
>
>>>> class A: pass
> ...
>>>> a = A()
>>>>
>>>> class A: pass
> ...
>
> We get the following somewhat confusing results:
>
>>>> type(a)
> <class '__main__.A'>
>>>> A
> <class '__main__.A'>
>>>> isinstance(a, A)
> False
>
> Class factories like namedtuple make it somewhat easier to run into this
> issue, but it's nothing really to do with namedtuple itself, and it's not
> something that could be "fixed" without significant language redesign.
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue22563>
> _______________________________________
>
History
Date User Action Args
2022-04-11 14:58:08adminsetgithub: 66753
2014-10-06 13:37:08fhaxbox66@googlemail.comsetmessages: + msg228681
2014-10-06 11:06:39mark.dickinsonsetmessages: + msg228659
2014-10-06 09:50:43martin.pantersetnosy: + martin.panter
messages: + msg228649
2014-10-06 08:40:17mark.dickinsonsetstatus: open -> closed
2014-10-06 08:39:31mark.dickinsonsetnosy: + mark.dickinson
messages: + msg228647
resolution: rejected

type: behavior -> enhancement
2014-10-06 05:10:55fhaxbox66@googlemail.comcreate