Python >> Tutoriel Python >  >> Python

Le guide ultime des tuples Python

Python a plusieurs structures de données intégrées telles que des listes, des ensembles et des dictionnaires (consultez les articles !).
Dans cet article, vous apprendrez tout ce que vous devez savoir sur les tuples, y compris des exemples concrets.

Exemple de motivation de tuple

Avez-vous déjà eu une fonction à partir de laquelle vous vouliez renvoyer plusieurs valeurs ?

Dites, vous avez une fonction translate(text, target_language) qui attend deux arguments. Le premier est le text à traduire en valeur de chaîne et la seconde est le target_language code sous la forme d'une chaîne vers laquelle l'entrée doit être traduite.

Supposons que l'entrée soit toujours en anglais. La sortie doit également avoir deux valeurs :

  • le texte traduit, et
  • une valeur de confiance indiquant la qualité estimée du résultat.

Maintenant, comment pouvons-nous renvoyer les deux valeurs à la fois ?

Une solution très courante consiste à prendre un objet résultat avec un attribut pour chaque valeur. Vous devez d'abord définir cet objet. Selon le contexte de votre programme, cela pourrait être une bonne idée. Cependant, en Python, il existe une option beaucoup plus simple - tuples !

Vidéo

Pas le temps de lire ? Regardez la vidéo !

Caractéristiques des tuples

La structure de données tuple est une structure de données intégrée du langage Python avec les caractéristiques suivantes :

  • Les tuples sont des conteneurs , vous pouvez y stocker des données. La documentation Python définit un conteneur comme un objet qui implémente la méthode __contains__ . En d'autres termes, un conteneur est quelque chose que vous pouvez utiliser le in opérateur activé. D'autres exemples de conteneurs en Python sont list, dict, set ou frozenset. La collection de modules contient plus de types de conteneurs.
  • Les tuples sont ordonnés , chaque élément a sa position ou, à l'inverse, la position a un sens.
  • Les tuples sont itérables , vous pouvez donc les utiliser, par exemple, dans une boucle for.
  • Les tuples sont immuables ce qui signifie que vous ne pouvez pas modifier un tuple une fois qu'il a été créé. Une fois qu'un tuple a été créé, vous ne pouvez plus le modifier. String est un autre exemple de type de données immuable en Python. Vous ne pouvez pas modifier les tuples ou les chaînes en Python, à la place, Python crée une nouvelle instance avec les valeurs modifiées. Cependant, si un tuple contient des types de données mutables tels que des listes, les éléments de ces listes peuvent changer ! Pourtant, les références dans le tuple à ces listes ne le peuvent pas.
  • Les tuples sont hétérogènes car ils peuvent contenir des éléments de plusieurs types de données différents à la fois. Un exemple de type de données homogène sont les chaînes car elles ne peuvent contenir que des caractères.

Syntaxe

Pour créer un tuple, nous mettons des valeurs séparées par des virgules entre parenthèses :

t1 = (1, 2, 3, 'Python')

Et on peut faire encore plus simple, la parenthèse n'est pas obligatoire :

t2 = 1, 2, 3, 'Python'

Les deux méthodes sont parfaitement valides et créent un tuple contenant quatre valeurs, trois entiers et une chaîne. La création d'un tuple est également appelée emballage. Voyons ensuite quelques tuples spéciaux :

empty_tuple = ()
one_element_tuple = 1,

Le tuple vide nécessite des parenthèses, eh bien, parce que c'est tout ce qu'il y a. Si vous souhaitez créer un tuple contenant un seul élément, vous n'avez pas besoin de parenthèses, mais dans ce cas, je recommanderais d'utiliser des parenthèses pour améliorer la lisibilité. Une seule virgule à la fin d'une ligne peut facilement passer inaperçue.

Opérations

Pour les exemples suivants, nous supposons que s et t sont des tuples, x, i, j, k, n sont des entiers.

