Python、__slots__、および「属性は読み取り専用です」
-
03-07-2019 - |
質問
Python でいくつかの属性を持つオブジェクトを作成したいのですが、誤って間違った属性名を使用しないようにしたいと考えています。コードは次のとおりです。
class MyClass( object ) :
m = None # my attribute
__slots__ = ( "m" ) # ensure that object has no _m etc
a = MyClass() # create one
a.m = "?" # here is a PROBLEM
しかし、この単純なコードを実行すると、非常に奇妙なエラーが発生します。
Traceback (most recent call last):
File "test.py", line 8, in <module>
a.m = "?"
AttributeError: 'test' object attribute 'm' is read-only
少し時間を割いて「読み取り専用」エラーについて教えてくれる賢明なプログラマーはいませんか?
解決
を使用してインスタンス変数を宣言すると、 __slots__
, Python は 記述子オブジェクト 同じ名前のクラス変数として。あなたの場合、この記述子はクラス変数によって上書きされます m
次の行で定義しています。
m = None # my attribute
行う必要があるのは次のとおりです。というクラス変数を定義しないでください。 m
, 、インスタンス変数を初期化します m
の中に __init__
方法。
class MyClass(object):
__slots__ = ("m",)
def __init__(self):
self.m = None
a = MyClass()
a.m = "?"
補足として、単一の要素を含むタプルには要素の後にカンマが必要です。どちらもコード内で機能します。 __slots__
単一の文字列または文字列の反復可能/シーケンスを受け入れます。一般に、要素を含むタプルを定義するには、 1
, 、 使用 (1,)
または 1,
そしてそうではありません (1)
.
他のヒント
__ slots __
を完全に誤用しています。インスタンスの __ dict __
の作成を防ぎます。これは、 __ dict __
を削除するとフットプリントを削減できるため、多くの小さなオブジェクトでメモリの問題が発生した場合にのみ意味があります。これは、すべてのケースの99.9%で必要とされない筋金入りの最適化です。
説明したような安全性が必要な場合、Pythonは本当に間違った言語です。 (PythonでJavaを記述しようとする代わりに)Javaのような厳密なものを使用する方が良い。
クラス属性がコード内でこれらの問題を引き起こした理由を自分で理解できなかった場合は、このような言語ハックの導入について考え直す必要があります。最初に言語に慣れる方が賢明でしょう。
完全を期すために、スロットのドキュメントリンク 。
__ slots __
はインスタンス変数で動作しますが、クラス変数があります。これがあなたのやり方です:
class MyClass( object ) :
__slots__ = ( "m", )
def __init__(self):
self.m = None
a = MyClass()
a.m = "?" # No error
これを考慮してください。
class SuperSafe( object ):
allowed= ( "this", "that" )
def __init__( self ):
self.this= None
self.that= None
def __setattr__( self, attr, value ):
if attr not in self.allowed:
raise Exception( "No such attribute: %s" % (attr,) )
super( SuperSafe, self ).__setattr__( attr, value )
より良いアプローチは、この種のチェックに単体テストを使用することです。これはかなりの量の実行時オーバーヘッドです。
class MyClass( object ) :
m = None # my attribute
ここでの m
は、インスタンス属性ではなくクラス属性です。 __ init __
で自分でインスタンスに接続する必要があります。