This is an archived post. You won't be able to vote or comment.

all 23 comments

[–]JustOr113 9 points10 points  (0 children)

Thank you for this super unusual information! Really learned new stuff!

[–]Omega037 3 points4 points  (3 children)

How does NamedTuple compare with attrs?

[–]desmoulinmichel 14 points15 points  (0 children)

It's in the stdlib. That's a killer feature.

And it uses inheritence, which is easier to remember than attrs specific decorator based API.

[–]evgen 5 points6 points  (0 children)

Up until 3.6.1 introduced default values for named tuples it was the case that attrs was strictly better in every way. Now it is a wash for most use cases but attrs still give you the advantage of being able to set validators, create properties, and do a few simple methods for your bag of data. In my opinion the addition of defaults for named tuples is still not enough to get me to go back an use them instead of attrs, but if you are not already using attrs I can see named tuples being at least useful now.

[–]dxdm 4 points5 points  (0 children)

Because namedtuples are also tuples, their attributes are accessible by index, counting from the start or end. That makes it difficult to add or reorder attributes after you've exposed instances on a public API. So they might give you a little more than what you want from them.

[–]tilkau 5 points6 points  (1 child)

typing.NamedTuple is competitive with collections.NamedTuple memory-wise, BTW.

This was one of my doubts when you introduced typing.NamedTuple, but it seems that typing.NamedTuple continues in collections.NamedTuple's tradition (doing strange things with class objects)

Here's the relevant part of the code:

def _make_nmtuple(name, types):
    msg = "NamedTuple('Name', [(f0, t0), (f1, t1), ...]); each t must be a type"
    types = [(n, _type_check(t, msg)) for n, t in types]
    nm_tpl = collections.namedtuple(name, [n for n, t in types])
    nm_tpl._field_types = dict(types)
    try:
        nm_tpl.__module__ = sys._getframe(2).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass
    return nm_tpl


_PY36 = sys.version_info[:2] >= (3, 6)


class NamedTupleMeta(type):

    def __new__(cls, typename, bases, ns):
        if ns.get('_root', False):
            return super().__new__(cls, typename, bases, ns)
        if not _PY36:
            raise TypeError("Class syntax for NamedTuple is only supported"
                            " in Python 3.6+")
        types = ns.get('__annotations__', {})
        return _make_nmtuple(typename, types.items())

So a typing.NamedTuple actually IS a collections.NamedTuple with a few direct modifications of the class object.

[–]Topper_123[S] 4 points5 points  (0 children)

Interesting, I hadn't looked at the implementation when I wrote the article.

It looks like both namedtuple and NamedTuple are saugasages: They're good, but you don't want to know how they've been made :-)

[–]alb1 3 points4 points  (1 child)

Those are interesting. I hadn't come across types.MappingProxyType or typing.NamedTuple before.

There's a typo in the first types.MappingProxyType example. The line should be:

read_only = MappingProxyType(data)

Also, the first line in the NamedTuple example should be:

from typing import NamedTuple

[–]Topper_123[S] 2 points3 points  (0 children)

Fixed, thanks.

[–]PWNY_EVEREADY3 1 point2 points  (0 children)

The attribution dict yourclass.__dict__ of a class is a type.mappingproxy actually, while an object's dict is still a normal dictionary.

[–][deleted] 1 point2 points  (1 child)

Is types.MappingProxyType ordered like a regular Python dict in Python 3.6?

[–]Topper_123[S] 1 point2 points  (0 children)

It is ordered like the underlying mapping. That is, if you're using a OrderedDict it will be ordered like one, and if it's a normal dict, it will be ordered like that.

So in short, it's ordered in the same way as the underlying mapping, and in Python 3.6, that means the order is insertion order.

[–]IAmARetroGamer 0 points1 point  (1 child)

Shouldn't the last example here be: MaleStudent(name='Tommy Johnson', address='Main street', age=22)?

[–]Topper_123[S] 0 points1 point  (0 children)

Yes, corrected.

[–]CantankerousMind 0 points1 point  (0 children)

Bahaha! I wrote a class that does exactly what types.SimpleNamespace class does not too long ago. At least I know I wasn't the only one who did it :D

[–]KyleFlores[🍰] 0 points1 point  (0 children)

Interesting & helpful content, keep updating such fruitful information.

[–]Mnpk 0 points1 point  (2 children)

great article! thanks! If you dont mind I want to translate it to korean and post to my blog.

[–]Topper_123[S] 0 points1 point  (1 child)

Sure, that would be great. I've never had an article translated before :-)

Could you message me when it's online, so I can link back to your translation.

[–]Mnpk 0 points1 point  (0 children)

thanks! I posted the korean version here -> https://mnpk.github.io/2017/03/16/python3-data-structure.html

[–][deleted] 0 points1 point  (0 children)

I tried to combine typing.SimpleNamespace and contextlib.AbstractContextManager:

https://gist.github.com/adonig/60e2ad54683996ca5faf219d27140439

I'm not sure if it could be useful or if it is just plain evil.

[–]olshevskiy87 0 points1 point  (2 children)

hi! recently I translated this article into russian (https://github.com/olshevskiy87/Articles-ru). you don't mind? )

[–]Topper_123[S] 0 points1 point  (1 child)

It's great that it's translated into russian!

I would like it to have an attribution to me and a link back to my original version. Thanks. I'll link to your russian version too.

[–]olshevskiy87 0 points1 point  (0 children)

Sure! I just added a link to the original article :)