[解決済み】クラスにプロパティを動的に追加する方法は?
質問
目標は、DBの結果セットのように動作するモッククラスを作成することです。
つまり、例えばデータベースクエリがdict式を使って返すとしたら。
{'ab':100, 'cd':200}
というのが欲しいところです。
>>> dummy.ab
100
最初はこの方法でできるかもしれないと思ったんです。
ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
def __init__(self, ks, vs):
for i, k in enumerate(ks):
self[k] = vs[i]
setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))
def fn_readonly(self, v)
raise "It is ready only"
if __name__ == "__main__":
c = C(ks, vs)
print c.ab
しかし
c.ab
は代わりにプロパティオブジェクトを返します。
を置き換えると
setattr
の行を
k = property(lambda x: vs[i])
は全く意味がありません。
では、実行時にインスタンスプロパティを作成する正しい方法とは何でしょうか?
P.S. 私は、次のような代替案を知っています。
どのように
__getattribute__
メソッドが使用されているのですか?
解決方法は?
この答えは、年を取って賢くなり、何が起こっているのかを知った今、拡大解釈すべきなのでしょう。 遅かれ早かれね。
あなた できる はクラスに動的にプロパティを追加します。 しかし、これが難点です。 クラス .
>>> class Foo(object):
... pass
...
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4
A
property
というものを単純に実装したものです。
記述子
. これは、与えられた属性のカスタム処理を提供するオブジェクトです。
与えられたクラスで
. 巨大な
if
のツリーアウト
__getattribute__
.
を求めると
foo.b
は、Pythonは
b
を実装しています。
記述子プロトコル
-を持つオブジェクトであることを意味します。
__get__
,
__set__
または
__delete__
メソッドを使用します。 ディスクリプタはその属性の処理に責任を持つことを主張するので、Pythonは
Foo.b.__get__(foo, Foo)
そして、その戻り値が属性の値として渡されます。 の場合
property
これらのメソッドは、単に
fget
,
fset
または
fdel
に渡した
property
のコンストラクタを使用します。
ディスクリプタは、PythonのOO実装全体の配管を公開する方法です。 実際、以下の記述子よりもさらに一般的な別のタイプの記述子があります。
property
.
>>> class Foo(object):
... def bar(self):
... pass
...
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>
謙虚なメソッドは、単なる記述子の一種です。 その
__get__
は、呼び出し元のインスタンスを第一引数として追加することで、実質的にはこのようになります。
def __get__(self, instance, owner):
return functools.partial(self.function, instance)
とにかく、これが、ディスクリプタがクラスでしか機能しない理由だと思うのです。 クラスには明らかに記述子を割り当てることができますし、クラスはそれ自体が
type
! を読もうとすると
Foo.bar
を呼び出したままです。
property.__get__
これは、クラスの属性としてアクセスされたときに、記述子が自分自身を返すようにするためのイディオムなのです。
PythonのOO系がほぼ全てPythonで表現できるのは、かなりクールだと思います :)
あ、あと、私が書いたのは ディスクリプタに関するブログ記事 を作成しました。
関連
-
[解決済み] _tkinter.TclError: 表示名がなく、$DISPLAY環境変数もない。
-
[解決済み】Flask ImportError: Flask という名前のモジュールがない
-
[解決済み] プログラムの実行やシステムコマンドの呼び出しはどのように行うのですか?
-
[解決済み] リストのリストからフラットなリストを作るには?
-
[解決済み] Pythonで辞書に新しいキーを追加するにはどうすればよいですか?
-
[解決済み] リストが空かどうかを確認するにはどうすればよいですか?
-
[解決済み] Pythonの@propertyデコレーターはどのように機能するのでしょうか?
-
[解決済み] 変数を使用してオブジェクトのプロパティに動的にアクセスする
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】2つの辞書を1つの式でマージする(辞書の和をとる)には?)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ピロウズ画像色処理の具体的な活用方法
-
Python 人工知能 人間学習 描画 機械学習モデル作成
-
Python百行で韓服サークルの画像クロールを実現する
-
[解決済み】ilocが「IndexError: single positional indexer is out-of-bounds」を出す。
-
[解決済み】 AttributeError: モジュール 'matplotlib' には属性 'plot' がない。
-
[解決済み】TypeErrorを取得しました。エントリを持つ子テーブルの後に親テーブルを追加しようとすると、 __init__() missing 1 required positional argument: 'on_delete'
-
[解決済み】Python Error: "ValueError: need more than 1 value to unpack" (バリューエラー:解凍に1つ以上の値が必要です
-
[解決済み】Python - "ValueError: not enough values to unpack (expected 2, got 1)" の修正方法 [閉店].
-
[解決済み】 TypeError: += でサポートされていないオペランド型: 'int' および 'list' です。
-
[解決済み] ネストされたPythonのdictをオブジェクトに変換する?