2

创建一个不能从类外部更改实例属性的类的最方便方法是什么您仍然可以获取值),因此可以self.var = v在类内部调用方法,但不能ClassObject().var = v在外部调用班的?

我试过弄乱,__setattr__()但如果我覆盖它,则name无法在__init__()方法中启动该属性。唯一的方法是覆盖__setattr__()和使用object.__setattr__(),我目前正在这样做:

class MyClass(object):
    def __init__(self, name):
        object.__setattr__(self, "name", name)
    def my_method(self):
        object.__setattr__(self, "name", self.name + "+")
    def __setattr__(self, attr, value):
        raise Exception("Usage restricted")

现在这个解决方案有效,已经足够了,但我想知道是否有更好的解决方案。这个问题是:我仍然可以object.__setattr__(MyClass("foo"), "name", "foo_name")从课堂外的任何地方打电话。

有没有办法完全防止将变量设置为类外的任何内容?

编辑:愚蠢的我没有提到我不是在property这里寻找,你们中的一些人已经回答了它,但是这对我来说还不够,因为它会self._name改变。

4

3 回答 3

3

不,你不能在纯 python 中做到这一点。

您可以使用属性将您的属性标记为只读;改用下划线前缀的“私有”属性:

class Foo(object):
    def __init__(self, value):
        self._spam = value

    @property
    def spam(self):
        return self._spam

上面的代码只为属性指定了一个getter;Python 暂时不会让你设置值Foo().spam

>>> class Foo(object):
...     def __init__(self, value):
...         self._spam = value
...     @property
...     def spam(self):
...         return self._spam
... 
>>> f = Foo('eggs')
>>> f.spam
'eggs'
>>> f.spam = 'ham'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

当然,您仍然可以_spam从外部访问 'private' 属性:

>>> f._spam
'eggs'
>>> f._spam = 'ham'
>>> f.spam
'ham'

您可以使用双下划线约定,__在编译时重命名开头(但不是结尾!)的属性名称。这并不是为了使属性无法从外部访问,而是为了保护属性不被子类覆盖。

class Foo(object):
    def __init__(self, value):
        self.__spam = value

    @property
    def spam(self):
        return self.__spam

您仍然可以访问这些属性:

>>> f = Foo('eggs')
>>> f.spam
'eggs'
>>> f.__spam
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__spam'
>>> f._Foo__spam
'eggs'
>>> f._Foo__spam = 'ham'
>>> f.spam
'ham'
于 2013-01-14T18:37:08.067 回答
2

在 Python 上没有严格的封装方式。您可以做的最好的事情是__在预期的私有属性前面加上 2 个下划线。这将导致它们被类名 (_ ClassName _AttribName) 破坏,因此如果您尝试在继承的类上使用它们,则不会引用基成员。如果您使用getattrib()setattrib()虽然,名称不会被破坏。

您也可以覆盖 __dir()__以隐藏它们。

于 2013-01-14T18:35:34.580 回答
2

您可以使用属性来模拟这种行为,但就像 Martijn 所说,可以直接访问变量。这样做是您不了解 Python 哲学的信号,请检查一下。

为什么 Python 不是完全面向对象的?

属性方式:

http://docs.python.org/2/library/functions.html#property

class C(object):
    def __init__(self):
        self._x = None

    def getx(self):
        return self._x
    def setx(self, value):
        raise Exception("Usage restricted")
    x = property(getx, setx)
于 2013-01-14T18:35:36.797 回答