【问题标题】:Make a python list constant and uneditable使 python 列表保持不变且不可编辑
【发布时间】:2015-11-22 02:46:29
【问题描述】:

我有一个代码:

def constant(f):
    def fset(self, value):
        raise SyntaxError( "You can't change a constant!" )
    def fget(self):
        return f(self)
    return property(fget, fset)

class A( object ):
    def __init__( self, a_list ):
        super( A, self ).__init__()
        self.__data = a_list[:]
    @constant
    def data( self ):
        return self.__data

我想让 self.__data 可访问,但不能从课堂外更改和编辑。我不能简单地将它更改为一个元组,因为我希望它可以很容易地更改为类中的方法。当有人修改列表时,我上面提出的解决方案不起作用:

>>> a = A( range(5) )
>>> a.data = []
Traceback (most recent call last):
    ...
SyntaxError: You can't change a constant! # it works
>>> a.data[0]=6                           # it doesn't work
>>> a.data
[6, 1, 2, 3, 4]

你知道我的问题有什么好的解决方案吗?

【问题讨论】:

  • 所以你想让它看起来是外部的,但实际上不是内部的?为什么? “在这里,我们都是同意的成年人” - 列表中只需一个前导下划线就足够了。
  • 另一种选择是使datareturn self.__data[:],然后如果接收到它确实改变它没关系。
  • 考虑引发自定义异常而不是 SyntaxError,因为如果有人试图以您不喜欢的方式使用您的对象,这并不是语法问题。
  • @CristianCiupitu 因为这个想法是在内部保留可变性。其他类方法应该能够更改内部列表,但在类之外没有任何内容。 (这基本上是关于 Python 不支持的一种封装。)

标签: python constants


【解决方案1】:

您还可以创建一个视图类来实现列表的所有读取操作。当然,还是有办法访问内部列表的,没有办法阻止。

class ListView(object):
  def __init__(self, list_):
    self._list = list_
  def __getitem__(self, index):
    return self._list[index]
  def __repr__(self):
    return 'ListView(%r)' % self._list
  def index(self, value):
    return self._list.index(value)
  # and so on

(从移动设备发送)

【讨论】:

  • 你可以这样做,但要准备好编写几十个冗余方法来做以下两件事之一:遵循内部列表(就像你展示的每个方法一样),或者引发异常抱怨无效的操作。
  • 我建议使用collections.abc.Sequence 作为基类。您需要做的就是定义__getitem____len__,然后abc 将为您完成剩下的工作。
【解决方案2】:

提供一些不应该改变的提示,但如果他们真的想要,让人们改变它。

如果您想要不可编辑的list,请使用tuple。使用前导下划线以获得额外的“安全性”。

总有办法改变 Python 中的 list 任何东西。即使我不得不闯入你的房子,偷走你的代码然后修改它——这是可能的。

_change_this_and_I_will_kill_you_with_my_axe = [] # never use this name

如果你例如。返回列表并且不希望它修改返回副本,但仍有修改它的方法。

return my_list[:]

【讨论】:

  • “即使我不得不闯入你的房子,偷走你的代码,然后修改它。”如果更改源代码很重要,我认为您的元组建议不会更好。 :P
  • @Two-BitAlchemist 是的,您可以将其更改为 list 并对其进行变异。 :) 如果不是很明显,重点不是防止您的代码更改,而是提供提示 - 也许您不应该将我的变量 pi 更改为 42,但如果您愿意,请随意这样做真的很想要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多