Syntaxe Explication
x in t Vérifier si le tuple t contient la valeur dans la variable x
x not in t Vérifier si le tuple t ne contient pas la valeur de la variable x.
t + s Concaténer les tuples t et s. Cela crée un nouveau tuple contenant les valeurs de t et s.
t * n Répéter le tuple t n fois. Cela crée un nouveau tuple contenant n fois toutes les valeurs de t.
t[i] Obtenir l'élément à l'index i
t[i:j] Obtenir les éléments de l'index i jusqu'à l'index j (hors j) sous forme de tuple
t[i:j:k] Obtenir les éléments de l'index i jusqu'à l'index j (hors j) en prenant chaque k-ième élément comme tuple
len(t) Renvoie la longueur du tuple
min(t) Renvoie le plus petit élément du tuple
max(t) Renvoie le plus grand élément du tuple
t.count(x) Renvoie le nombre d'occurrences de x dans le tuple

Essayez vous-même :

Exercice pratique :Que se passe-t-il si vous essayez d'assigner une valeur dans un tuple ? (par exemple t[0] = 3 )

Décompresser les tuples

Nous avons déjà vu comment récupérer un seul élément d'un tuple en utilisant l'index. Mais comment récupéreriez-vous tous les éléments d'un tuple ? À l'aide d'indices, vous pouvez effectuer les opérations suivantes :

my_tuple = (1, 2, 3, 4, 5)

one = my_tuple[0]
two = my_tuple[1]
three = my_tuple[2]
four = my_tuple[3]
five = my_tuple[4]

Bien que le code ci-dessus fonctionne, il n'est pas du tout pythonique - ce n'est pas comme ça que vous le faites en Python. En Python, vous pouvez simplement affecter un tuple à plusieurs variables. Ainsi, pour l'exemple ci-dessus, nous écrirons le code suivant :

my_tuple = (1, 2, 3, 4, 5)

one, two, three, four, five = my_tuple

Et c'est tout ce dont nous avons besoin pour obtenir le même résultat que dans le premier extrait. Il est important de mentionner que nous avons besoin d'autant de variables sur le côté gauche qu'il y a de valeurs dans le tuple.

Parfois, nous n'avons pas besoin de toutes les valeurs d'un tuple. Par exemple, disons que nous n'avons besoin que des deux premières et de la dernière valeur de notre tuple. Encore une fois, nous pourrions le faire en utilisant des indices, mais il existe une manière plus pythonique. C'est ce qu'on appelle le déballage étendu, laissez-moi vous montrer comment cela fonctionne :

my_tuple = (1, 2, 3, 4, 5)

one, *_, four, five = my_tuple

Comme vous pouvez le voir, nous avons marqué la variable appelée _ (trait de soulignement) avec un astérisque. Premièrement, cela signifie que "tout le reste" va à cette variable.

Ainsi, après avoir mappé les positions des éléments aux variables, toutes les valeurs restantes vont à la variable marquée d'un astérisque. Cette variable contient une liste d'éléments après l'affectation.

L'autre chose intéressante ici est le nom de la variable _ (trait de soulignement). Bien que cela n'ait rien à voir avec les tuples, c'est une convention générale en Python d'appeler une variable factice ou jetable comme celle-ci. Étant donné que dans l'exemple, nous ne voulions obtenir que la première et les deux dernières valeurs, appelez la variable contenant les valeurs restantes _. Ainsi, lorsqu'un autre programmeur lit le code, il comprend que nous ne nous soucions pas de ces valeurs restantes.

Lorsque vous utilisez le déballage étendu, vous devez être prudent car il doit être sans ambiguïté. Vous ne pouvez pas avoir deux variables avec un astérisque car cela rendrait l'affectation ambiguë.

Travailler avec des tuples

Nous avons déjà vu un cas d'utilisation pour les tuples :renvoyer plusieurs valeurs qui vont ensemble. Si vous souhaitez traiter la sortie d'une telle fonction, vous avez besoin d'une fonction qui accepte un tuple ou vous devez supprimer la structure de données englobante à l'aide de l'opérateur astérisque. Lorsque vous passez un tuple dans un appel de fonction, vous devez utiliser des parenthèses, sinon, Python ne comprendra pas qu'il s'agit d'un tuple et interprétera les valeurs comme des arguments séparés.

Passer des tuples aux fonctions

Si vous voulez passer un tuple dans un appel de fonction, vous devez utiliser des parenthèses.

def func(tup):
    for element in tup:
        print(element)


# call function func
func((1, 2, 3))

Si nous voulons passer un tuple à une fonction où nous voulons utiliser chaque élément du tuple comme paramètre séparé, nous devons supprimer le tuple en utilisant l'opérateur astérisque * .

