Можно ли принудительно установить неизменность данных в функции Python? - PullRequest
3 голосов
/ 31 мая 2019

Скажем, я определяю объект списка и хочу, чтобы он был доступен только для чтения в определяемой мной функции. В C ++ вы бы сделали это с помощью константной ссылки. Есть ли способ сделать это с помощью функции Python? Имеет ли это смысл при написании «питонического» кода или я просто пытаюсь неправильно применить парадигму C ++?

Ответы [ 3 ]

3 голосов
/ 31 мая 2019

Используйте tuple, вместо:

>>> 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
>>> 

hash может определить, является ли он изменяемым или нет, и выдает ошибку TypeError: unhashable type, если оно изменчиво, например list s, OTOH tuple вернет несколько больших чисел (в данном конкретном случае это не нужно), мы можем использовать try except, если вы хотите:

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

Какие выходные данные:

Immutable object
1 голос
/ 31 мая 2019

В Python все переменные являются ссылками, поэтому наличие эквивалента C const на самом деле ничего не даст. Если указанный объект является изменяемым, вы можете изменить его; если он неизменен, вы не можете.

Однако есть некоторые типы, которые могут изменяться, а некоторые - нет. Списки изменчивы, а кортежи - нет. Поэтому, если вы передадите свои данные в виде кортежа, вы гарантированно не сможете с этим ничего сделать.

Чтобы использовать метафору C, список целых чисел напоминает int[], а кортеж целых чисел - const int[]. Когда вы передаете их функции, не имеет значения, передаете ли вы ссылку const или ссылку не const; имеет значение, является ли то, на что оно ссылается , const или нет.

0 голосов
/ 01 июня 2019

Использование tuple является наиболее распространенным способом сделать это, как объяснено в других ответах.Предполагая, что вы начинаете с экземпляра list, другие возможные стратегии включают в себя:

  • , если роль списка в функции просто повторяется, передайте итератор, а не сам список -iterator = iter(my_list).Обратите внимание, что вы можете зацикливаться на итераторе только один раз;если вам нужно сделать цикл более одного раза, вы можете передать генератор, который многократно дает iter(my_list).
  • передать копию списка вместо самого списка: new_list = my_list.copy() или new_list = my_list[:].Это может быть не очень хорошей стратегией для очень больших списков из-за потребления памяти.

Какой бы метод вы ни выбрали - даже кортежи - помните, что все эти подходы предполагают, что элементы в коллекции сами по себе являются неизменяемымиНапример, целые числа и строки.Если элементы являются изменяемыми, они могут быть видоизменены (но не заменены):

>>> 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]]

Вы можете обойти это, используя copy.deepcopy , но опять же с затратами в памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...