8

__setattr__インスタンス変数のオーバーライドを介してできるように、Python でクラス変数へのアクセスを防止または変更する方法はありますか?

この質問はタイトルが間違っており、実際にはクラス変数ではなくインスタンス変数を参照していることに注意してください。

である(見かけの)デストラップに関する複数の投稿を読んだことに基づいて__slots__、私はそのルートに行かないことを好みます(そして、それが私が求めていることを行うかどうかを知るのに十分に調べていません)。

例:

class A(object):

    foo = "don't change me"

    def __setattr__(self, name, value):
        raise ValueError

if __name__ == '__main__':
a1 = A()
print a1.foo # don't change me
print A.foo  # don't change me

A.foo = 'bar' # ideally throw an exception or something here
print A.foo   # bar
a2 = A()
print a1.foo  # bar
print a2.foo  # bar
4

2 に答える 2

4

うん!あなたはそれをまったく同じ方法で行います。

クラスの__setattr__メソッドは、そのクラスのインスタンスの属性の設定を制御します。Python では、すべてがオブジェクトです。また、オブジェクトにはクラスがあります。__setattr__したがって、インスタンスの属性が変更されるのを防ぎたい場合とまったく同じように、メソッドを持つクラスのインスタンスになるようにクラスを調整する必要があります。

クラスのクラスはメタクラスと呼ばれます。デフォルトのメタクラスはtype、「タイプのタイプ」または「クラスのクラス」です。インスタンス属性の設定を許可しない のサブクラスを作成する必要があります (インスタンス レベルでこれを行うときにインスタンス属性の設定を許可しないtypeのサブクラスを作成するのとまったく同じです)。object

class CantTouchThis(type):
    def __setattr__(cls, attr, value):
        raise Exception("NO!")

class SomeClass(object):
    __metaclass__ = CantTouchThis

の基本クラスSomeClassと のクラス違いに注意してくださいSomeClassSomeClassのサブクラスですobject。のインスタンスですCantTouchThis

インスタンス レベルで動作する他のほとんどすべては、メタクラスを使用してクラス レベルに同様に適用できます。クラスは、他のすべてのものと同様に単なるインスタンスです。typeメソッドと実装(正確には...など)のために、それらは独特の上品な動作しかありません。

于 2012-10-16T11:35:22.033 に答える
2

__setattr__もうすぐです。メソッドをメタクラスに移動するだけです。

class ReadOnlyClass(type):
    def __setattr__(self, name, value):
        raise ValueError(name)
    
class A(object, metaclass=ReadOnlyClass):
    foo = "don't change me"
    
>>> a1 = A()
>>> a1.foo
"don't change me"
>>> A.foo
"don't change me"
>>> A.foo = 'bar'

Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    A.foo = 'bar'
  File "<pyshell#4>", line 3, in __setattr__
    raise ValueError, name
ValueError: foo
>>> print A.foo
don't change me
>>> a2 = A()
>>> a2.foo
"don't change me"
>>> a2.foo = 'x'
>>> a2.foo
'x'

メタクラス__setattr__はクラス内の属性の変更を停止しますが、インスタンス属性で属性を非表示にすることは停止しません。それが必要な場合は__setattr__、両方の場所で定義する必要があります。

編集:古いPython2.xの代わりにPython3.x構文を使用するように更新されました

于 2012-10-16T11:23:33.530 に答える