https://docs.python.org/3/library/typing.html#typing.NamedTu...
class Employee(NamedTuple):
name: str
id: int
This is equivalent to: Employee = collections.namedtuple('Employee', ['name', 'id'])https://docs.python.org/3/library/typing.html#typing.NamedTu...
class Employee(NamedTuple):
name: str
id: int
This is equivalent to: Employee = collections.namedtuple('Employee', ['name', 'id']) Pointe = namedtuple('Point'...The class exists, there is an existing valid reference to it, and Python itself knows about it and the class itself knows its own name and namedtuple generates the right __getnewargs__. Everything is there for this to "just work" but pickle expects that every class object will have a reference to it of the same name which is kinda weird when you think about it.
You can see it with this stupid little program.
from collections import namedtuple
import pickle
def get_all_subclasses(cls):
all_subclasses = []
for subclass in cls.__subclasses__():
if subclass != type:
all_subclasses.append(subclass)
all_subclasses.extend(get_all_subclasses(subclass))
return all_subclasses
E = namedtuple('EEEEEEEEEEEEEEEEEEE', 'x')
e = E(x='hello')
for cls in get_all_subclasses(object):
print(cls)
pickle.dumps(e)
You'll that the class it there and called the right thing! But pickle tries to look up a reference to it under __main__.Yeah: its qualname. The qualname, as per PEP 3155, is defined as:
> a dotted path leading to the object from the module top-level
so of course pickle can't cope with this information being incorrect. (How would you make it work?)
This is the part that, to me, is really odd because pickle knows (in theory) the class and module name of the thing it needs to instantiate and the class objects themselves know their name and module.
Up to the lack efficiency actually doing this you could just enumerate all class objects to find the one with the right name and module name.
You get nested classes for free this way and you break the requirement that there be references to class objects of the same name in the module.
[1]: https://stackoverflow.com/questions/4071765/in-python-how-do...
so it is immutable and you can get it via slicing.
>>> from collections import namedtuple
>>> Hat = namedtuple('Hat', ['style', 'size', 'color'])
>>> my_hat = Hat('safari', 'XL', 'Orange')
>>> my_hat
Hat(style='safari', size='XL', color='Orange')
>>> my_hat[0]
'safari'
>>> my_hat.color
'Orange'
>>> my_hat[1:]
('XL', 'Orange')
>>> style, size, color = my_hat
>>> size
'XL'
>>>
If thats all your using your classes for, then a named tuple is probably a better solution, or a dataclass. Though I normally just use dicts in that situation. If I see someone create a class without any methods, or atleast planned methods, I don't let it through code review.EDIT: Also, Raymond Hettinger created named tuples. I'm not normally one for call to authority, or hero worship, but I am a huge fan of his. I recommend that anyone interested in Python should watch as many of his talks as they can.
EDIT2: As masklinn pointed out, another really good use of named tuples is when you're already returning a tuple, and you realize it would be better if it had names. You could change it to a named tuple without breaking any of the existing code. Unless they're doing something dumb like halfassing type checking at runtime. (this use case is in the article, which i didn't read at first)
* extends tuples, so a namedtuple is literally a tuple (which is useful)
* sets up a bunch of properties for the "named fields", which are basically just names on the tuple elements
* sets up a few other utility methods e.g. nice formatting, `_make`, `_asdict`, `_replace`
Now the latter two are nice, and mostly replicated by dataclasses (or attrs). The first one is the raison d'être of namedtuples though: originally their purpose is to "upgrade" tuple return values into richer / clearer types e.g. urlparse originally returned a 6-utple which is not necessarily super wieldy / clear, you can probably infer that the 3rd element is the path but… after upgrading to namedtuple it's just `result.path which is usually much clearer.
And because namedtuples are still classes in and of themselves, you can inherit from them to create a class with a `__dict__` with relative ease.
The reason you reach for it is because it's tedious to write the same methods over and over to get things like a nice repr, methods covert between dicts, or pickling support.
The source from Python 3.6 is much more readable than 3.9 so I recommend reading that if you want to see how it works.
https://github.com/python/cpython/blob/3.6/Lib/collections/_...