2008年12月28日日曜日

曖昧さ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

class Hoge(object):
bar = 1

class Piyo(Hoge):
def __init__(self):
self.bar = 2

Piyoのなかでbarというinstance変数を作ろうとして実際のところはclass変数への代入が生じて間違えているのだが、継承ツリーが深いと気づけないかもしれない。どうしたら安全に書けるのだろうか。

名前を探すときにinstanceみてなければclassをみる
という類の話。

属性アクセスのデフォルトの動作は、オブジェクトの辞書から値を取り出したり、 値を設定したり、削除したりするというものです。例えば、a.x による 属性の検索では、まず a.__dict__['x'] 、次に type(a).__dict__['x'] 、そしてtype(a) の基底クラスで メタクラスでないものに続く、といった具合に連鎖が起こります。


a.__dict__にエントリを追加するのか代入しているのか区別がつかないことが原因のひとつではある。
問題が起こらないが、気になるときはparserとかformatterの__init__のなかでresetを呼ぶと時とかは

C++でやられているm_みたいなダサい解決策はcls_をつけるとかがそう。しかしそのようなnaming conventionは、文法上selfを書かせるpythonとしては正しい解決策(pythonic)ではないだろう。
いまどきの人はIDEつかうから問題にならないのかな・・・。


class Hoge(object):
index = dict(...)
def __getattr__(self, name):
begin, end, validator = self.index[name]
assert validator
return validator.from_bitarray(self._data[begin:end])

def __setattr__(self, name, value):
begin, end, validator = self.index[name]
assert validator
validator.to_bitarray(value, self._data, begin, end)

def __init__(self, s=None):
self.__dict__['_data'] = BitArray(66, binary=s, endian='<')

みたいなことをすればclassを書いた時点でインスタンス変数の名前は固定されてしまうので回避はできる。
いいかどうかは別にしてね。動的にインスタンス変数を増やすコードが簡単に書けるという人もいるかもしれないが、それはどのくらいつかわれるかとか、dictを変数でもってそのdictへ転送する手間は大したことじゃないはずだ。

propertyになぞらえていうなら(変ですが)、set, get, delの組じゃなくて、new, set, get, delの組であってほしいのです。

property( [fget[, fset[, fdel[, doc]]]])
新しい形式のクラス (object から導出されたクラス) における プロパティ属性を返します。
fget は属性値を取得するための関数で、同様に fset は 属性値を設定するための関数です。また、fdel は属性を 削除するための関数です。以下に属性 x を扱う典型的な利用法を示します:

class C(object):
def getx(self): return self.__x
def setx(self, value): self.__x = value
def delx(self): del self.__x
x = property(getx, setx, delx, "I'm the 'x' property.")
バージョン 2.2 で 新たに追加 された仕様です。


構文的にシンプルでわかりやすい回答がない、現実的なのか、そこまで問題なのかといった話のほかにもpython本体の実装のシンプルさの問題があるのだろうなぁ・・・。

0 件のコメント: