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ではこれを行うことはできません。

ただし、プロパティを使用して、属性を読み取り専用としてマークすることができます。代わりに、アンダースコアプレフィックス付きの「private」属性を使用します。

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

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

上記のコードは、プロパティのゲッターのみを指定しています。Foo().spamPythonでは、現時点では値を設定できません。

>>> 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 に答える