Что такое "именованные кортежи" в Python?


чтение изменения в Python 3.1, Я кое-что нашел... неожиданно:

функции sys.кортеж version_info теперь является по имени кортеж:

Я никогда не слышал об именованных кортежах раньше, и я думал, что элементы могут быть проиндексированы числами (например, в кортежах и списках) или ключами (например, в диктах). Я никогда не ожидал, что они могут быть проиндексированы в обоих направлениях.

Итак, мои вопросы:

  • что именованные кортежи?
  • как их использовать?
  • почему/когда я должен использовать именованные кортежи вместо обычных кортежей?
  • почему/когда я должен использовать обычные кортежи вместо именованных кортежей?
  • есть ли какой-либо" именованный список " (изменяемая версия именованного кортежа)?
10 695

10 ответов:

именованные кортежи в основном просты в создании, легкие типы объектов. На именованные экземпляры кортежей можно ссылаться с помощью разыменования объектных переменных или стандартного синтаксиса кортежей. Они могут быть использованы аналогично struct или другие распространенные типы записей, за исключением того, что они неизменяемы. Они были добавлены в Python 2.6 и Python 3.0, хотя есть рецепт реализации в Python 2.4.

например, обычно точку представляют в виде кортежа (x, y). Это приводит к следующему коду:

pt1 = (1.0, 5.0)
pt2 = (2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)

С помощью именованного кортежа он становится более читаемым:

from collections import namedtuple
Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)

однако именованные кортежи по-прежнему обратно совместимы с обычными кортежами, поэтому по-прежнему будет работать следующее:

Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
# use index referencing
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)
 # use tuple unpacking
x1, y1 = pt1

таким образом, вы должны использовать именованные кортежи вместо кортежей, где вы думаете, обозначение объекта сделает ваш код более подходящие для Python и более легко читаемым. Я лично начал использовать их представляют очень простые типы значений, особенно при передаче их в качестве параметров в функции. Это делает функции более читаемыми, не видя контекста упаковки кортежа.

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

class Point(namedtuple('Point', 'x y')):
    [...]

однако, как и в случае с кортежами, атрибуты в именованных кортежах являются неизменный:

>>> Point = namedtuple('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
AttributeError: can't set attribute

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

>>> from rcdtype import *
>>> Point = recordtype('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
>>> print(pt1[0])
    2.0

Я не знаю о какой-либо форме "именованного списка", которая позволяет добавлять новые поля. Вы можете просто использовать словарь в этой ситуации. Именованные кортежи могут быть преобразованы в словари с помощью pt1._asdict() возвращает {'x': 1.0, 'y': 5.0} и может эксплуатироваться по со всеми обычными функциями словаря.

Как уже отмечалось, вы должны Регистрация документации для получения дополнительной информации, из которой были построены эти примеры.

namedtuple - это функции фабрики для создания класса кортежа. С помощью этого класса мы можем создавать кортежи, которые также можно вызывать по имени.

import collections

#Create a namedtuple class with names "a" "b" "c"
Row = collections.namedtuple("Row", ["a", "b", "c"], verbose=False, rename=False)   

row = Row(a=1,b=2,c=3) #Make a namedtuple from the Row class we created

print row    #Prints: Row(a=1, b=2, c=3)
print row.a  #Prints: 1
print row[0] #Prints: 1

row = Row._make([2, 3, 4]) #Make a namedtuple from a list of values

print row   #Prints: Row(a=2, b=3, c=4)

как называются кортежи?

именованный кортеж-кортеж.

он делает все, что кортеж может.

но это больше, чем просто кортеж.

это определенный подкласс кортежа, который программно создается в соответствии с вашей спецификацией, с именованными полями и фиксированной длиной.

это, например, создает подкласс кортежа, и помимо того, что он имеет фиксированную длину (в данном случае три), его можно использовать везде кортеж используется без нарушения. Это известно как заменяемость Лискова:

>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)

это создает его:

>>> ant = ANamedTuple(1, 'bar', [])

мы можем проверить его и использовать его атрибутов:

>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']

более глубокое объяснение

чтобы понять именованные кортежи, вам сначала нужно знать, что такое кортеж. Кортеж по существу является неизменяемым (не может быть изменен на месте в памяти) списком.

вот как вы можете использовать обычный кортеж:

>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'

вы можете развернуть кортеж с итерационной распаковкой:

>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'

именованные кортежи-это кортежи, которые позволяют обращаться к их элементам по имени, а не только по индексу!

вы делаете namedtuple вот так:

>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])

