Python类无法编辑实例的属性

时间:2013-01-14 18:22:31

标签: python class methods python-3.x instance

创建一个类的最方便的方法是哪些实例的属性不能从类外部更改(你仍然可以获得值),所以它是可能的在类的方法中调用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,你们中的一些人已经回答过了,但这对我来说还不够,因为它会离开{{1}可变的。

3 个答案:

答案 0 :(得分:3)

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

您可以使用属性将属性标记为只读;使用下划线前缀'private'属性代替:

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属性:

>>> 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'

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

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

Why Python is not full object-oriented?

物业方式:

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)