python:不可变的私有类变量?

Jas*_*n S 10 python oop static class

有没有办法将这个Java代码翻译成Python?

class Foo
{
    final static private List<Thingy> thingies = 
       ImmutableList.of(thing1, thing2, thing3);
}
Run Code Online (Sandbox Code Playgroud)

例如,属于类thingies的不可变私有列表,而不是它的实例.ThingyFoo

我知道如何从这个问题中定义静态类变量Python中的静态类变量,但我不知道如何使它们成为不可变和私有的.

小智 21

在Python中,惯例是使用_属性名称上protected__前缀来表示和表示前缀private.这不是由语言强制执行的; 程序员应该知道不要编写依赖于非公开数据的代码.

如果你真的想强制实现不变性,可以使用元类[ docs ](类的类).当有人试图修改它时,只需修改__setattr____delattr__引发异常,并使其成为tuple(不可变列表)[ docs ].

class FooMeta(type):
    """A type whose .thingies attribute can't be modified."""

    def __setattr__(cls, name, value):
        if name == "thingies":
            raise AttributeError("Cannot modify .thingies")
        else:
            return type.__setattr__(cls, name, value)

    def __delattr__(cls, name):
        if name == "thingies":
            raise AttributeError("Cannot delete .thingies")
        else:
            return type.__delattr__(cls, name)

thing1, thing2, thing3 = range(3)

class Foo(object):
    __metaclass__ = FooMeta
    thingies = (thing1, thing2, thing3)
    other = [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

例子

print Foo.thingies # prints "(0, 1, 2)"
Foo.thingies = (1, 2) # raises an AttributeError
del Foo.thingies # raise an AttributeError
Run Code Online (Sandbox Code Playgroud)
Foo.other = Foo.other + [4] # no exception
print Foo.other # prints "[1, 2, 3, 4]"
Run Code Online (Sandbox Code Playgroud)

技术上仍然可以通过遍历类的内部.__dict__属性来修改它们,但这应该足以阻止大多数用户,完全保护Python对象非常困难.

  • +1.我将添加一个警告:只是因为Python允许你这样做并不意味着你应该这样做.好的Java不一定是好的Python(反之亦然). (5认同)
  • @EthanFurman:使用“property”的答案受保护实例属性“Foo().thingies”,他要求保护类属性“Foo.thingies”。我也可以在这里使用属性,但很多人不理解元类,我想有一个相对简单的例子。 (2认同)

kin*_*all 13

无论如何,你不能用Python做任何一件事,也不能用Java做.

按照惯例,以下划线为前缀的名称被视为私有,不应在实现之外访问,但Python中没有任何内容强制执行此约定.在未来的代码版本中,您可能会在未发出警告的情况下更改可能会更改的实现细节.

  • 要获得一些非必要的东西并被视为不必要的东西,这将是一项很多工作.只是前缀是`_`. (3认同)
  • 使用`property()`可以实现不变性.理论上,私有变量可以通过让getter执行一些检查来确定它是否是一个实例,并根据检查返回一些可接受的默认值来代替实际值来实现.至少,我认为这是可能的.我没有发现有必要这样做...... (2认同)

Eth*_*man 6

你可以通过使用属性使它不可写(与不可变的略有不同),但没有办法使它成为私有 - 这违背了Python的理念.

class Foo(object):    # don't need 'object' in Python 3
    @property
    def thingies(self):
        return 'thing1', 'thing2', 'thing3'

f = Foo()
print f.thingies
#('thing1', 'thing2', 'thing3')
f.thingies = 9
#Traceback (most recent call last):
#  File "test.py", line 8, in <module>
#    f.thingies = 9
#AttributeError: can't set attribute
Run Code Online (Sandbox Code Playgroud)

它是否一成不变取决于你的回归; 如果你返回一个可变对象,你可能会改变它让这些更改显示在实例/类中.

class FooMutable(object):
    _thingies = [1, 2, 3]
    @property
    def thingies(self):
        return self._thingies

foo = FooMutable()
foo.thingies.append(4)
print foo.thingies
# [1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

这将允许您进行变异thingies,并且因为返回的对象与实例/类中保留的对象相同,所以更改将反映在后续访问中.

与之相比:

class FooMutable(object):
    @property
    def thingies(self):
        return [1, 2, 3]

foo = FooMutable()
foo.thingies.append(4)
print foo.thingies
# [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

由于每次都会返回一个全新的列表,因此对其的更改不会反映在后续访问中.

  • @Steven如果你把它作为一个元组,我仍然可以做`myinstance._thingies = None`. (2认同)