Python eine Klasse dekorieren Mutterobjekttyp ändern
-
05-07-2019 - |
Frage
Angenommen, Sie haben zwei Klassen X & Y. Sie wollen, dass diese Klassen dekorieren durch Attribute der Klasse Hinzufügen neuer Klassen X1 und Y1 zu erzeugen.
Zum Beispiel:
class X1(X):
new_attribute = 'something'
class Y1(Y):
new_attribute = 'something'
new_attribute wird immer die gleiche sowohl für X1 und Y1. X & Y nicht in sinnvoller Weise im Zusammenhang, mit der Ausnahme, dass die Mehrfachvererbung nicht möglich ist. Es gibt eine Reihe von anderen Attributen als auch, aber das ist degeneriert zu illustrieren.
Ich fühle mich wie ich dies overcomplicating, aber ich hatte gedacht, einen Dekorateur zu verwenden, etwas likeso:
def _xywrap(cls):
class _xy(cls):
new_attribute = 'something'
return _xy
@_xywrap(X)
class X1():
pass
@_xywrap(Y)
class Y1():
pass
Es fühlt sich an wie ich bin ein ziemlich häufiges Muster fehlt, und ich würde viel für Gedanken, Input und Feedback dazu verpflichtet werden.
Danke für das Lesen.
Brian
EDIT: Beispiel:
Hier ist ein entsprechender Auszug, die beleuchten kann. Die gemeinsamen Klassen sind wie folgt:
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
Hier ist ein Teildokument:
class Thing(AccessExpando):
it = db.StringProperty()
Manchmal Sache die folgenden Eigenschaften haben:
Thing { it: ... }
Und andere Zeiten:
Thing { it: ..., users_permitted:..., owner:... }
Ich habe nicht in der Lage gewesen, um herauszufinden, warum Ding würde manchmal seine _AccessParent Eigenschaften haben, und ein anderes Mal nicht.
Lösung
Mit 3-Argumente geben :
def makeSomeNicelyDecoratedSubclass(someclass):
return type('MyNiceName', (someclass,), {'new_attribute':'something'})
Das ist in der Tat, wie Sie vermuten, ein einigermaßen populär Idiom.
Bearbeiten : im allgemeinen Fall, wenn Someclass ein benutzerdefiniertes hat metaclass Sie es (mit einem 1-Argumente type
) verwenden extrahieren müssen können anstelle von type
selbst, es zu erhalten (dies kann sein, den Fall für Django und App Engine-Modelle):
def makeSomeNicelyDecoratedSubclass(someclass):
mcl = type(someclass)
return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})
Dies funktioniert auch, wenn die einfachere Version oben tut (da in einfachen Fällen w / ohne individuelle metaclasses type(someclass) is type
).
Andere Tipps
Als Reaktion auf Ihre Kommentare zu voyager Antwort :
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
Ausführen, dass die Ergebnisse in
Buck Armstrong, Dinosaur Hunter 1 2 3
5000 1 2 3
Ist das nicht das, was Sie im Sinn hatte?
Warum können Sie nicht verwenden Mehrfachvererbung ?
class Origin:
new_attribute = 'something'
class X:
pass
class Y:
pass
class X1(Origin, X):
pass
class Y1(Origin, Y):
pass