8

Python では、クラスの選択したインスタンス属性を、クラス外のコードに対して読み取り専用にしたいと考えています。インスタンスでメソッドを呼び出すことによって間接的に行う場合を除いて、外部コードが属性を変更できないようにしたいと考えています。構文を簡潔にしたい。最善の方法は何ですか?(現在のベストアンサーを以下に示します...)

4

6 に答える 6

7

@propertyデコレータを使用する必要があります。

>>> class a(object):
...     def __init__(self, x):
...             self.x = x
...     @property
...     def xval(self):
...             return self.x
... 
>>> b = a(5)
>>> b.xval
5
>>> b.xval = 6
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
于 2008-09-24T02:22:16.967 に答える
2
class C(object):

    def __init__(self):

        self.fullaccess = 0
        self.__readonly = 22 # almost invisible to outside code...

    # define a publicly visible, read-only version of '__readonly':
    readonly = property(lambda self: self.__readonly)

    def inc_readonly( self ):
        self.__readonly += 1

c=C()

# prove regular attribute is RW...
print "c.fullaccess = %s" % c.fullaccess
c.fullaccess = 1234
print "c.fullaccess = %s" % c.fullaccess

# prove 'readonly' is a read-only attribute
print "c.readonly = %s" % c.readonly
try:
    c.readonly = 3
except AttributeError:
    print "Can't change c.readonly"
print "c.readonly = %s" % c.readonly

# change 'readonly' indirectly...
c.inc_readonly()
print "c.readonly = %s" % c.readonly

これは以下を出力します:

$ python ./p.py
c.fullaccess = 0
c.fullaccess = 1234
c.readonly=22
変更できません
c.readonlyc.readonly= 22
c.readonly=23

指がかゆくて言うことができません

    @readonly
    self.readonly = 22

つまり、属性にデコレータを使用します。それはとてもきれいだろう...

于 2008-09-24T02:21:56.250 に答える
2

方法は次のとおりです。

class whatever(object):
  def __init__(self, a, b, c, ...):
    self.__foobar = 1
    self.__blahblah = 2

  foobar = property(lambda self: self.__foobar)
  blahblah = property(lambda self: self.__blahblah)

( とは読み取り専用にしたい属性であると仮定foobarします。) 属性名の先頭に2 つのアンダースコアを追加すると、クラスの外部から効果的に隠蔽されるため、外部から内部バージョンにアクセスできなくなります。に依存しているため、これはオブジェクトから継承する新しいスタイルのクラスでのみ機能しますblahblahproperty

一方で...これはかなりばかげたことです。変数をプライベートに保つことは、C++ と Java に由来する強迫観念のようです。ユーザーは、強制的に使用するのではなく、適切に設計されているため、クラスへのパブリック インターフェイスを使用する必要があります。

編集: ケビンはすでに同様のバージョンを投稿しているようです。

于 2008-09-24T06:49:36.107 に答える
1

これを行う実際の方法はありません。それをより「困難」にする方法はありますが、完全に隠された、アクセスできないクラス属性の概念はありません。

クラスを使用している人がAPIドキュメントに従うことを信頼できない場合、それは彼ら自身の問題です。人々を愚かなことから守るということは、彼らがそもそもやるべきではないことをやろうとするために、はるかに精巧で、複雑で、損害を与える愚かなことをするということを意味します。

于 2008-09-24T02:20:16.847 に答える
0

ウィリアム・ケラーが最もクリーンなソリューションであることは承知しています..しかし、ここに私が思いついたものがあります..

class readonly(object):
    def __init__(self, attribute_name):
        self.attribute_name = attribute_name

    def __get__(self, instance, instance_type):
        if instance != None:
            return getattr(instance, self.attribute_name)
        else:
            raise AttributeError("class %s has no attribute %s" % 
                                 (instance_type.__name__, self.attribute_name))

    def __set__(self, instance, value):
        raise AttributeError("attribute %s is readonly" % 
                              self.attribute_name)

そしてこちらが使用例

class a(object):
    def __init__(self, x):
        self.x = x
    xval = readonly("x")

残念ながら、このソリューションはプライベート変数 (__ 名前付き変数) を処理できません。

于 2010-04-24T11:37:38.000 に答える
0

命名規則に従うメソッド (またはクラス属性) をプロパティに自動ラップするメタクラスを使用できます ( Python 2.2 の型とクラスの統一から恥知らずに取得:

class autoprop(type):
    def __init__(cls, name, bases, dict):
        super(autoprop, cls).__init__(name, bases, dict)
        props = {}
        for name in dict.keys():
            if name.startswith("_get_") or name.startswith("_set_"):
                props[name[5:]] = 1
        for name in props.keys():
            fget = getattr(cls, "_get_%s" % name, None)
            fset = getattr(cls, "_set_%s" % name, None)
            setattr(cls, name, property(fget, fset))

これにより、以下を使用できます。

class A:
    __metaclass__ = autosuprop
    def _readonly(self):
        return __x
于 2008-09-24T02:49:37.477 に答える