Que sont les "tuples nommés" en Python?

en lisant les changements en python 3.1 , j'ai trouvé quelque chose... inattendu:

Le sys.version_info tuple est maintenant un nommé tuple :

Je n'avais jamais entendu parler de tuples nommés avant, et j'ai pensé que les éléments pourraient être soit indexés par des nombres (comme dans tuples et listes) ou par des clés (comme dans dicts). Je ne m'attendais pas à ce qu'ils soient indexés dans les deux sens.

Ainsi, mes questions sont:

  • comment s'appellent les tuples?
  • Comment les utiliser?
  • pourquoi / quand devrais-je utiliser les tuples nommés à la place des tuples normaux?
  • pourquoi / quand devrais-je utiliser des tuples normaux au lieu des tuples nommés?
  • Existe-t-il une sorte de" named list " (une version mutable du tuple nommé)?
695
demandé sur SilentGhost 2010-06-04 03:50:16

10 réponses

Les tuples nommés

sont des types d'objets légers et faciles à créer. Les instances de tuple nommées peuvent être référencées en utilisant la variable dereferencing ou la syntaxe tuple standard. Ils peuvent être utilisés de la même façon que struct ou d'autres types de documents communs, sauf qu'ils sont immuables. Ils ont été ajoutés en python 2.6 et Python 3.0, bien qu'il existe une recette pour l'implémentation en Python 2.4 .

par exemple, il est commun à représente un point comme un tuple (x, y) . Cela conduit au code suivant:

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)

en utilisant 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, les tuples nommés sont toujours compatibles à l'envers avec les tuples normaux, de sorte que le suivant fonctionnera toujours:

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 devriez utiliser les tuples nommés à la place des tuples n'importe où vous pensez que la notation d'objet rendra votre code plus pythonique et plus facilement lisible . J'ai personnellement commencé à les utiliser pour représenter des types de valeurs très simples, en particulier quand je les passe en tant que paramètres à des fonctions. Il rend les fonctions plus lisibles, sans voir le contexte de l'emballage tuple.

en outre, vous pouvez également remplacer ordinaire immuable classes qui n'ont pas de fonctions , seuls les champs avec eux. Vous pouvez même utiliser votre nommée types de tuples comme classes de base:

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

cependant, comme pour les tuples, les attributs dans les 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 pouvoir changer les valeurs, vous avez besoin d'un autre type. Il existe une recette pratique pour les "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 au courant d'aucune forme de "named list" qui vous permet d'ajouter de nouveaux champs, cependant. Vous pouvez utiliser un dictionnaire dans cette situation. Les tuples nommés peuvent être convertis en dictionnaires en utilisant pt1._asdict() qui retourne {'x': 1.0, 'y': 5.0} et peut être utilisé avec toutes les fonctions dictionnaires habituelles.

comme déjà noté, vous devez vérifier la documentation pour plus d'informations à partir de laquelle ces exemples ont été construits.

933
répondu fmark 2017-05-31 03:58:26

namedtuple est un usine de la fonction pour faire un n-uplet de la classe. Avec cette classe, nous pouvons créer des tuples qui sont rachetables 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)
79
répondu The Demz 2012-12-04 10:30:39

comment s'appellent les tuples?

un tuple nommé est un tuple.

Il fait tout ce qu'un n-uplet peut.

mais c'est plus qu'un tuple.

c'est une sous-classe spécifique d'un tuple qui est créé programmatiquement selon vos spécifications, avec des champs nommés et une longueur fixe.

cela, par exemple, crée une sous-classe de tuple, et à part de longueur fixe (dans ce cas, trois), il peut être utilisé partout où un tuple est utilisé sans se casser. C'est ce qu'on appelle la substituabilité de Liskov:

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

this instanciates it:

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

nous pouvons l'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 plus profonde

pour comprendre les tuples, il faut d'abord savoir ce qu'est un tuple. Un tuple est essentiellement un liste immuable (ne peut pas être changée en place dans la mémoire).

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 étendre un tuple avec déballage itérable:

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

