Why does namedtuple in python need a name?

2019-07-27 04:13发布

问题:

Why do we need to mention the name Card for namedtuple like below?

import collections

Card = collections.namedtuple('Card', ['rank', 'suit'])

I think a simple Card = collections.namedtuple(['rank', 'suit']) can actually give the same effect right?

For example I can have the same information in a dict like:

card = dict({'rank': 'A', 'suit': 'spade'})

回答1:

No, that won't give the same effect.

collections.namedtuple: Returns a new tuple subclass named typename...

namedtuple returns a subclass of the tuple type, not a tuple instance.

The name parameter specifies the class name of the new subclass, just as you would define a regular Python class and give it a name:

>>> from collections import namedtuple
>>> namedtuple('Card', ['rank', 'suit'], verbose=True)
class Card(tuple):
    'Card(rank, suit)'

    __slots__ = ()

    _fields = ('rank', 'suit')

    def __new__(_cls, rank, suit):
        'Create new instance of Card(rank, suit)'
        return _tuple.__new__(_cls, (rank, suit))
    ...

A quick type check clears every doubt:

>>> type(_), issubclass(_, tuple)
(<class 'type'>, True) 

So there, you have namedtuple, a factory function that returns a subclass of a tuple.



回答2:

When you create a named tuple like this

from collections import namedtuple
Card = namedtuple('Card', ['rank', 'suit'])

You are creating a new class (which is a subclass of tuple)

>>> Card
<class '__main__.Card'>

So for clarity, it is nicer to specifically name the class, as it has it's own specific properties (__init__ takes two arguments, the first becomes the instance's rank attribute, and the second becomes it's suit argument).

The namedtuple author could have used the same name for all of these classes, so it would have looked like <class 'collections.NamedTuple'>. But then how do you tell which one is your new Card class, and which one is your new PokerHands class?