Что такое "именованные кортежи" в Python?
чтение изменения в Python 3.1, Я кое-что нашел... неожиданно:
функции sys.кортеж version_info теперь является по имени кортеж:
Я никогда не слышал об именованных кортежах раньше, и я думал, что элементы могут быть проиндексированы числами (например, в кортежах и списках) или ключами (например, в диктах). Я никогда не ожидал, что они могут быть проиндексированы в обоих направлениях.
Итак, мои вопросы:
- что именованные кортежи?
- как их использовать?
- почему/когда я должен использовать именованные кортежи вместо обычных кортежей?
- почему/когда я должен использовать обычные кортежи вместо именованных кортежей?
- есть ли какой-либо" именованный список " (изменяемая версия именованного кортежа)?
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
- как только что говорилось, namedtuple делает понимание кортежей много облегчающий. Поэтому, если вам нужно ссылаться на элементы в кортеже, то создание их как namedtuples просто имеет смысл.
- помимо того, что более легкий, чем словарь, namedtuple также сохраняет порядок в отличие от словаря.
- как и в примере выше, проще создать экземпляр 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
. Он все еще распаковывается как обычный кортеж.методы
_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'