les tuples nommés sont des tuples qui permettent d'accéder à leurs éléments par leur nom au lieu de simplement les indexer!

Vous faites une namedtuple comme ceci:

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

Vous pouvez également utiliser une chaîne unique avec les noms séparés par des espaces, une utilisation légèrement plus lisible de L'API:

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

Comment les utiliser?

Vous pouvez tout faire tuples peuvent le faire (voir ci-dessus) ainsi que d'effectuer les opérations suivantes:

>>> 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 commentateur a demandé:

dans un grand script ou programme, où définit-on habituellement un tuple nommé?

les types que vous créez avec namedtuple sont essentiellement des classes que vous pouvez créer avec la sténographie facile. Les traiter comme des classes. Définissez - les au niveau du module, afin que pickle et les autres utilisateurs puissent les trouver.

exemple pratique, 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 le défaut de chercher 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 devrais-je utiliser les tuples nommés au lieu de tuples normaux?

utilisez-les quand il améliore votre code pour avoir la sémantique des éléments tuple exprimés dans votre code. Vous pouvez les utiliser à la place d'un objet si vous autrement utiliser un objet immuable attributs de données 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 devrais-je utiliser des tuples normaux au lieu de nommé tuples?

ce serait probablement une régression pour passer de l'utilisation de tuples nommés à tuples. La décision de conception initiale est centrée sur la question de savoir si le coût du code supplémentaire en jeu vaut la peine d'être amélioré en termes de lisibilité lorsque le tuple est utilisé.

il n'y a pas de mémoire supplémentaire utilisée par les tuples nommés contre les tuples.

Existe-t-il une sorte de "named list" (une version mutable du tuple nommé)?

vous êtes à la recherche soit d'un objet fendu qui implémente toutes les fonctionnalités d'une liste de taille statique ou d'une liste subclassée qui fonctionne comme un tuple nommé (et qui bloque d'une manière ou d'une autre la liste de changer de taille.)

a maintenant élargi, et peut-être même Liskov substituable, exemple de la première:

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 pour utiliser, juste sous-classe et 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
50
répondu Aaron Hall 2018-07-02 17:38:09

namedtuples sont une grande caractéristique, ils sont des conteneurs parfaits pour les données. Lorsque vous devez "stocker" des données, vous utilisez des tuples ou des dictionnaires, comme:

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

ou:

user = ("John", 20)

Le dictionnaire approche est écrasante, depuis dict sont mutables et plus lents que les n-uplets. D'autre part, les tuples sont immuables et léger, mais le manque de lisibilité pour un grand nombre d'entrées dans les champs de données.

namedtuples sont le compromis parfait pour les deux approches, les ont une grande lisibilité, légèreté et immuabilité (en plus, ils sont polymorphiques!).

37
répondu pygabriel 2011-08-19 14:34:39

les tuples nommés permettent une rétrocompatibilité avec le code qui vérifie la version comme ceci

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

tout en permettant au code futur d'être plus explicite en utilisant cette syntaxe

>>> sys.version_info.major
3
>>> sys.version_info.minor
1
28
répondu John La Rooy 2010-06-04 00:12:23

namedtuple

est l'un des moyens les plus faciles à nettoyer votre code et de le rendre plus lisible. Elle documente elle-même ce qui se passe dans le tuple. Les instances Namedtuples sont aussi efficaces en mémoire que les tuples réguliers, car elles n'ont pas de dictionnaires par instance, ce qui les rend 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, il se lirait comme ceci:

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 tellement plus difficile de comprendre ce qui se passe dans le premier exemple. Avec un attribut named, chaque champ a un nom. Et vous y accédez par nom plutôt que par position ou index. Au lieu de p[1] , nous pouvons l'appeler p. saturation. Il est plus facile à comprendre. Et il a l'air plus propre.

