web-dev-qa-db-fra.com

Pourquoi les tuples peuvent-ils contenir des objets mutables?

Si un tuple est immuable, alors pourquoi peut-il contenir des objets mutables?

C'est apparemment une contradiction que lorsqu'un élément modifiable, tel qu'une liste, est modifié, le nuplet auquel il appartient est maintenu immuable.

171
qazwsx

C'est une excellente question.

L'idée clé est que les n-uplets n'ont aucun moyen de savoir si les objets qu'ils contiennent sont mutables. La seule chose qui rend un objet mutable est d'avoir une méthode qui altère ses données. En général, il n'y a aucun moyen de détecter cela.

Une autre idée est que les conteneurs Python ne contiennent en réalité rien. Au lieu de cela, ils conservent des références à d'autres objets. De même, les variables de Python ne ressemblent pas aux variables des langages compilés. au lieu de cela, les noms de variables ne sont que des clés dans un dictionnaire d'espaces de noms où ils sont associés à un objet correspondant. Ned Batchhelder explique bien cela dans son article de blog . Dans les deux cas, les objets ne connaissent que leur nombre de références. ils ne savent pas quelles sont ces références (variables, conteneurs ou Python internes).

Ensemble, ces deux idées expliquent votre mystère (pourquoi un tuple immuable "contenant" une liste semble changer lorsque la liste sous-jacente change). En fait, le tuple n'a pas changé (il contient toujours les mêmes références à d'autres objets qu'auparavant). Le tuple ne pouvait pas changer (car il n’avait pas de méthodes de mutation). Lorsque la liste a changé, le tuple n'a pas été averti du changement (la liste ne sait pas si elle est référée par une variable, un tuple ou une autre liste).

Pendant que nous sommes sur le sujet, voici quelques autres idées pour vous aider à compléter votre modèle mental de ce que sont les n-uplets, comment ils fonctionnent et de leur utilisation prévue:

  1. Les tuples se caractérisent moins par leur immutabilité que par leur but.
    Les tuples sont un moyen utilisé par Python pour collecter des informations hétérogènes sous un même toit. Par exemple, s = ('www.python.org', 80) rassemble une chaîne et un nombre afin que la paire hôte/port puisse être transmise en tant que socket, objet composite. Vu sous cet angle, il est parfaitement raisonnable d’avoir des composants mutables.

  2. L'immuabilité va de pair avec une autre propriété, hashability . Mais la hashabilité n'est pas une propriété absolue. Si l'un des composants du tuple n'est pas obligatoire, l'ensemble du tuple ne l'est pas non plus. Par exemple, t = ('red', [10, 20, 30]) n'est pas obligatoire.

Le dernier exemple montre un 2-Tuple contenant une chaîne et une liste. Le tuple lui-même n'est pas modifiable (c'est-à-dire qu'il n'a aucune méthode permettant de changer son contenu). De même, la chaîne est immuable car les chaînes n'ont aucune méthode de mutation. L'objet de liste a des méthodes de mutation, donc il peut être changé. Cela montre que la mutabilité est une propriété d'un type d'objet - certains objets ont des méthodes de mutation et d'autres pas. Cela ne change pas simplement parce que les objets sont imbriqués.

Rappelez-vous deux choses. Premièrement, l’immutabilité n’est pas magique, c’est simplement l’absence de méthodes de mutation. Deuxièmement, les objets ne savent pas quelles variables ou quels conteneurs les utilisent, ils ne connaissent que le nombre de références.

J'espère que cela vous a été utile :-)

192
Raymond Hettinger

En effet, les n-uplets ne contiennent pas de listes, de chaînes de caractères ou de chiffres. Ils contiennent des références à d'autres objets .1 L'incapacité de changer la séquence de références qu'un Tuple contient ne signifie pas que vous ne pouvez pas muter les objets associés à ces références.2

1. Objets, valeurs et types (voir: avant-dernier paragraphe)
2. La hiérarchie des types standard (voir: "Séquences immuables")

169

Si je comprends bien, cette question doit être reformulée en une question sur les décisions de conception: pourquoi les concepteurs de Python ont-ils choisi de créer un type de séquence immuable pouvant contenir des objets mutables?