from math import sqrt

def distance(a, b):
    return sqrt(a**2 + b**2)


point2D = (5, 3)

# call function distance
distance(*point2D)

Essayez-le, que se passe-t-il si vous appelez la fonction distance() sans utiliser l'astérisque devant le tuple.

Tuples nommés

Jusqu'à présent, nous devions savoir à quelle position dans un tuple une certaine valeur est stockée. Par exemple, si nous avons un tuple dot = (1.5, 98, 75, 12, 12.5) , nous devons savoir à quoi correspond chaque nombre. Si vous ne savez pas que l'élément à l'index 0 est censé être le rayon, à l'index 1 est la valeur rouge, à l'index 2 la valeur verte et ainsi de suite, vous ne pourrez pas travailler avec le tuple. Et lorsque vous créez un nouveau tuple, vous devez faire attention à l'ordre des valeurs car leur position leur donne leur sens. Voici où namedtuples entrer en jeu. Si vous souhaitez utiliser namedtuples vous devez import namedtuples from collections . Le module collections fait partie de la bibliothèque standard Python.

Comment utiliser les tuples nommés

from collections import namedtuple

Person = namedtuple('Person', 'name age country')
bob = Person('Bob', 31, 'UK')

Tout d'abord, il est important de noter que le namedtuple importé est une fonction, pas un type de données. Plus précisément namedtuple est une fabrique de classes car c'est une fonction qui crée des classes. Dans notre exemple ci-dessus, nous avons créé une classe appelée Person qui comporte trois éléments :name, age et country. Le premier argument que nous avons passé à namedtuple est notre nom de classe, le deuxième argument est une chaîne de noms d'éléments. Au lieu de la chaîne, nous aurions également pu utiliser un tuple ou une liste de noms d'éléments. Après avoir créé la classe Person nous l'utilisons pour créer une instance de Person. Si le vocabulaire ici vous semble très proche de la POO, vous êtes sur la bonne voie. Bien que namedtuple sont en effet des tuples, sous le capot Python crée une classe.

Avec namedtuple nous n'avons plus besoin de savoir quelle valeur est à quelle position, à la place, nous pouvons simplement accéder aux valeurs par leurs noms, par exemple :

bob.name
bob.age
bob.country

Modifier les tuples nommés

Comme nous l'avons vu précédemment, les tuples ne sont pas modifiables en Python. Depuis namedtuple hériter de tuple , ils sont également immuables. Si nous voulons modifier un tuple, nous devons copier toutes les valeurs dans un nouveau tuple et remplacer les valeurs que nous voulons mettre à jour. Pour ce faire, nous avons plusieurs options :

Découpage

Supposons que c'est l'anniversaire de Bob, alors comment pouvons-nous mettre à jour son enregistrement de données ?

new_values = bob[:1] + (32, ) + bob[2:]
bob = Person(*new_values)

Depuis notre namedtuple Personne ne contient que trois valeurs, le découpage peut sembler un peu surdimensionné mais cela montre l'idée.
Lorsque nous créons le nouveau namedtuple nous devons supprimer le tuple englobant avec l'opérateur astérisque car le constructeur de Person attend trois arguments distincts, pas un tuple. Si vous n'aimez pas l'opérateur astérisque, vous pouvez également utiliser le method _make() pour créer une nouvelle instance de notre namedtuple .

Ensuite, le code ressemble à ceci :

new_values = bob[:1] + (32, ) + bob[2:]
bob = Person._make(new_values)

Mettre à jour les valeurs à l'aide de _replace()

Une autre façon de modifier les valeurs dans un namedtuple est en utilisant le _replace() méthode. Pourtant, à l'esprit, les tuples sont immuables, la modification signifie toujours la création d'un nouveau tuple. Si vous essayez ce qui suit, vous obtenez une erreur :

# Error!
bob.name = 'Alice'

Ainsi, un an plus tard, lors de son prochain anniversaire, Bob déménage aux États-Unis. Comment pouvons-nous mettre à jour notre tuple en utilisant le _replace() méthode maintenant? C'est parti :

bob = bob._replace(age=33, country='US')

C'est ça! Et n'oubliez pas la réaffectation - les tuples sont immuables, en fait nous créons un nouveau tuple !