il est plus facile de créer une instance de l'attribut named que de créer 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

  1. comme vient de le dire, l'exemple nommé fait comprendre tuples beaucoup facile. Donc, si vous avez besoin de référencer les éléments du tuple, puis les créer comme des tuplesnomés n'a que du sens.
  2. en plus d'être plus léger qu'un dictionnaire, nommé aussi garde la commande contrairement au dictionnaire.
  3. Comme dans l'exemple ci-dessus, il est plus simple de créer une instance de namedtuple que dictionnaire. Et référencer l'élément dans le nommé tuple a l'air plus propre qu'un dictionnaire. p.hue plutôt que p['hue'] .

la syntaxe

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
  • namedtuple est dans les collections de la bibliothèque.
  • nom typé: 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 liste ['x', 'y', 'z'] ou chaîne x y z (sans virgule, juste whitespace) ou x, y, z .
  • renommer: si renommer est True , les noms de champs invalides sont automatiquement remplacé par position nom. Par exemple, ['abc', 'def', 'ghi','abc'] est converti en ['abc', '_1', 'ghi', '_3'] , ce qui élimine la mot-clé 'def' (puisqu'il s'agit d'un mot réservé pour définir les fonctions)) et le nom de champ dupliqué 'abc' .
  • verbose: si verbose est True , la définition de la classe est imprimée juste avant d'être construit.

vous pouvez toujours accéder à namedtuples par leur position, si vous le souhaitez. p[1] == p.saturation . Il se défait toujours comme un tuple normal.

méthodes

Tous les régulier tuple méthodes sont pris en charge. Ex: min(), max(), len(), dans, pas, de concaténation (+), d'un index, d'une tranche, etc. Et il ya quelques autres pour namedtuple. Note: tout commence par un souligner. _replace , _make , _asdict .

_replace Renvoie une nouvelle instance du tuple nommé remplaçant les champs spécifiés par 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)

Notice : les noms des champs ne sont pas entre guillemets; ce sont des mots-clés ici. Souvenez-vous : n-Uplets sont immuables, même si elles sont namedtuples _replace la méthode. Le _replace produit une instance new ; il ne modifie pas l'original ou ne remplace pas l'ancienne valeur. Vous pouvez bien sûr sauvegarder le nouveau résultat dans la variable. p = p._replace(hue=169)

_make

rend une nouvelle instance à partir d'une séquence existante ou itérable.

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

que s'est-il passé avec le dernier? L'item à l'intérieur de la parenthèse doit être l'itérable. Ainsi une liste ou un tuple à l'intérieur de la parenthèse fonctionne, mais la séquence de valeurs sans enfermer comme une itération retourne une erreur.

_asdict

Renvoie un nouveau OrderedDict qui établit la correspondance entre les noms des champs et leurs 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 est similaire au tuple nommé mais mutable https://pypi.python.org/pypi/namedlist

9
répondu Kevin Zhu 2016-10-28 10:55:04

Quel est le nom de l'échantillon ?

comme son nom l'indique, namedtuple est un tuple avec un nom. Dans le tuple standard, nous accédons aux éléments en utilisant l'index, tandis que namedtuple permet à l'utilisateur de définir le nom des éléments. C'est très pratique surtout pour traiter des fichiers csv (valeur séparée par des virgules) et travailler avec des ensembles de données complexes et volumineux, où le code devient brouillé avec l'utilisation d'indices (pas si 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)

Lire

>>>#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 en 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)
8
répondu Saravanan Subramanian 2015-11-27 07:48:44

en Python à l'intérieur il y a une bonne utilisation de 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 original.

utilisant tuple nommé 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.

5
répondu Marcus Thornton 2013-07-19 03:34:03

essayez ceci:

collections.namedtuple()

en gros, namedtuples sont des types d'objets légers et faciles à créer. Ils transforment les tuples en récipients pratiques pour des tâches simples. Avec namedtuples , vous n'avez pas à utiliser des indices entiers pour accéder aux 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
1
répondu saarthak johari 2018-02-28 19:03:05

tout le monde y a déjà répondu, mais je pense que j'ai encore quelque chose à ajouter.

Namedtuple pourrait être intuitivement considéré comme un raccourci pour définir une classe.

voir une façon lourde et conventionnelle de 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'

comme pour 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'
-1
répondu JawSaw 2017-12-10 02:18:38