Pour répondre à cette question, nous devons réfléchir à l'objectif tuples servir: ils servent comme rapide , séquences d'usage général . Dans cet esprit, il devient évident que les n-uplets sont immuables mais peuvent contenir des objets mutables. En être témoin:

  1. Les tuples sont rapides et efficaces sur le plan mémoire: Les tuples sont plus rapides à créer que les listes car ils sont immuables. L'immuabilité signifie que les n-uplets peuvent être créés en tant que constantes et chargés en tant que tels, en utilisant pliage constant . Cela signifie également qu'ils sont plus rapides et plus efficaces en termes de mémoire, car ils ne nécessitent pas de surallocation, etc. Ils sont un peu plus lent que les listes d'accès aléatoires aux éléments, mais plus rapides pour déballer (au moins sur ma machine). Si les n-uplets étaient mutables, ils ne seraient pas aussi rapides pour des objectifs tels que ceux-ci.

  2. Les tuples sont polyvalents : ils doivent pouvoir contenir n'importe quel type d'objet. Ils sont habitués à (rapidement) faire des choses comme liste d'arguments de longueur variable (via le * opérateur dans les définitions de fonctions). Si les n-uplets ne pouvaient pas contenir d'objets mutables, ils ne serviraient à rien. Python devrait utiliser des listes, ce qui ralentirait probablement les choses et serait certainement moins efficace en termes de mémoire.

Vous voyez donc que, pour remplir leur fonction, les n-uplets doivent être immuables, mais doivent également pouvoir contenir des objets mutables. Si les concepteurs de Python voulaient créer un objet immuable garantissant que tous les objets qu’il "contient" sont également immuables, ils devraient créer un troisième type de séquence. Le gain ne vaut pas la peine. complexité supplémentaire.

16
senderle

Tout d'abord, le mot "immuable" peut signifier différentes choses pour différentes personnes. J'aime particulièrement la manière dont Eric Lippert a classé l'immutabilité dans son blog . Là, il énumère ces sortes d’immuabilité:

  • Immuabilité Realio-trulio
  • Immutabilité une seule fois
  • Immutabilité Popsicle
  • Immutabilité peu profonde vs profonde
  • Façades immuables
  • Immuabilité observationnelle

Celles-ci peuvent être combinées de différentes manières pour créer encore plus de types d'immutabilité, et je suis sûr qu'il en existe plus. Le genre d’immuabilité que vous semblez intéresser à l’immutabilité profonde (ou transitive), dans laquelle les objets immuables ne peuvent contenir que d’autres objets immuables.

Le point clé de ceci est que l'immutabilité profonde n'est qu'un des nombreux types d'immuabilité. Vous pouvez adopter le type de votre choix, à condition que vous sachiez que votre notion d '"immuable" diffère probablement de celle de quelqu'un d'autre "immuable".

16

Vous ne pouvez pas changer le id de ses éléments. Donc, il contiendra toujours les mêmes éléments.

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368
12
kev

Je vais vous expliquer que la partie pertinente ici est que, bien que vous puissiez changer le contenu d'une liste, ou l'état d'un objet, contenu dans un tuple, ce que vous ne pouvez pas changer est that l'objet ou la liste est là. Si vous aviez quelque chose qui dépendait de la chose [3] étant une liste, même vide, alors je pourrais voir cela utile.

5
user1276209

Une des raisons est qu’il n’existe aucun moyen général dans Python de convertir un type mutable en un type immuable (voir le PEP 351! Rejeté] , et le lié à la discussion pourquoi il a été rejeté). Ainsi, il serait impossible de placer différents types d'objets dans des n-uplets s'il y avait cette restriction, y compris à peu près n'importe quel objet non-hashable créé par l'utilisateur.

La seule raison pour laquelle les dictionnaires et les ensembles ont cette restriction est qu'ils exigent que les objets soient hasachables, car ils sont implémentés de manière interne en tant que tables de hachage. Mais notons que, paradoxalement, les dictionnaires et les ensembles eux-mêmes ne sont pas immuables (ou haschables). Les tuples n'utilisent pas le hash d'un objet, sa mutabilité importe donc peu.

3
asmeurer

Un tuple est immuable en ce sens que le tuple lui-même ne peut ni se développer ni se réduire, pas que tous les éléments contenus eux-mêmes soient immuables. Sinon, les tuples sont ternes.

2
adamsmith