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

问题描述 投票:0回答:6

有什么方法可以将这个Java代码翻译成Python吗?

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

例如

thingies
是属于
Thingy
类而不是其实例的
Foo
对象的不可变私有列表。

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

python oop class static
6个回答
35
投票

在 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 对象是非常困难的。


20
投票

你无法在 Python 中完成这些事情,无论如何,这与你在 Java 中所做的不同。

按照约定,带有下划线前缀的名称被认为是私有的,不应在实现之外访问,但 Python 中没有强制执行此约定。它更多地被认为是一个警告,表明您正在搞乱实现细节,该细节可能会在代码的未来版本中毫无警告地更改。


9
投票

您可以通过使用属性使其不可写(与不可变略有不同),但无法将其设为私有——这违背了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]

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


2
投票
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

可能会有所帮助。

    


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
可能就可以了。
*通常的警告是用户可以忽略它们


0
投票
@Jeremy

的答案的不同风格,在我看来更干净,并且还在 IDE 中提供了类型提示(假设使用 mypy)。 from typing import Final # (optional Final): Final is not enforced, but this provide a nice hint in IDE (assuming mypy is used) class Immutable(type): def __setattr__(cls, attr, value): raise AttributeError("Cannot reassign members.") def __delattr__(cls, name): raise AttributeError("Cannot delete members.") class ImmutableConstant(metaclass=Immutable): FOO: Final = 1 # (optionnal Final)

这是一个运行时示例:

print(ImmutableConstant.FOO) # Prints '1' try: ImmutableConstant.FOO = 3 # Nice IDE warning (assuming mypy is used: Cannot assign to final attribute "FOO" mypy) except AttributeError as e: print(e) # Cannot reassign members. try: del ImmutableConstant.FOO except AttributeError as e: print(e) # Cannot delete members.

© www.soinside.com 2019 - 2024. All rights reserved.