Pythonはクラスを装飾して親オブジェクトタイプを変更します
-
05-07-2019 - |
質問
2つのクラスX&があるとします。 Y.クラスに属性を追加して、新しいクラスX1およびY1を生成することにより、これらのクラスを装飾します。
例:
class X1(X):
new_attribute = 'something'
class Y1(Y):
new_attribute = 'something'
new_attribute は、X1とY1の両方で常に同じです。 X& Yは、多重継承が不可能であることを除いて、意味のある方法で関連付けられていません。他にも属性のセットがありますが、これは説明のために縮退しています。
これを複雑にしすぎているように感じますが、デコレータを使用することを考えていました。
def _xywrap(cls):
class _xy(cls):
new_attribute = 'something'
return _xy
@_xywrap(X)
class X1():
pass
@_xywrap(Y)
class Y1():
pass
かなり一般的なパターンを見逃しているように感じます。また、考え、入力、フィードバックを非常に義務付けられます。
読んでくれてありがとう。
ブライアン
編集:例:
ここに、関連する抜粋があります。一般的なクラスは次のとおりです。
from google.appengine.ext import db
# I'm including PermittedUserProperty because it may have pertinent side-effects
# (albeit unlikely), which is documented here: [How can you limit access to a
# GAE instance to the current user][1].
class _AccessBase:
users_permitted = PermittedUserProperty()
owner = db.ReferenceProperty(User)
class AccessModel(db.Model, _AccessBase):
pass
class AccessExpando(db.Expando, _AccessBase):
pass
# the order of _AccessBase/db.* doesn't seem to resolve the issue
class AccessPolyModel(_AccessBase, polymodel.PolyModel):
pass
ここにサブドキュメントがあります:
class Thing(AccessExpando):
it = db.StringProperty()
Thingには次のプロパティが含まれることがあります:
Thing { it: ... }
その他の時間:
Thing { it: ..., users_permitted:..., owner:... }
Thingに_AccessParentプロパティが設定されている場合とない場合がある理由を理解できませんでした。
解決
3つの引数を使用 type :
def makeSomeNicelyDecoratedSubclass(someclass):
return type('MyNiceName', (someclass,), {'new_attribute':'something'})
これは確かに、あなたが推測したように、かなり人気のあるイディオムです。
編集:一般的なケースでは、一部のクラスにカスタムメタクラスがある場合、 type
自体、それを保持するため(DjangoおよびApp Engineモデルの場合があります):
def makeSomeNicelyDecoratedSubclass(someclass):
mcl = type(someclass)
return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})
これは、上記のより単純なバージョンが機能する場所でも機能します(単純なケースではカスタムメタクラスがない type(someclass)はtype
であるため)。
他のヒント
from google.appengine.ext import db
class Mixin(object):
"""Mix in attributes shared by different types of models."""
foo = 1
bar = 2
baz = 3
class Person(db.Model, Mixin):
name = db.StringProperty()
class Dinosaur(db.polymodel.PolyModel, Mixin):
height = db.IntegerProperty()
p = Person(name='Buck Armstrong, Dinosaur Hunter')
d = Dinosaur(height=5000)
print p.name, p.foo, p.bar, p.baz
print d.height, d.foo, d.bar, d.baz
結果として実行
Buck Armstrong, Dinosaur Hunter 1 2 3
5000 1 2 3
それはあなたが念頭に置いていたものではありませんか?
多重継承を使用できないのはなぜですか
class Origin:
new_attribute = 'something'
class X:
pass
class Y:
pass
class X1(Origin, X):
pass
class Y1(Origin, Y):
pass