3
votes

Est-il possible de forcer l'immuabilité des données dans une fonction python?

Disons que je définis un objet de liste et que je souhaite uniquement qu'il soit en lecture seule dans une fonction que je définis. En C ++, vous feriez cela avec une référence const. Existe-t-il un moyen de le faire avec une fonction python? Est-ce que cela a du sens par rapport à l'écriture de code "pythonique" ou est-ce que j'essaye simplement d'appliquer un paradigme C ++ de manière incorrecte?


2 commentaires

Utilisez un tuple au lieu d'une liste.


En Python, la mutabilité est une fonctionnalité du type, pas des instances ou des variables spécifiques.


3 Réponses :


2
votes

Utilisez un tuple , à la place:

Immutable object

hash peut définir s'il est mutable ou non, et produit une erreur de TypeError: type unhashable s'il est mutable, comme les list s, OTOH tuple renverra de grands nombres (pas besoin de s'en soucier en particulier case), nous pouvons utiliser un try sauf si vous voulez:

try:
    hash((1,2,3))
    print('Immutable object')
except:
    print('Mutable object')

Quelles sorties:

>>> hash([1,2,3])
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    hash([1,2,3])
TypeError: unhashable type: 'list'
>>> hash((1,2,3))
2528502973977326415
>>> 


0 commentaires

1
votes

En Python, toutes les variables sont des références, donc avoir un équivalent de C const ne ferait vraiment rien. Si l'objet pointé est mutable, vous pouvez le muter; si c'est immuable, vous ne pouvez pas.

Cependant, certains types sont modifiables et d'autres non. Les listes sont modifiables, mais les tuples ne le sont pas. Donc, si vous transmettez vos données sous forme de tuple, vous êtes assuré que la fonction ne peut rien y faire.

Pour utiliser une métaphore C, une liste d'entiers est un peu comme un int [] , et un tuple d'entiers est un const int [] . Lorsque vous les passez à une fonction, peu importe si vous passez une référence const ou une référence non- const ; ce qui compte, c'est de savoir si l'objet auquel il fait référence est const ou non.


0 commentaires

0
votes

L'utilisation d'un tuple est la manière la plus courante de le faire, comme expliqué dans les autres réponses. En supposant que vous commencez avec une instance de list , d'autres stratégies possibles incluent:

  • si le rôle de la liste dans la fonction doit simplement être bouclé, passez un itérateur plutôt que la liste elle-même - iterator = iter (ma_liste) . Notez que vous ne pouvez faire une boucle sur l'itérateur qu'une seule fois; si vous avez besoin de boucler plus d'une fois, vous pouvez passer un générateur qui génère à plusieurs reprises iter (my_list) .
  • transmettre une copie de la liste au lieu de la liste elle-même: new_list = my_list.copy () ou new_list = my_list [:] . Cela peut ne pas être une bonne stratégie pour les très grandes listes, en raison de la consommation de mémoire.

Quelle que soit la méthode que vous choisissez - même les tuples - sachez que ces approches supposent toutes que les éléments de la collection sont eux-mêmes immuables, par exemple des entiers et des chaînes. Si les éléments sont mutables, ils peuvent être mutés (mais pas remplacés):

>>> t = ([1], [1,2])
>>> t[0] = 6
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t[0][0] = 6
>>> t
([6], [1, 2])


>>> L = [[1], [1, 2]]
>>> for x in iter(L):
...     x[0] += 1
... 
>>> L
[[2], [2, 2]]

>>> L = [[1], [1, 2]]
>>> copy = L.copy()
>>> for x in copy:
...     x[0] += 1
... 
>>> L
[[2], [2, 2]]
>>> 

>>> copy[0] = 42
>>> copy
[42, [2, 2]]
>>> L
[[2], [2, 2]]

Vous pouvez contourner ce problème en utilisant copy.deepcopy , mais encore une fois à un coût en mémoire.


0 commentaires