是否可以在python函数中强制数据不变性?

时间:2019-05-31 02:14:49

标签: python immutability

说我定义一个列表对象,只希望它在我定义的函数中为只读。在C ++中,您可以使用const引用进行此操作。有什么办法可以使用python函数吗?就编写“ pythonic”代码而言,这有意义吗?还是我只是试图错误地应用C ++范例?

3 个答案:

答案 0 :(得分:3)

使用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 :(得分:1)

在Python中,所有变量都是引用,因此拥有C的const并不会真正起到任何作用。如果指向的对象是可变的,则可以对其进行突变;如果它是不可变的,那你就不能。

但是,有些类型是可变的,有些不是。列表是可变的,但元组不是。因此,如果您将数据作为元组传递,则可以确保该函数不能对其执行任何操作。

要使用C隐喻,整数列表有点像int[],而整数元组是const int[]。当您将它们传递给函数时,无论传递的是const引用还是非const引用都无关紧要;重要的是它引用的东西是否为const

答案 2 :(得分:0)

使用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来解决此问题,但同样会消耗内存。