Fri 29 May 2015
Filed under Python
I recently watched the most wonderful talk by Raymond Hettinger at Pycon 2015 about Pep8. Amongst many interesting and important points, he spoke about
namedtuple that I believe he wrote. (It's toward the end of the talk at ~47:00). He posits that the namedtuple is one of the easiest ways to clean up your code and make it more readable. It self-documents what is happening in the tuple.
Another advantage: Namedtuples instances are just as memory efficient as regular tuples as they do not have per-instance dictionaries, making them faster than dictionaries.
Here's the code from his talk:
f```python from collections import namedtuple
Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
p = Color(170, 0.1, 0.6) if p.saturation >= 0.5: print "Whew, that is bright!" if p.luminosity >= 0.5: print "Wow, that is light"
Without naming each element in the tuple, it would read like this: ```python p = (170, 0.1, 0.6) if p >= 0.5: print "Whew, that is bright!" if p>= 0.5: print "Wow, that is light"
It is so much harder to understand what is going on in the first example. With a namedtuple, each field has a name. And you access it by name rather than position or index. Instead of
p, we can call it
p.saturation. It's easier to understand. And it looks cleaner.
Creating an instance of the namedtuple is easier than creating a dictionary.
# dictionary >>>p = dict(hue = 170, saturation = 0.1, luminosity = 0.6) >>>p['hue'] 170 #nametuple >>>from collections import namedtuple >>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity']) >>>p = Color(170, 0.1, 0.6) >>>p.hue 170
When might you use namedtuple
As just stated, the namedtuple makes understanding tuples much easier. So if you need to reference the items in the tuple, then creating them as namedtuples just makes sense.
Besides being more lightweight than a dictionary, namedtuple also keeps the order unlike the dictionary.
As in the example above, it is simpler to create an instance of namedtuple than dictionary. And referencing the item in the named tuple looks cleaner than a dictionary.
p.hue rather than
collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
- namedtuple is in the `collections` library - `typename`: This is the name of the new tuple subclass. - `field_names`: a sequence of names for each field. It can be a sequence as in a list `['x', 'y', 'z']` or string `x y z` (without commas, just whitespace) or `x, y, z`. - `rename`: If rename is `True`, invalid fieldnames are automatically replaced with positional names. For example, ['abc', 'def', 'ghi', 'abc'] is converted to ['abc', '_1', 'ghi', '_3'], eliminating the keyword 'def' (since that is a reserved word for defining functions) and the duplicate fieldname 'abc'. - `verbose`: If verbose is `True`, the class definition is printed just before being built.
You can still access namedtuples by their position, if you so choose.
p == p.saturation
It still unpacks like a regular tuple.
Methods All the regular tuple methods are supported. Ex: min(), max(), len(), in, not in, concatenation (+), index, slice, etc.
And there are a few additional ones for namedtuple. Note: these all start with an underscore.
Returns a new instance of the named tuple replacing specified fields with new values.
>>>from collections import namedtuple >>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity']) >>>p = Color(170, 0.1, 0.6) >>>p._replace(hue=169) Color(169, 0.1, 0.6) >>>p._replace(hue=169, staturation=0.2) Color(169, 0.2, 0.6)
Notice: The field names are not in quotes; they are keywords here.
Remember: Tuples are immutable - even if they are namedtuples and have the
_replace method. The
_replace produces a new instance; it does not modify the original or replace the old value. You can of course save the new result to the variable.
p = p._replace(hue=169)
Makes a new instance from an existing sequence or iterable.
>>>data = (170, 0.1, 0.6) >>>Color._make(data) Color(hue=170, saturation=0.1, luminosity=0.6) >>>Color._make([170, 0.1, 0.6]) #the list is an iterable Color(hue=170, saturation=0.1, luminosity=0.6) >>>Color._make((170, 0.1, 0.6)) #the tuple is an iterable Color(hue=170, saturation=0.1, luminosity=0.6) >>>Color._make(170, 0.1, 0.6) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 15, in _make TypeError: 'float' object is not callable ``` What happened with the last one? The item inside the parenthesis should be the iterable. So a list or tuple inside the parenthesis works, but the sequence of values without enclosing as an iterable returns an error. ###`_asdict` Returns a new [OrderedDict](https://docs.python.org/2/library/collections.html#collections.OrderedDict) which maps field names to their corresponding values. **The syntax** `somenamedtuple._asdict()` **Example** ```python >>>p._asdict() OrderedDict([('hue', 169), ('saturation', 0.1), ('luminosity', 0.6)])