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

时间:2011-09-13 18:52:09

标签: python oop class static

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

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

e.g。 thingiesThingy对象的不可变私有列表,属于Foo类而不是其实例。

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

5 个答案:

答案 0 :(得分:17)

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

实施例

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

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

答案 1 :(得分:12)

你不能用Python做任何一件事,不管你用Java做什么,无论如何。

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

答案 2 :(得分: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

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

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]

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

将其与:

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

foo = FooMutable()
foo.thingies.append(4)
print foo.thingies
# [1, 2, 3]

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

答案 3 :(得分:1)

您想查看property()功能。它允许您为类的成员属性定义自己的自定义Getter和Setter。它可能看起来像这样:

class myClass(object):
  _x = "Hard Coded Value"

  def set_x(self, val): return

  def get_x(self): return self._x

  def del_x(self): return

  x = property(get_x, set_x, del_x, "I'm an immutable property named 'x'")

我没有充分利用它来确定它是否可以用于创建“私人”内容,因此您必须自己深入研究,但isinstance可能会有所帮助。

答案 4 :(得分:0)

您可以使用类型提示*实现final部分。正如其他人所说,__可以很好地实现private方面,所以

from typing import List
from typing_extensions import Final

class Foo:
    __thingies: Final[List[Thingy]] = ImmutableList.of(thing1, thing2, thing3)

我将ImmutableList的定义留给您。 tuple可能会做到。

*,通常的警告是用户可以忽略它们