Wednesday, May 12, 2021

Real Python: Write Pythonic and Clean Code With namedtuple

Python’s collections module provides a factory function called namedtuple(), which is specially designed to make your code more Pythonic when you’re working with tuples. With namedtuple(), you can create immutable sequence types that allow you to access their values using descriptive field names and the dot notation instead of unclear integer indices.

If you have some experience using Python, then you know that writing Pythonic code is a core skill for Python developers. In this tutorial, you’ll level up that skill using namedtuple.

In this tutorial, you’ll learn how to:

  • Create namedtuple classes using namedtuple()
  • Identify and take advantage of cool features of namedtuple
  • Use namedtuple instances to write Pythonic code
  • Decide whether to use a namedtuple or a similar data structure
  • Subclass a namedtuple to provide new features

To get the most out of this tutorial, you need to have a general understanding of Python’s philosophy related to writing Pythonic and readable code. You also need to know the basics of working with:

If you don’t have all the required knowledge before starting this tutorial, then that’s okay! You can stop and review the above resources as needed.

Free Bonus: Click here to get a Python Cheat Sheet and learn the basics of Python 3, like working with data types, dictionaries, lists, and Python functions.

Using namedtuple to Write Pythonic Code

Python’s namedtuple() is a factory function available in collections. It allows you to create tuple subclasses with named fields. You can access the values in a given named tuple using the dot notation and the field names, like in obj.attr.

Python’s namedtuple was created to improve code readability by providing a way to access values using descriptive field names instead of integer indices, which most of the time don’t provide any context on what the values are. This feature also makes the code cleaner and more maintainable.

In contrast, using indices to values in a regular tuple can be annoying, difficult to read, and error-prone. This is especially true if the tuple has a lot of fields and is constructed far away from where you’re using it.

Note: In this tutorial, you’ll find different terms used to refer to Python’s namedtuple, its factory function, and its instances.

To avoid confusion, here’s a summary of how each term is used throughout the tutorial:

Term Meaning
namedtuple() The factory function
namedtuple, namedtuple class The tuple subclass returned by namedtuple()
namedtuple instance, named tuple An instance of a specific namedtuple class

You’ll find these terms used with their corresponding meaning throughout the tutorial.

Besides this main feature of named tuples, you’ll find out that they:

  • Are immutable data structures
  • Have a consistent hash value
  • Can work as dictionary keys
  • Can be stored in sets
  • Have a helpful docstring based on the type and field names
  • Provide a helpful string representation that prints the tuple content in a name=value format
  • Support indexing
  • Provide additional methods and attributes, such as ._make(), _asdict(), ._fields, and so on
  • Are backward compatible with regular tuples
  • Have similar memory consumption to regular tuples

In general, you can use namedtuple instances wherever you need a tuple-like object. Named tuples have the advantage that they provide a way to access their values using field names and the dot notation. This will make your code more Pythonic.

With this brief introduction to namedtuple and its general features, you can dive deeper into creating and using them in your code.

Creating Tuple-Like Classes With namedtuple()

You use a namedtuple() to create an immutable and tuple-like data structure with field names. A popular example that you’ll find in tutorials about namedtuple is to create a class to represent a mathematical point.

Depending on the problem, you probably want to use an immutable data structure to represent a given point. Here’s how you can create a two-dimensional point using a regular tuple:

>>>
>>> # Create a 2D point as a tuple
>>> point = (2, 4)
>>> point
(2, 4)

>>> # Access coordinate x
>>> point[0]
2
>>> # Access coordinate y
>>> point[1]
4

>>> # Try to update a coordinate value
>>> point[0] = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Here, you create an immutable two-dimensional point using a regular tuple. This code works: You have a point with two coordinates, and you can’t modify any of those coordinates. However, is this code readable? Can you tell up front what the 0 and 1 indices mean? To prevent these ambiguities, you can use a namedtuple like this:

>>>
>>> from collections import namedtuple

>>> # Create a namedtuple type, Point
>>> Point = namedtuple("Point", "x y")
>>> issubclass(type(point), tuple)
True

>>> # Instantiate the new type
>>> point = Point(2, 4)
>>> point
Point(x=2, y=4)

>>> # Dot notation to access coordinates
>>> point.x
2
>>> point.y
4

>>> # Indexing to access coordinates
>>> point[0]
2
>>> point[1]
4

>>> # Named tuples are immutable
>>> point.x = 100
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Now you have a point with two appropriately named fields, x and y. Your point provides a user-friendly and descriptive string representation (Point(x=2, y=4)) by default. It allows you to access the coordinates using the dot notation, which is convenient, readable, and explicit. You can also use indices to access the value of each coordinate.

Note: It’s important to note that, while tuples and named tuples are immutable, the values they store don’t necessarily have to be immutable.

It’s totally legal to create a tuple or a named tuple that holds mutable values:

>>>
>>> from collections import namedtuple

>>> Person = namedtuple("Person", "name children")
>>> john = Person("John Doe", ["Timmy", "Jimmy"])
>>> john
Person(name='John Doe', children=['Timmy', 'Jimmy'])
>>> id(john.children)
139695902374144

>>> john.children.append("Tina")
>>> john
Person(name='John Doe', children=['Timmy', 'Jimmy', 'Tina'])
>>> id(john.children)
139695902374144

>>> hash(john)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

You can create named tuples that contain mutable objects. You can modify the mutable objects in the underlying tuple. However, this doesn’t mean that you’re modifying the tuple itself. The tuple will continue holding the same memory references.

Finally, tuples or named tuples with mutable values aren’t hashable, as you saw in the above example.

Read the full article at https://realpython.com/python-namedtuple/ »


[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]



from Planet Python
via read more

No comments:

Post a Comment

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...