Пропустить до содержимого

Как использовать и исправить named tuples в Python?

CodeMDD.io

Написание питонического и чистого кода с помощью именованных кортежей в Python

Независимо от того, насколько опытным программистом на Python вы являетесь, написание питонического кода является основным навыком для разработчиков Python. В этом руководстве вы повысите этот навык, используя именованные кортежи.

Использование именованных кортежей для написания питонического кода

Python модуль collections предоставляет функцию-фабрику под названием namedtuple(), которая специально разработана, чтобы сделать ваш код более питоническим при работе с кортежами. С помощью namedtuple() вы можете создавать неизменяемые типы последовательностей, которые позволяют вам получать доступ к их значениям, используя описательные имена полей и синтаксис с точкой вместо неясных целочисленных индексов.

Создание классов, похожих на кортежи, с помощью namedtuple()

Вы можете создавать классы, которые напоминают кортежи, с помощью функции namedtuple(). Это полезно, когда вам нужно иметь неизменяемый тип данных с определенными свойствами. Вот как создавать такие классы с помощью namedtuple():

from collections import namedtuple
# Создание именованного кортежа с именем Point
Point = namedtuple('Point', ['x', 'y'])
# Создание экземпляра класса Point
p1 = Point(1, 2)

Предоставление обязательных аргументов для namedtuple()

Когда вы создаете класс с помощью namedtuple(), вы можете указать обязательные аргументы, которые должны быть предоставлены при создании экземпляра класса. Например, в следующем коде аргументы x и y являются обязательными:

from collections import namedtuple
# Создание именованного кортежа с обязательными аргументами
Person = namedtuple('Person', ['name', 'age'], mandatory=True)
# Создание экземпляра класса Person
p1 = Person('John', 25) # OK
p2 = Person() # Raises a TypeError: 'name' is a required argument

Использование необязательных аргументов с namedtuple()

Вы также можете использовать необязательные аргументы при создании класса с помощью namedtuple(). Эти аргументы могут быть опущены при создании экземпляра класса. Вот пример:

from collections import namedtuple
# Создание именованного кортежа с необязательным аргументом
Car = namedtuple('Car', ['brand', 'model', 'year'], defaults=['Unknown'])
# Создание экземпляра класса Car
c1 = Car('Ford', 'Mustang', 2020) # OK
c2 = Car('Toyota', 'Camry') # OK, год будет установлен как "Unknown"

Исследование дополнительных возможностей классов namedtuple

Именованные кортежи предоставляют некоторые дополнительные возможности, которые могут быть полезны при работе с данными. Вот некоторые из них:

Создание экземпляров класса namedtuple из итерируемых объектов

Вы можете создавать экземпляры класса namedtuple из итерируемых объектов, таких как списки или кортежи. Например:

from collections import namedtuple
# Создание именованного кортежа
Point = namedtuple('Point', ['x', 'y'])
# Создание экземпляра класса Point из списка
p1 = Point._make([1, 2])

Преобразование экземпляров класса namedtuple в словари

Вы можете преобразовывать экземпляры класса namedtuple в словари и наоборот. Вот пример преобразования экземпляра класса Point в словарь:

from collections import namedtuple
# Создание именованного кортежа
Point = namedtuple('Point', ['x', 'y'])
# Создание экземпляра класса Point
p1 = Point(1, 2)
# Преобразование экземпляра класса в словарь
point_dict = p1._asdict()

Замена полей в существующих экземплярах класса namedtuple

Вы можете заменить значения полей в существующих экземплярах класса namedtuple. Это полезно, когда вам нужно обновить или изменить данные. Например:

from collections import namedtuple
# Создание именованного кортежа
Point = namedtuple('Point', ['x', 'y'])
# Создание экземпляра класса Point
p1 = Point(1, 2)
# Замена значения поля x в экземпляре класса
p2 = p1._replace(x=3)

Исследование дополнительных атрибутов класса namedtuple

Именованные кортежи предоставляют дополнительные атрибуты, которые вы можете использовать при работе с данными. Вот некоторые из них:

from collections import namedtuple
# Создание именованного кортежа
Point = namedtuple('Point', ['x', 'y'])
# Получение имен полей класса
field_names = Point._fields
# Получение имени класса
class_name = Point._name
# Получение количества полей класса
num_fields = len(Point._fields)

Написание питонического кода с помощью именованных кортежей

Именованные кортежи могут помочь вам писать более питонический код во многих ситуациях. Вот несколько примеров:

Использование имен полей вместо индексов

Использование имен полей вместо индексов делает код более читабельным и понятным. Вот пример:

from collections import namedtuple
# Создание именованного кортежа
Person = namedtuple('Person', ['name', 'age'])
# Создание экземпляра класса Person
p = Person('John', 25)
# Использование имен полей для доступа к значению
name = p.name
age = p.age

Возвращение нескольких именованных значений из функций

Именованные кортежи могут использоваться для возвращения нескольких именованных значений из функций. Вот пример:

from collections import namedtuple
# Создание именованного кортежа
Point = namedtuple('Point', ['x', 'y'])
# Функция, возвращающая несколько именованных значений
def get_coordinates():
return Point(1, 2)
# Использование функции
p = get_coordinates()
x = p.x
y = p.y

Уменьшение количества аргументов у функций

Именованные кортежи могут помочь уменьшить количество аргументов, передаваемых в функцию. Вместо передачи нескольких значений как аргументы функции, вы можете передать один именованный кортеж. Вот пример:

from collections import namedtuple
# Создание именованного кортежа
Rectangle = namedtuple('Rectangle', ['width', 'height'])
# Функция, принимающая один именованный кортеж вместо двух значений
def calculate_area(rectangle):
return rectangle.width * rectangle.height
# Создание экземпляра класса Rectangle
r = Rectangle(10, 5)
# Использование функции
area = calculate_area(r)

Чтение табличных данных из файлов и баз данных

Именованные кортежи могут использоваться для чтения табличных данных из файлов и баз данных. Вот пример:

from collections import namedtuple
# Создание именованного кортежа
Person = namedtuple('Person', ['name', 'age', 'city'])
# Чтение табличных данных из файла и создание экземпляров класса Person
people = []
with open('people.csv') as file:
lines = file.readlines()
for line in lines:
values = line.strip().split(',')
person = Person(*values)
people.append(person)

Использование именованных кортежей по сравнению с другими структурами данных

Именованные кортежи можно использовать вместо других структур данных в определенных ситуациях. Рассмотрим некоторые сравнения:

Именованные кортежи против словарей

Именованные кортежи предлагают более эффективное использование памяти и более быстрое чтение данных по сравнению со словарями. Однако словари более гибкие и могут содержать переменное количество ключей и значений. Выбор между именованными кортежами и словарями зависит от конкретной ситуации и требований вашего проекта.

Именованные кортежи против классов данных

Именованные кортежи предлагают легкий и быстрый способ создания классов данных без необходимости определять класс отдельно. Однако классы данных, созданные с помощью namedtuple(), могут иметь ограниченный набор функций и возможностей по сравнению с полноценными классами, определенными пользователем.

Именованные кортежи против typing.NamedTuple

Модуль typing предоставляет аннотации типов в Python. typing.NamedTuple представляет эквивалент именованного кортежа с аннотациями типов. Когда вам нужно обеспечить аннотации типов для ваших данных, typing.NamedTuple может быть предпочтительным выбором.

Расширение классов именованных кортежей

Вы можете создавать подклассы классов именованных кортежей, чтобы предоставить новые функции или изменить поведение существующих функций. Вот пример:

from collections import namedtuple
# Создание исходного класса именованного кортежа
Point = namedtuple('Point', ['x', 'y'])
# Создание подкласса именованного кортежа
class LabeledPoint(Point):
def __str__(self):
return f"LabeledPoint(x={self.x}, y={self.y})"
# Создание экземпляра класса LabeledPoint
lp = LabeledPoint(1, 2)
# Использование новой функции подкласса
print(lp) # Выводит "LabeledPoint(x=1, y=2)"

Измерение времени создания: кортежи против именованных кортежей

Именованные кортежи обеспечивают быстрый способ создания классов данных с помощью меньшего количества и более ясного кода. Однако они могут быть немного медленнее по сравнению с обычными кортежами, так как именованные кортежи включают дополнительную логику для доступа к полям по именам. В общем случае, разница в производительности между кортежами и именованными кортежами незначительна и зависит от конкретной ситуации.

Заключение

Именованные кортежи - это удобный и эффективный способ создания классов данных в Python. Они позволяют вам писать более питонический код, который легко читать и поддерживать. Вы можете использовать их во многих ситуациях, где вам требуется структура данных с определенными полями. Проведите эксперименты с именованными кортежами в своих проектах и посмотрите, как они могут улучшить ваш код и сделать его более чистым.