Immuable vs Mutable types
Je suis confus sur ce qu'est un immuable type est. Je sais que le float
objet est considéré comme immuable, avec ce type d'exemple de mon livre:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
Est-il considéré comme immuable en raison de la structure de classe /de la hiérarchie?, sens float
est au top de la classe et qui est son propre appel de méthode. Similaire à ce type d'exemple (même si mon livre dit dict
est mutable):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Alors que quelque chose mutable a des méthodes à l'intérieur de la classe, avec ce type d'exemple:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Aussi, pour la dernière class(SortedKeyDict_a)
, si je passe ce type de jeu de:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
sans appel de la example
méthode, il retourne un dictionnaire. Le SortedKeyDict
avec __new__
drapeaux comme une erreur. J'ai essayé en passant entiers à la RoundFloat
classe avec __new__
et qu'elle avait pas d'erreurs.
- Vous pouvez aussi consulter les affectation de la Liste avec [:] et python lors de l'utilisation de la copie.copie qui j'ai aussi répondu pour plus d'info à propos de la mutabilité.
Vous devez vous connecter pour publier un commentaire.
Quoi? Les flotteurs sont-ils immuables? Mais on ne peut pas faire
N'est pas que "mut" x?
Bien vous acceptez les chaînes sont immuables droit? Mais vous pouvez faire la même chose.
La valeur de la variable change, mais il change en changeant ce que la variable se rapporte. Une mutable peut évoluer de cette façon, et il peut aussi changement "en place".
Ici est la différence.
Des exemples concrets
def f(my_list): my_list = [1, 2, 3]
. Avec le passage par référence en C, la valeur de l'argument pourrait changer en appelant cette fonction. En Python, cette fonction ne fait rien.def f(my_list): my_list[:] = [1, 2, 3]
ferait quelque chose.a += b
parfois est mutation. Et le fait que la cession d'une partie d'un grand objet est parfois synonyme de mutation de ce grand objet, jamais la mutation de la partie—par exemple,a[0] = b
n'est pas mutera[0]
, mais il est sans doute mutera
... c'est pourquoi il peut être préférable de ne pas essayer de mettre les choses en termes de C++ et, au lieu de simplement décrire ce que Python n'est dans ses propres termes...)void f(list* my_list) { my_list = (list*) malloc(sizeof(list)); }
ne changerait pas l'argument, juste de l' (local) de paramètre.x = ([],2) #Immutable type
, puisfunc(x)
puisprint x
peut imprimer quelque chose de différent, par exemple(['a', 'b', 'c'], 2)
.Vous devez comprendre que Python représente l'ensemble de ses données comme des objets. Certains de ces objets comme les listes et les dictionnaires sont mutables, ce qui signifie que vous pouvez en modifier le contenu sans changer leur identité. D'autres objets tels que les entiers, les décimaux, les chaînes et les tuples sont des objets qui ne peuvent pas être modifiés.
Une manière facile à comprendre c'est si vous avez un coup d'oeil à l'un des objets de l'ID.
Ci-dessous vous voyez une chaîne de caractères qui est immuable. Vous ne pouvez pas modifier son contenu. Il va soulever une
TypeError
si vous essayez de le changer. Aussi, si nous attribuer un nouveau contenu, un nouvel objet est créé à la place du contenu en cours de modification.Vous pouvez le faire avec une liste et il ne changera pas les objets de l'identité
Pour en savoir plus sur Python du modèle de données, vous pourriez avoir un coup d'oeil à la référence au langage Python:
Commune immuable type:
int()
,float()
,complex()
str()
,tuple()
,frozenset()
,bytes()
Commune mutable type (presque tout le reste):
list()
,bytearray()
set()
dict()
Un truc pour tester rapidement si un type est mutable ou pas, est d'utiliser
id()
fonction intégrée.Exemples, à l'aide de sur entier,
l'aide sur la liste, l'
id()
. +1.id()
est trompeur ici. Un objet est toujours le même identifiant au cours de sa durée de vie, mais les différents objets qui existent à des moments différents peuvent avoir le même identifiant due à la collecte des déchets.Tout d'abord, si une classe possède des méthodes ou ce que c'est la structure de la classe n'a rien à voir avec la mutabilité.
int
s etfloat
s sont immuable. Si je neIl indique le nom
a
à un1
quelque part dans la mémoire de la première ligne. Sur la deuxième ligne, il semble que1
, ajoute5
, obtient6
, les pointsa
à6
dans la mémoire -- il n'a pas changement la1
à un6
en aucune façon. La même logique s'applique pour les exemples suivants, à l'aide d'autres immuable types:Pour mutable types, je peux faire la chose que actallly modifier la valeur où il est stocké dans la mémoire. Avec:
J'ai créé une liste des emplacements de
1
,2
, et3
dans la mémoire. Si je puis faireJe viens de point
e
à la mêmelist
d
points. Je peux alors faire:Et la liste que les deux
e
etd
points seront mis à jour à ont également les emplacements de4
et5
dans la mémoire.Si je reviens un immuable type et de le faire avec un
tuple
:Puis
f
encore que les points à l' originaltuple
-- vous l'avez indiquég
à un entièrement nouveautuple
.Maintenant, avec votre exemple de
Où vous passez
(qui est un
tuple
detuples
) commeval
, vous obtenez une erreur parce quetuple
s n'avez pas de.clear()
méthode, vous auriez à passerdict(d)
commeval
pour que ça fonctionne, dans ce cas, vous obtiendrez un videSortedKeyDict
comme un résultat.Si vous venez à Python d'une autre langue (à l'exception de celui qui est comme beaucoup de Python, comme Ruby), et d'insister sur la compréhension en termes de cette autre langue, c'est ici où d'habitude les gens se confondre:
En Python, la cession n'est pas de mutation en Python.
En C++, si vous écrivez
a = 2
, vous appeleza.operator=(2)
, qui va muter l'objet stocké dansa
. (Et si il y était pas d'objet stocké dansa
, c'est une erreur.)En Python,
a = 2
ne fait rien pour tout ce qui était stocké dansa
; cela signifie juste que2
est maintenant stocké dansa
à la place. (Et si il y était pas d'objet stocké dansa
, c'est bien.)En fin de compte, c'est en partie un, même les plus profondes distinction.
Une variable dans un langage tel que le C++ est tapé un emplacement dans la mémoire. Si
a
est unint
, cela signifie qu'il est de 4 octets quelque part que le compilateur sait qu'il est censé être interprété comme uneint
. Donc, quand vous nea = 2
, ça change de ce qui est stocké dans les 4 octets de mémoire de0, 0, 0, 1
à0, 0, 0, 2
. Si il y a une autre variable int ailleurs, il a sa propre 4 octets.Une variable dans un langage comme Python est le nom d'un objet qui a sa vie propre. Il y a un objet pour le nombre
1
, et un autre objet pour le nombre2
. Eta
n'est pas 4 octets de mémoire qui sont représentées comme unint
, c'est juste un nom qui pointe à la1
objet. Il ne fait pas de sens poura = 2
à son tour le nombre de 1 dans le numéro 2 (qui donnerait à n'importe quel programmeur Python de trop de pouvoir pour changer le fonctionnement fondamental de l'univers); ce qui est plutôt juste fairea
oublier le1
objet et le point à la2
objet à la place.Donc, si l'affectation n'est pas une mutation, ce qui est une mutation?
a.append(b)
. (Notez que ces méthodes presque toujours de retourNone
). Immuable types n'ont pas une quelconque de ces méthodes, mutable types de d'habitude.a.spam = b
oua[0] = b
. Immuable types ne permettent pas de cession à des attributs ou des éléments, mutable types généralement de permettre à l'un ou l'autre.a += b
, parfois pas. Mutable types généralement muter la valeur, immuable types de ne jamais faire, et de vous en donner une copie à la place (ils calculenta + b
, puis d'affecter le résultat dea
).Mais si l'affectation n'est pas une mutation, quelle est l'affectation d'une partie de l'objet de la mutation? C'est là que ça devient délicat.
a[0] = b
ne pas mutera[0]
(encore une fois, contrairement au C++), mais il ne mutera
(contrairement au C++, sauf de manière indirecte).Tout cela, c'est pourquoi il est probablement mieux pas pour essayer de mettre Python sémantique en termes d'une langue que vous connaissez, et au lieu d'apprendre Python est la sémantique qui leur est propre.
Si un objet est mutable ou non dépend de son type. Cela ne veut pas dépendre de l'existence ou non de certaines méthodes, ni sur la structure de la hiérarchie de classe.
Types définis par l'utilisateur (c'est à dire les classes) sont généralement mutable. Il y a quelques exceptions près, comme de simples sous-classes d'une immuable type. D'autres immuable types incluent certains types intégrés tels que
int
,float
,tuple
etstr
, ainsi que quelques classes Python mis en œuvre dans C.Une explication générale de le "Modèle de Données", chapitre dans la Référence au Langage Python":
Un objet mutable doit avoir au moins une méthode de mesure de la mutation de l'objet. Par exemple, le
list
objet a laappend
méthode, qui aura pour effet de la mutation de l'objet:mais la classe
float
a pas de méthode pour muter un objet float. Vous pouvez le faire:mais la
=
opérande n'est pas une méthode. Qu'il vient de faire une liaison entre la variable et tout ce qui est à la droite de celui-ci, rien d'autre. Il ne change jamais ou crée des objets. C'est une déclaration de ce que la variable de point de, depuis maintenant.Lorsque vous ne
b = b + 0.1
la=
opérande lie la variable à un nouveau flotteur, qui est créé avec te résultat de5 + 0.1
.Lorsque vous affecter une variable à un objet existants, mutable ou pas, le
=
opérande lie la variable de l'objet. Et rien ne se passeDans les deux cas, la
=
juste faire la liaison. Il ne permet pas de modifier ou de créer des objets.Lorsque vous ne
a = 1.0
, le=
opérande n'est pas qui créer le flotteur, mais le1.0
partie de la ligne. En fait, quand vous écrivez1.0
c'est un raccourci pourfloat(1.0)
un appel de constructeur de retourner un objet float. (C'est la raison pour laquelle si vous tapez1.0
et appuyez sur entrée, vous obtenez le "echo"1.0
imprimé ci-dessous, c'est la valeur de retour de la fonction de constructeur vous appelle)Maintenant, si
b
est un flotteur et de vous attribuera = b
, les deux variables pointent vers le même objet, mais en fait, les variables ne peuvent pas communiquer entre eux, parce que l'objet est inmutable, et si vous neb += 1
, maintenantb
point à un nouvel objet, eta
pointe toujours vers le oldone et impossible de savoir ce queb
pointe.mais si
c
est, disons, unlist
, et vous attribuera = c
, maintenanta
etc
peut "communiquer", parce quelist
est mutable, et si vous nec.append('msg')
, puis il suffit de vérifiera
vous obtenez le message.(Par ailleurs, chaque objet a un numéro d'identification unique associée à, que vous pouvez obtenir avec
id(x)
. Ainsi, vous pouvez vérifier si un objet est la même ou pas de vérifier si son id unique a changé.)Différence entre Changeant et Immuable objet
Définitions
Mutable objet: Objet qui peut être modifié après sa création.
Immuable objet: Objet qui ne peut pas être modifié après sa création.
En python va essayer de changer la valeur de l'objet immuable, il donnera à la nouvelle de l'objet.
Mutable Objets
Voici la liste des objets en python qui sont des mutable type:
list
Dictionary
Set
bytearray
user defined classes
Des Objets Immuables
Voici la liste des objets en python qui sont immuables type:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Des Questions Sans Réponse
Questions: Est une chaîne immuable type?
Réponse: oui il est, mais pouvez-vous expliquer cela:
Preuve 1:
Sortie
Dans l'exemple ci-dessus, la chaîne a obtenu une fois créé comme "Bonjour" enfin changé pour "Hello World". Ceci implique que la chaîne est de la mutable type. Mais il n'est pas, nous pouvons vérifier son identité et vérifier si elle est de mutables ou non.
Sortie
Preuve 2:
Sortie
Questions: Est un Tuple immuable type?
Réponse: oui il est
Preuve 1:
Sortie
En d'autres termes, changer la valeur de cette variable
(name)
ou de le laisser seul.Exemple:
vous attendu à ce travail et d'impression bonjour tout le monde mais ceci lancera l'erreur suivante:
L'interprète dit : je ne peux pas changer le premier caractère de cette chaîne
vous aurez à modifier l'ensemble de la
string
afin de rendre cela fonctionne:vérifier ce tableau:
source
my_string = 'h' + my_string[1:]
. Cela va générer une nouvelle chaîne de caractères appelée my_string, et l'original my_string est allé (impressionid(my_string)
pour le vérifier). Bien sûr, ce n'est pas très souple, pour le cas plus général vous pouvez convertir à la liste et à l'arrière:l = list(my_string)
l[0] = 'h'
my_string = ''.join(l)
Il me semble que vous vous battez avec la question de ce que mutable/immuable signifie en fait. Voici donc une simple explenation:
Nous avons d'abord besoin d'une fondation de base de la explenation sur.
Donc penser à tout ce qui vous programme comme un objet virtuel, quelque chose qui est enregistrée dans une mémoire d'ordinateurs comme une séquence de nombres binaires. (N'essayez pas d'imaginer ce trop dur, quand même.^^) Maintenant, dans la plupart des langages informatiques, vous ne fonctionneront pas avec ces nombres binaires directement, mais plutôt, plus vous utilisez une interprétation de nombres binaires.
E. g. vous ne pensez pas à des chiffres comme 0x110, 0xaf0278297319 ou similaire, mais au lieu de cela, vous pensez à des chiffres comme 6 ou des Chaînes de caractères comme "Hello, world". Jamais le moins ces nombres ou de Chaînes de caractères ne sont qu'une interprétation d'un nombre binaire dans la mémoire des ordinateurs. La même chose est vraie pour toute valeur d'une variable.
En bref: Nous ne pas programme avec valeurs réelles, mais avec interprétations de réelles valeurs binaires.
Maintenant nous avons des interprétations qui ne doivent pas être changés par souci de logique et d'autres "trucs sympa" alors qu'il y a des interprétations qui peuvent être changé. Par exemple penser à la simulation d'une ville, en d'autres termes, un programme où il y a beaucoup d'objets virtuels et certains de ces maisons. Maintenant que ces objets virtuels (les maisons) être modifiées et peuvent-ils encore être considérés comme les mêmes maisons? Bien sûr qu'ils le peuvent. Ainsi, ils sont mutables: Ils peuvent être modifiés sans devenir une "complètement" l'objet est différent.
Maintenant, pensez à des nombres entiers: Ce sont également des objets virtuels (des séquences de nombres binaires dans une mémoire d'ordinateurs). Donc, si nous changeons l'un d'entre eux, comme l'incrémentation de la valeur de six à un, est-il encore un six? Bien sûr que non. Ainsi, tout nombre entier est immuable.
Donc: Si un changement dans un objet virtuel signifie qu'il devient réellement un autre objet virtuel, puis il est appelé immuable.
Remarques finales:
(1) ne Jamais mélanger votre expérience du monde réel de changeant et immuable de la programmation dans une certaine langue:
Chaque langage de programmation a une définition de son propre sur les objets qui peuvent être mis en sourdine et ceux qui ne le peut pas.
Ainsi, alors que vous pouvez maintenant comprendre la différence de sens, vous avez encore à apprendre de la mise en œuvre effective pour chaque langage de programmation. ... En effet il y a peut être un objet d'une langue où un 6 peut être coupé pour devenir un 7. Puis, de nouveau, ce serait tout à fait quelques fous ou des choses intéressantes, comme des simulations d'univers parallèles.^^
(2) Cette explenation est certainement pas scientifique, il est destiné à vous aider à saisir la différence entre changeant et immuable.
L'objectif de cette réponse est de créer un lieu unique pour trouver toutes les bonnes idées sur comment savoir si vous avez affaire à une mutation/nonmutating (immuable/mutable), et, si possible, que faire à ce sujet? Il ya des moments où la mutation n'est pas souhaitable et python comportement à cet égard peuvent se sentir contre-intuitif pour les codeurs à venir dans d'autres langues.
Que par un post utile par @mina-gabriel:
mutable/imutable types d'image
L'analyse ci-dessus et en les combinant w/post by @arrakëën:
Ce qui ne peut changer de façon inattendue?
Ce qui peut?
par "de manière inattendue", je veux dire que les programmeurs d'autres langues peuvent ne pas s'attendre à ce comportement (à l'exception ou Ruby, et peut-être quelques autres "Python comme" langues).
Ajouter à cette discussion:
Ce comportement est un avantage quand il vous évite de remplir votre code avec plusieurs copies de la mémoire à manger de grandes structures de données. Mais quand ce n'est pas souhaitable, comment la contourner?
Avec des listes, la solution la plus simple est d'en construire une nouvelle, de cette façon:
list2 = liste(list1)
avec d'autres structures ... la solution peut être plus difficile. Une façon est de faire une boucle par les éléments et de les ajouter à un vide nouvelle structure de données (de même type).
fonctions peuvent muter l'original lorsque vous passez dans des structures mutables. Comment dire?
Approches Non standard (dans le cas utile):
Trouvé ceci sur github publié sous une licence MIT:
Pour les classes personnalisées, @point-virgule suggère de vérifier si il y a un
__hash__
fonction car mutable objets ne devraient pas avoir un__hash__()
fonction.C'est tout ce que j'ai amassé sur ce sujet pour l'instant. D'autres idées, corrections, etc. sont les bienvenus. Merci.
Une façon de pensée de la différence:
Affectations à des objets immuables en python peut être considéré comme profond des copies,
alors que les affectations à mutable objets sont peu profondes
La réponse la plus simple:
Une variable mutable est celui dont la valeur peut varier en place, tandis que dans une immuable changement de variable de la valeur ne se fera pas en place. La modification d'une immuable variable de recréer la même variable.
Exemple:
Va créer une valeur de 5 référencé par x
x -> 5
Cette déclaration va faire y référer à 5 de x
x -------------> 5 <-----------y
Que x étant un entier (immuable type) a été la reconstruction.
Dans l'énoncé, l'expression de l'ERS aura pour conséquence une valeur de 10 et quand il est affecté à G (x), x reconstruire à 10. Alors maintenant,
x--------->10
y--------->5
Pour des objets immuables, la cession crée une nouvelle copie de valeurs, par exemple.
Pour mutable objets, la mission n'est pas de créer une autre copie de valeurs. Par exemple,
x=10
est tout simplement une autre affectation, alors que lesx[2] = 5
appelle une méthode mutateur.int
objets tout simplement un manque de mutateur méthodes, mais la sémantique de python attribution de ne dépendent pas du typeJe n'ai pas lu toutes les réponses, mais la réponse choisie n'est pas correct et je pense que l'auteur a une idée que d'être en mesure de réaffecter une variable signifie que, quel que soit le type de données est mutable. Ce n'est pas le cas. La mutabilité a à voir avec le passage par référence plutôt que de passer par valeur.
Permet de dire que vous avez créé une Liste
Si vous disiez:
Même si vous avez choisi une valeur de B, il sera également réaffecter la valeur. C'est parce que lorsque vous affectez "b = a". Vous êtes de passage à la "Référence" de l'objet plutôt qu'une copie de la valeur. Ce n'est pas le cas avec des cordes, des flotteurs, etc. Cela fait de liste, les dictionnaires et les goûts mutables, mais les booléens, les chars etc immuable.
En Python, il y a un moyen facile de savoir:
Immuable:
Mutable:
Et:
Donc je pense que fonction intégrée est aussi immuable en Python.
Mais je ne comprends vraiment pas comment flotteur fonctionne:
C'est tellement bizarre.
x = (1, 2)
et puis essayer de muterx
, il n'est pas possible. L'un des moyens que j'ai trouvé pour vérifier la mutabilité esthash
, il travaille pour le groupe builtin objets au moins.hash(1)
hash('a')
hash((1, 2))
hash(True)
tous les travaux, ethash([])
hash({})
hash({1, 2})
tous ne fonctionnent pas.hash()
fonctionne si l'objet définit un__hash__()
méthode, même si les classes définies par l'utilisateur sont généralement mutable.hash
méthode est encore assez bon, parce que mutable objets ne devraient pas avoir un__hash__()
méthode, car les décisions clés dans un dictionnaire est juste dangereux.