Étendre les tuples nommés

Maintenant, nous voulons rendre nos données sur les personnes plus précises. Par conséquent, nous voulons ajouter un autre élément appelé ville. Comment pouvons-nous étendre notre tuple Person pour contenir un quatrième élément ?

new_fields = Person._fields + ('City',)
NewPerson = namedtuple('NewPerson', new_fields)

bob = NewPerson(*bob, 'Washington')

Puisque nous ne voulons pas retaper les noms de champ de notre premier tuple Person, nous utilisons simplement l'attribut _fields pour obtenir un tuple de tous les noms de champs. Ensuite, nous ajoutons un tuple avec les noms des champs que nous voulons ajouter. Ensuite, nous créons un nouveau namedtuple avec un champ supplémentaire et créez une nouvelle instance de bob vivant à Washington.

Applications des tuples nommés

Dans certains cas, les tuples nommés peuvent être utilisés à la place des dictionnaires, car non seulement ils sont plus légers que le dictionnaire, mais il est également possible d'accéder aux valeurs avec la notation par points au lieu de dictionnaire['nom_champ'] ou dictionnaire.get( ). Il est très simple de convertir des dictionnaires en tuples nommés et des tuples nommés en dictionnaires.

Convertir un tuple nommé en dictionnaire

C'est très simple car les namedtuples ont une méthode pour _asdict() qui fait le travail pour vous. Voyons donc comment convertir les anciennes données de Bob en dictionnaire :

data_dict = bob._asdict()

Convertir un dictionnaire en Namedtuple

La conversion du dictionnaire en namedtuple est également très simple. Tout ce dont nous avons besoin est l'opérateur à double astérisque ** pour le déballage du dictionnaire. Cela nous laisse avec les entrées du dictionnaire à utiliser comme paramètres de mots-clés.

data = {
    'name': 'Prasanth',
    'age': 27,
    'country': 'India',
}
# Person is the same namedtuple as defined in the examples above
p = Person(**data)

Convertir une liste de dictionnaires en une liste de tuples nommés

Il est courant d'obtenir des données d'une base de données sous la forme d'une liste de dictionnaires. Chaque dictionnaire contient des paires clé-valeur où les clés sont les noms de colonne de la base de données. Supposons que notre requête de base de données renvoie ce résultat :

query_results = [
    {'name': 'Alice', 'age': 25, 'country': 'Spain'},
    {'name': 'Bob', 'age': 33, 'country': 'US'},
    {'name': 'Chloe', 'country': 'France'},
    {'name': 'Dagobert', 'age': 50},
]

Comme vous pouvez le voir, certaines valeurs étaient nulles dans la base de données. Ainsi, certains tuples contiennent moins d'entrées que d'autres. Néanmoins, une fonction assez courte suffit pour obtenir le résultat souhaité :

def create_tuples(results):
    keys = {key for data in results for key in data.keys()}
    Person = namedtuple('Person', sorted(keys))
    Person.__new__.__defaults__ = (None, ) * len(Person._fields)
    return [Person(**data) for data in results]

# call the function
create_tuples(query_results)

Maintenant, nous pouvons très bien travailler avec les données sans aucun problème avec des entrées inexistantes et beaucoup moins de code que ce dont nous aurions eu besoin si nous avions pris la liste des dictionnaires.

Résumé

Les tuples sont une structure de données intégrée du langage Python. Ils sont immuables, vous ne pouvez donc pas modifier les valeurs à l'intérieur. Au lieu de cela, un nouveau tuple doit être créé.

Les tuples sont des conteneurs de données qui vont ensemble, comme les coordonnées x et y d'un point dans l'espace 2D.

Les tuples nommés sont aussi des tuples mais ils ont un avantage décisif :vous pouvez accéder aux éléments du tuple par leur nom, pas seulement par index. Cela permet de convertir facilement entre les tuples nommés et les dictionnaires.

Tout développeur Python avancé doit connaître les tuples car ils sont omniprésents en Python. Après avoir parcouru cet article, vous ne devriez avoir aucun problème pour résoudre le casse-tête de code suivant :

x, *_, y = 1, 2, 3, 4
x, y = y, x

# What's the output?
print(y)

Pour tester si vous avez bien deviné, utilisez le shell interactif suivant pour tester votre supposition :