вы также можете использовать одну строку с именами, разделенными пробелами, немного более читаемым использованием API:

>>> Student = namedtuple('Student', 'first last grade')

как их использовать?

вы можете сделать все Кортежи могут делать (см. выше) , а также делать следующее:

>>> named_student_tuple = Student('Lisa', 'Simpson', 'A')
>>> named_student_tuple.first
'Lisa'
>>> named_student_tuple.last
'Simpson'
>>> named_student_tuple.grade
'A'
>>> named_student_tuple._asdict()
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> vars(named_student_tuple)
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> new_named_student_tuple = named_student_tuple._replace(first='Bart', grade='C')
>>> new_named_student_tuple
Student(first='Bart', last='Simpson', grade='C')

комментатор спросил:

в большом сценарии или программе, где обычно определяется именованный кортеж?

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

рабочий пример, на глобальный уровень модуля:

>>> from collections import namedtuple
>>> NT = namedtuple('NT', 'foo bar')
>>> nt = NT('foo', 'bar')
>>> import pickle
>>> pickle.loads(pickle.dumps(nt))
NT(foo='foo', bar='bar')

и это демонстрирует невозможность поиска определения:

>>> def foo():
...     LocalNT = namedtuple('LocalNT', 'foo bar')
...     return LocalNT('foo', 'bar')
... 
>>> pickle.loads(pickle.dumps(foo()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <class '__main__.LocalNT'>: attribute lookup LocalNT on __main__ failed

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

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

class Point(namedtuple('Point', 'x y')):
    """adding functionality to a named tuple"""
        __slots__ = ()
        @property
        def hypot(self):
            return (self.x ** 2 + self.y ** 2) ** 0.5
        def __str__(self):
            return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

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

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

нет дополнительной памяти, используемой кортежей против кортежи.

есть ли какой-либо" именованный список " (изменяемая версия именованного кортежа)?

вы ищете либо щелевой объект, который реализует все функции списка статического размера, либо подклассный список, который работает как именованный кортеж (и который каким-то образом блокирует изменение размера списка.)

а теперь развернутый, и возможно даже Лисков заменяемый, пример первый:

from collections import Sequence

class MutableTuple(Sequence): 
    """Abstract Base Class for objects that work like mutable
    namedtuples. Subclass and define your named fields with 
    __slots__ and away you go.
    """
    __slots__ = ()
    def __init__(self, *args):
        for slot, arg in zip(self.__slots__, args):
            setattr(self, slot, arg)
    def __repr__(self):
        return type(self).__name__ + repr(tuple(self))
    # more direct __iter__ than Sequence's
    def __iter__(self): 
        for name in self.__slots__:
            yield getattr(self, name)
    # Sequence requires __getitem__ & __len__:
    def __getitem__(self, index):
        return getattr(self, self.__slots__[index])
    def __len__(self):
        return len(self.__slots__)

и используйте, просто подкласс и определите __slots__:

class Student(MutableTuple):
    __slots__ = 'first', 'last', 'grade' # customize 


>>> student = Student('Lisa', 'Simpson', 'A')
>>> student
Student('Lisa', 'Simpson', 'A')
>>> first, last, grade = student
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
>>> student[0]
'Lisa'
>>> student[2]
'A'
>>> len(student)
3
>>> 'Lisa' in student
True
>>> 'Bart' in student
False
>>> student.first = 'Bart'
>>> for i in student: print(i)
... 
Bart
Simpson
A

namedtuples-отличная функция, они являются идеальным контейнером для данных. Когда вам нужно "хранить" данные, вы будете использовать кортежи или словари, например:

user = dict(name="John", age=20)

или:

user = ("John", 20)

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

namedtuples являются идеальным компромиссом для двух подходы, имеют большую читаемость, легкость и неизменяемость (плюс они полиморфны!).

именованные кортежи позволяют обратную совместимость с кодом, который проверяет версию, как это

>>> sys.version_info[0:2]
(3, 1)

позволяя будущему коду быть более явным с помощью этого синтаксиса

>>> sys.version_info.major
3
>>> sys.version_info.minor
1

namedtuple

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

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"

не называя каждый элемент в кортеже, он будет выглядеть так:

p = (170, 0.1, 0.6)
if p[1] >= 0.5:
    print "Whew, that is bright!"
if p[2]>= 0.5:
   print "Wow, that is light"

это намного сложнее понять, что происходит в первом примере. С namedtuple, каждое поле имеет имя. И вы получаете доступ к нему по имени, а не по должности или индексу. Вместо p[1], мы можем назвать это p. насыщенность. Это легче понять. И он выглядит чище.

создание экземпляра namedtuple проще, чем создание словаря.

# 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

когда вы можете использовать namedtuple

  1. как только что говорилось, namedtuple делает понимание кортежей много облегчающий. Поэтому, если вам нужно ссылаться на элементы в кортеже, то создание их как namedtuples просто имеет смысл.
  2. помимо того, что более легкий, чем словарь, namedtuple также сохраняет порядок в отличие от словаря.
  3. как и в примере выше, проще создать экземпляр namedtuple, чем словарь. И ссылки на элемент в названном кортеж выглядит чище словаря. p.hue а чем p['hue'].

синтаксис

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
  • namedtuple находится в библиотеке коллекций.
  • typename: это имя нового подкласса кортежа.
  • field_names: последовательность имен для каждого поля. Это может быть последовательность как в списке ['x', 'y', 'z'] или строку x y z (без запятых, просто пробел) или x, y, z.
  • переименовать: если переименовать True, недопустимые имена полей автоматически заменены позиционными именами. Например, ['abc', 'def', 'ghi','abc'] превращается в ['abc', '_1', 'ghi', '_3'], исключения ключевое слово 'def' (так как это зарезервированное слово для определения функций) и дубликат fieldname 'abc'.
  • verbose: если verbose-это True определение класса печатается только до того, как был построен.

вы все еще можете получить доступ к namedtuples по их положению, если вы так хотите. p[1] == p.saturation. Он все еще распаковывается как обычный кортеж.

методы

все обычные методы кортежа!--35--> поддерживаются. Например: min(), max(), len (), in, not in, конкатенация ( + ), индекс, срез и т. д. И есть несколько дополнительных для namedtuple. Примечание: все они начинаются с подчеркивания. _replace,_make,_asdict.

_replace Возвращает новый экземпляр именованного кортежа, заменяющего указанные поля новыми значениями.

в синтаксис

somenamedtuple._replace(kwargs)

пример

>>>from collections import namedtuple

>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)

>>>p._replace(hue=87)
Color(87, 0.1, 0.6)

>>>p._replace(hue=87, saturation=0.2)
Color(87, 0.2, 0.6)

обратите внимание: имена полей не заключены в кавычки; здесь они являются ключевыми словами. помните: кортежи неизменяемы-даже если они являются namedtuples и имеют _replace метод. Элемент _replace производит new экземпляр; он не изменяет исходное или заменить старое значение. Конечно, вы можете сохранить новый результат переменной. p = p._replace(hue=169)

_make

создает новый экземпляр из существующей последовательности или итерации.

синтаксис

somenamedtuple._make(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

что случилось с последним? Элемент внутри круглой скобки должен быть iterable. Таким образом, список или кортеж внутри круглой скобки работает, но последовательность значений без включения в качестве итерационного возвращает ошибка.

_asdict

возвращает новый OrderedDict, который сопоставляет имена полей соответствующими значениями.

синтаксис

somenamedtuple._asdict()

пример

 >>>p._asdict()
OrderedDict([('hue', 169), ('saturation', 0.1), ('luminosity', 0.6)])

ссылка: https://www.reddit.com/r/Python/comments/38ee9d/intro_to_namedtuple/

существует также именованный список, который похож на именованный кортеж но изменчивый https://pypi.python.org/pypi/namedlist

что namedtuple ?

как следует из названия, namedtuple-это кортеж с именем. В стандартном кортеже мы получаем доступ к элементам с помощью индекса, тогда как namedtuple позволяет пользователю определять имя для элементов. Это очень удобно, особенно при обработке csv-файлов (разделенных запятыми) и работе со сложными и большими наборами данных, где код становится беспорядочным с использованием индексов (не так pythonic).

как их использовать ?

>>>from collections import namedtuple
>>>saleRecord = namedtuple('saleRecord','shopId saleDate salesAmout totalCustomers')
>>>
>>>
>>>#Assign values to a named tuple 
>>>shop11=saleRecord(11,'2015-01-01',2300,150) 
>>>shop12=saleRecord(shopId=22,saleDate="2015-01-01",saleAmout=1512,totalCustomers=125)

чтение

>>>#Reading as a namedtuple
>>>print("Shop Id =",shop12.shopId)
12
>>>print("Sale Date=",shop12.saleDate)
2015-01-01
>>>print("Sales Amount =",shop12.salesAmount)
1512
>>>print("Total Customers =",shop12.totalCustomers)
125

интересный сценарий в обработке CSV:

from csv import reader
from collections import namedtuple

saleRecord = namedtuple('saleRecord','shopId saleDate totalSales totalCustomers')
fileHandle = open("salesRecord.csv","r")
csvFieldsList=csv.reader(fileHandle)
for fieldsList in csvFieldsList:
    shopRec = saleRecord._make(fieldsList)
    overAllSales += shopRec.totalSales;

print("Total Sales of The Retail Chain =",overAllSales)

в Python внутри есть хорошее использование контейнера под названием именованный Кортеж, он может быть использован для создания определения класса и имеет все функции исходного кортежа.

использование именованного Кортежа будет непосредственно применено к шаблону класса по умолчанию для создания простого класса, этот метод позволяет много кода для улучшения читаемости, а также очень удобен при определении класса.

попробуйте это:

collections.namedtuple()

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

примеры:

код 1:

>>> from collections import namedtuple

>>> Point = namedtuple('Point','x,y')

>>> pt1 = Point(1,2)

>>> pt2 = Point(3,4)

>>> dot_product = ( pt1.x * pt2.x ) +( pt1.y * pt2.y )

>>> print dot_product
11

код 2:

>>> from collections import namedtuple

>>> Car = namedtuple('Car','Price Mileage Colour Class')

>>> xyz = Car(Price = 100000, Mileage = 30, Colour = 'Cyan', Class = 'Y')

>>> print xyz

Car(Price=100000, Mileage=30, Colour='Cyan', Class='Y')
>>> print xyz.Class
Y

все остальные уже ответили на него, но я думаю, что мне еще есть что добавить.

Namedtuple можно интуитивно рассматривать как ярлык для определения класса.

см. громоздкий и обычный способ определения class .

class Duck:
    def __init__(self, color, weight):
        self.color = color
        self.weight = weight
red_duck = Duck('red', '10')

    In [50]: red_duck
    Out[50]: <__main__.Duck at 0x1068e4e10>
    In [51]: red_duck.color
    Out[51]: 'red'

как namedtuple

from collections import namedtuple
Duck = namedtuple('Duck', ['color', 'weight'])
red_duck = Duck('red', '10')

In [54]: red_duck
Out[54]: Duck(color='red', weight='10')
In [55]: red_duck.color
Out[55]: 'red'