Python 使实例中的选定属性成为只读的最简单、最简洁的方法是什么?

Python 使实例中的选定属性成为只读的最简单、最简洁的方法是什么?,python,attributes,readonly,Python,Attributes,Readonly,在Python中,我希望将类的选定的实例属性设置为只读,以便在类之外编写代码。我希望除了通过调用实例上的方法间接地改变属性外,外部代码没有其他方法可以改变属性。我希望语法简洁。最好的方法是什么?(我在下面给出了我目前的最佳答案…没有真正的方法可以做到这一点。有一些方法可以让它变得更“困难”,但没有完全隐藏、不可访问的类属性的概念 如果不能信任使用您的类的人遵循API文档,那么这就是他们自己的问题。保护人们不做愚蠢的事情只意味着他们会做更复杂、更复杂、更具破坏性的愚蠢的事情,去做他们本来不应该做的

在Python中,我希望将类的选定的实例属性设置为只读,以便在类之外编写代码。我希望除了通过调用实例上的方法间接地改变属性外,外部代码没有其他方法可以改变属性。我希望语法简洁。最好的方法是什么?(我在下面给出了我目前的最佳答案…

没有真正的方法可以做到这一点。有一些方法可以让它变得更“困难”,但没有完全隐藏、不可访问的类属性的概念

如果不能信任使用您的类的人遵循API文档,那么这就是他们自己的问题。保护人们不做愚蠢的事情只意味着他们会做更复杂、更复杂、更具破坏性的愚蠢的事情,去做他们本来不应该做的事情

class C(object):

    def __init__(self):

        self.fullaccess = 0
        self.__readonly = 22 # almost invisible to outside code...

    # define a publicly visible, read-only version of '__readonly':
    readonly = property(lambda self: self.__readonly)

    def inc_readonly( self ):
        self.__readonly += 1

c=C()

# prove regular attribute is RW...
print "c.fullaccess = %s" % c.fullaccess
c.fullaccess = 1234
print "c.fullaccess = %s" % c.fullaccess

# prove 'readonly' is a read-only attribute
print "c.readonly = %s" % c.readonly
try:
    c.readonly = 3
except AttributeError:
    print "Can't change c.readonly"
print "c.readonly = %s" % c.readonly

# change 'readonly' indirectly...
c.inc_readonly()
print "c.readonly = %s" % c.readonly
这将产生:

$python./p.py
c、 fullaccess=0
c、 fullaccess=1234
c、 只读=22
无法更改c.readonly
c、 只读=22
c、 只读=23

我的手指渴望能说

    @readonly
    self.readonly = 22

i、 例如,在属性上使用修饰符。它会很干净…

您应该使用
@属性
装饰器

>>> class a(object):
...     def __init__(self, x):
...             self.x = x
...     @property
...     def xval(self):
...             return self.x
... 
>>> b = a(5)
>>> b.xval
5
>>> b.xval = 6
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>a类(对象):
...     定义初始化(self,x):
...             self.x=x
...     @财产
...     def xval(自身):
...             返回self.x
... 
>>>b=a(5)
>>>b.xval
5.
>>>b.xval=6
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:无法设置属性

您可以使用一个元类,将遵循命名约定的方法(或类属性)自动包装到属性中(无耻地取自:

这允许您使用:

class A:
    __metaclass__ = autosuprop
    def _readonly(self):
        return __x
以下是方法:

class whatever(object):
  def __init__(self, a, b, c, ...):
    self.__foobar = 1
    self.__blahblah = 2

  foobar = property(lambda self: self.__foobar)
  blahblah = property(lambda self: self.__blahblah)
(假设
foobar
blahblah
是您希望只读的属性。)在属性名称前加两个下划线可以有效地将其隐藏在类外部,因此内部版本无法从外部访问。这仅适用于从对象继承的新样式类,因为它依赖于
属性

另一方面,这是一个非常愚蠢的事情。保持变量私有似乎是来自C++和java的困扰。用户应该使用公共接口到你的类,因为它设计得很好,不是因为你强迫他们。


编辑:看起来凯文已经发布了一个类似的版本。

我知道威廉·凯勒是目前为止最干净的解决方案。但是我想到了一个办法

class readonly(object):
    def __init__(self, attribute_name):
        self.attribute_name = attribute_name

    def __get__(self, instance, instance_type):
        if instance != None:
            return getattr(instance, self.attribute_name)
        else:
            raise AttributeError("class %s has no attribute %s" % 
                                 (instance_type.__name__, self.attribute_name))

    def __set__(self, instance, value):
        raise AttributeError("attribute %s is readonly" % 
                              self.attribute_name)
下面是使用示例

class a(object):
    def __init__(self, x):
        self.x = x
    xval = readonly("x")

不幸的是,这个解决方案不能处理私有变量(_uuu命名变量)。

有一种方法,它并不像我们希望的那样简洁明了…-kYou可以将attr.to属性()设置为,然后什么都不能,甚至实例本身也不能访问它!(尽管我还想指出您的第二点是有效的!)特殊的扩展模块可能会使更改所选属性变得“困难”得多。这难道不等同于我所做的“readonly=property(lambda self:self.\uu readonly)”?您可以!@property可以工作,但您必须使用def readonly(self):return readonly尽管如此,它仍然避免了lambda噪声。这不是一个readonly属性,因为其他代码仍然可以执行“c”。_c_uureadonly=4“是的,我知道这是用于“uuu”前缀的“弄乱”。这真的是被外部代码欺骗了,如果他们那么绝望,我就让步!)
class a(object):
    def __init__(self, x):
        self.x = x
    xval = readonly("x")