Quels sont nommés « tuples » en Python?
-
24-10-2019 - |
Question
Lire les en Python 3.1 , j'ai trouvé quelque chose ... inattendu:
Le tuple sys.version_info est maintenant un nom tuple :
Je ne ai entendu parler tuples nommés avant, et je pensais que les éléments pourraient être soit indexés par des nombres (comme dans tuples et listes) ou par touches (comme dans dicts). Je ne pensais pas qu'ils pourraient être indexés dans les deux sens.
Ainsi, mes questions sont:
- Qu'est-ce que sont nommés tuples?
- Comment les utiliser?
- Pourquoi / quand dois-je utiliser nommé tuples au lieu de tuples normaux?
- Pourquoi / quand dois-je utiliser tuples normale au lieu de tuples nommé?
- Y at-il sorte de "liste nommée" (une version mutable du tuple nom)?
La solution
sont essentiellement nommés tuples faciles à créer, types d'objets légers. Nommées instances de tuple peuvent être référencés à l'aide objet comme déréférencement variable ou la syntaxe standard de tuple. Ils peuvent être utilisés de façon similaire à struct
ou d'autres types d'enregistrement commun, sauf qu'ils sont immuables. Ils ont été ajoutés en Python 2.6 et Python 3.0, bien qu'il y ait une recette pour la mise en œuvre en Python 2.4 .
Par exemple, il est courant de représenter un point comme (x, y)
tuple. Cela conduit à un code comme suit:
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)
L'utilisation d'un tuple nommé il devient plus lisible:
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)
Cependant, tuples nommés sont toujours en arrière compatible avec tuples normaux, donc ce qui suit va encore du travail:
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
Ainsi, vous devez utiliser au lieu nommé tuples de tuples où vous pensez que la notation objet va rendre votre code plus pythonique et plus facilement lisible . Personnellement, j'ai commencé à les utiliser pour représenter les types de valeurs très simples, en particulier en les passant en tant que paramètres aux fonctions. Il rend les fonctions plus lisibles, sans voir le contexte de l'emballage tuple.
En outre, vous pouvez également remplacer ordinaires immuable classes qui ont pas de fonctions , seuls les champs avec eux. Vous pouvez même utiliser vos types de tuple nommés classes de base:
class Point(namedtuple('Point', 'x y')):
[...]
Cependant, comme tuples, les attributs de tuples nommés sont immuables:
>>> Point = namedtuple('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
AttributeError: can't set attribute
Si vous voulez être en mesure le changement des valeurs, vous avez besoin d'un autre type. Il y a une recette pratique pour mutable recordtypes qui vous permettent de définir de nouvelles valeurs aux attributs.
>>> 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
Je ne suis pas au courant d'aucune forme de « liste nommée » qui vous permet d'ajouter de nouveaux champs, cependant. Vous pouvez juste utiliser un dictionnaire dans cette situation. Nommés tuples peuvent être convertis en utilisant des dictionnaires pt1._asdict()
qui retourne {'x': 1.0, 'y': 5.0}
et peut être utilisé sur toutes les fonctions habituelles du dictionnaire.
Comme indiqué précédemment, vous devriez consultez la documentation pour plus d'informations à partir de laquelle ces exemples ont été construits.
Autres conseils
namedtuple est un Fonction usine pour faire un classe tuple. Avec cette classe, nous pouvons créer tuples qui sont appelables par nom aussi.
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)
Qu'est-ce que sont nommés tuples?
Un tuple nommé est un tuple.
Il fait tout une boîte tuple.
Mais il est plus que juste un tuple.
Il est une sous-classe spécifique d'un tuple qui est créé par programme à votre cahier des charges, avec des champs nommés et une longueur fixe.
, par exemple, crée une sous-classe de tuple, et en plus d'être de longueur fixe (dans ce cas, trois), il peut être utilisé partout un tuple est utilisé sans casser. Ceci est connu comme substituabilité Liskov:
>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)
instancie:
>>> ant = ANamedTuple(1, 'bar', [])
Nous pouvons inspecter et utiliser ses attributs:
>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']
explication Deeper
Pour comprendre tuples nommé, vous devez d'abord savoir ce qu'est un tuple est. Un tuple est essentiellement un immuable (ne peut pas être changé en place en mémoire) liste.
Voici comment vous pouvez utiliser un tuple régulier:
>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'
Vous pouvez développer un tuple avec décompactage itérables:
>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
sont nommés tuples tuples qui permettent à leurs éléments accessibles par nom au lieu de l'index juste!
Vous faites un namedtuple comme ceci:
>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])
Vous pouvez également utiliser une seule chaîne avec les noms séparés par des espaces, une utilisation un peu plus lisible de l'API:
>>> Student = namedtuple('Student', 'first last grade')
Comment les utiliser?
Vous pouvez faire tuples tout peut faire (voir ci-dessus), ainsi que faire ce qui suit:
>>> 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')
Un intervenant a demandé:
Dans un grand script ou un programme, où définit-on habituellement un tuple nommé?
Les types que vous créez avec namedtuple
sont les classes que vous pouvez créer avec essentiellement un raccourci facile. Les traiter comme des cours. les définir au niveau du module, de sorte que cornichon et d'autres utilisateurs peuvent les trouver.
L'exemple de travail, au niveau du module global:
>>> 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')
Et cela démontre l'échec de rechercher la définition:
>>> 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
Pourquoi / quand dois-je utiliser nommé tuples au lieu de tuples normaux?
Utilisez-les quand il améliore votre code pour avoir la sémantique des éléments de tuple exprimés dans votre code. Vous pouvez les utiliser au lieu d'un objet si vous sinon utiliser un objet avec des attributs de données immuables et aucune fonctionnalité. Vous pouvez également les sous-classe pour ajouter des fonctionnalités, par exemple :
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)
Pourquoi / quand dois-je utiliser tuples normale au lieu de tuples nommé?
Il serait sans doute une régression à passer de l'aide tuples nommé à tuples. Les centres de décision de conception initiaux à savoir si le coût du code supplémentaire impliqué vaut la meilleure lisibilité lorsque le tuple est utilisé.
Il n'y a pas de mémoire supplémentaire utilisé par tuples nommé par rapport tuples.
Y at-il sorte de "liste nommée" (une version mutable du tuple nom)?
Vous cherchez soit un objet rainuré qui implémente toutes les fonctionnalités d'une liste statique de taille ou une liste qui fonctionne comme sous-classé un tuple nom (et qui en quelque sorte bloque la liste de changer la taille.)
A maintenant étendu, et peut-être même substituable Liskov, exemple du premier:
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__)
Et à l'utilisation, juste sous-classe et de définir __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 sont une grande fonctionnalité, ils sont parfaits pour les données contenant. Lorsque vous avez des données que vous utilisez, comme tuples ou dictionnaires « magasin »:
user = dict(name="John", age=20)
ou
user = ("John", 20)
L'approche dictionnaire est écrasante, puisque dict sont mutable et plus lent que tuples. D'autre part, les tuples sont immuables et léger, mais manquent de lisibilité pour un grand nombre d'entrées dans les champs de données.
namedtuples sont le parfait compromis pour les deux approches, ont une grande lisibilité, et immuabilité légèreté (plus ils sont polymorphes!).
tuples nommés permettent une compatibilité descendante avec le code qui vérifie la version comme ceci
>>> sys.version_info[0:2]
(3, 1)
tout en permettant le code de l'avenir d'être plus explicite en utilisant cette syntaxe
>>> sys.version_info.major
3
>>> sys.version_info.minor
1
namedtuple
est l'un des moyens les plus faciles à nettoyer votre code et le rendre plus lisible. Il auto-documents ce qui se passe dans le tuple. les instances Namedtuples sont tout aussi efficace que la mémoire tuples réguliers car ils ne disposent pas des dictionnaires par instance, les rendant plus rapides que les dictionnaires.
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"
Sans nommer chaque élément du tuple, on lirait comme suit:
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"
Il est beaucoup plus difficile de comprendre ce qui se passe dans le premier exemple. Avec un namedtuple, chaque champ a un nom. Et vous accédez par nom plutôt que la position ou de l'indice. Au lieu de p[1]
, nous pouvons l'appeler p.saturation. Il est plus facile à comprendre. Et il semble plus propre.
Création d'une instance de la namedtuple est plus facile que la création d'un dictionnaire.
# 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
Quand pourriez-vous utiliser namedtuple
- Comme vient de le dire, le namedtuple fait comprendre beaucoup tuples Plus facile. Donc, si vous avez besoin de référencer les éléments dans le tuple, puis les créer comme namedtuples tout à fait logique.
- En plus d'être plus léger qu'un dictionnaire, namedtuple aussi maintient l'ordre à la différence du dictionnaire.
- Comme dans l'exemple ci-dessus, il est plus simple de créer une instance de
namedtuple que le dictionnaire. Et faisant référence au point dans le nom
tuple semble plus propre qu'un dictionnaire.
p.hue
plutôt quep['hue']
.
La syntaxe
collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
- namedtuple est dans la bibliothèque de collections.
- typename. C'est le nom de la nouvelle sous-classe tuple
- FIELD_NAMES: une séquence de noms pour chaque champ. Il peut être une séquence
comme dans une
['x', 'y', 'z']
liste ou une chaînex y z
(sans virgules, juste des espaces) oux, y, z
. - changement de nom: Si renommage est
True
, fieldnames incorrects sont automatiquement remplacé par des noms de position. Par exemple,['abc', 'def', 'ghi','abc']
est converti en['abc', '_1', 'ghi', '_3']
, éliminant ainsi le mot-clé'def'
(puisque c'est un mot réservé pour définir des fonctions) et le double nomchamp'abc'
. - bavard: Si bavard est
True
, la définition de classe est imprimée juste avant d'être construit.
Vous pouvez toujours namedtuples d'accès par leur position, si vous le souhaitez. p[1] == p.saturation
. Il décompresse encore comme un tuple régulier.
Méthodes
Toutes les méthodes de tuple régulières sont pris en charge. Ex: min (), max (), len (), dans, non, concaténation (+), index, tranche, etc. Et il y a quelques unes supplémentaires pour namedtuple. Remarque: ces commencent tous avec un trait de soulignement. _replace
, _make
, _asdict
.
_replace
Renvoie une nouvelle instance de tuple nommé remplaçant les champs indiqués avec de nouvelles valeurs.
La syntaxe
somenamedtuple._replace(kwargs)
Exemple
>>>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)
Avis : Les noms de champs ne sont pas entre guillemets; ils sont des mots clés ici.
Rappelez-vous : Tuples sont immuables - même si elles sont namedtuples et ont la méthode _replace
. Le _replace
produit une instance de new
; il ne modifie pas l'original ou de remplacer l'ancienne valeur. Vous pouvez bien sûr sauver le nouveau résultat à la variable. p = p._replace(hue=169)
_make
Donne une nouvelle instance d'une séquence existante ou iterable.
La syntaxe
somenamedtuple._make(iterable)
Exemple
>>>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
Qu'est-ce qui est arrivé avec le dernier? L'élément à l'intérieur de la parenthèse doit être itérable. Ainsi, une liste ou tuple dans les œuvres de parenthèses, mais la séquence de valeurs sans enfermer comme iterable renvoie une erreur.
_asdict
Retourne une nouvelle OrderedDict associant les noms de champ à leur les valeurs correspondantes.
La syntaxe
somenamedtuple._asdict()
Exemple
>>>p._asdict()
OrderedDict([('hue', 169), ('saturation', 0.1), ('luminosity', 0.6)])
Référence : https: // www. reddit.com/r/Python/comments/38ee9d/intro_to_namedtuple/
Il y a aussi la liste nommée qui est similaire à tuple nommé mais mutable https://pypi.python.org/pypi/namedlist
Qu'est-ce que namedtuple?
Comme son nom l'indique, namedtuple est un tuple avec le nom. En tuple standard, nous avons accès à des éléments à l'aide de l'indice, alors que namedtuple permet à l'utilisateur de définir le nom des éléments. Ceci est très pratique des fichiers de traitement particulier csv (valeurs séparées par des virgules) et travailler avec ensemble de données complexes et de grande, où le code devient désordonné avec l'utilisation d'indices (pas pythonique).
Comment les utiliser?
>>>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)
Lecture
>>>#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
Scénario intéressant au format CSV Traitement:
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)
En Python à l'intérieur il y a un bon usage du conteneur appelé un tuple nommé, il peut être utilisé pour créer une définition de classe et a toutes les caractéristiques du tuple d'origine.
En utilisant le nom tuple sera directement appliqué au modèle de classe par défaut pour générer une classe simple, cette méthode permet beaucoup de code pour améliorer la lisibilité et il est également très pratique lors de la définition d'une classe.
Une autre façon (une nouvelle façon) d'utiliser le nom tuple utilise namedtuple du package en tapant: remarques en namedtuple
Soit de l'utilisation de l'exemple de la réponse de haut dans cet article pour voir comment l'utiliser.
(1) Avant d'utiliser le nom tuple, le code est comme ceci:
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)
print(line_length)
(2) Maintenant, nous utilisons le nom tuple
from typing import NamedTuple, Number
hériter de la classe namedtuple et définir le nom de la variable dans la nouvelle classe. test est le nom de la classe.
class test(NamedTuple):
x: Number
y: Number
créer des instances de la classe et attribuer des valeurs à les
pt1 = test(1.0, 5.0) # x is 1.0, and y is 5.0. The order matters
pt2 = test(2.5, 1.5)
utilisez les variables des instances à calculer
line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)
print(line_length)
Essayez ceci:
collections.namedtuple()
En gros, namedtuples
sont faciles à créer, types d'objets légers.
Ils se tournent tuples dans des conteneurs commodes pour des tâches simples.
Avec namedtuples
, vous ne devez pas utiliser des entiers indices pour accéder à des membres d'un tuple.
Exemples:
Code 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
Code 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
Tout le monde a déjà répondu, mais je pense avoir encore quelque chose à ajouter.
namedtuple pourrait être intuitivement considéré comme un raccourci pour définir une classe.
Voir une lourdeur et de manière classique pour définir un 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'
En ce qui concerne 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'