Python decora una classe per cambiare il tipo di oggetto padre
-
05-07-2019 - |
Domanda
Supponi di avere due classi X & amp; Y. Vuoi decorare quelle classi aggiungendo attributi alla classe per produrre nuove classi X1 e Y1.
Ad esempio:
class X1(X):
new_attribute = 'something'
class Y1(Y):
new_attribute = 'something'
new_attribute sarà sempre lo stesso per X1 e Y1. X & amp; Y non sono correlati in alcun modo significativo, tranne per il fatto che l'ereditarietà multipla non è possibile. Esistono anche altri attributi, ma questo è degenerato da illustrare.
Mi sento come se stessi complicando troppo, ma avevo pensato di usare un decoratore, un po 'mi piace:
def _xywrap(cls):
class _xy(cls):
new_attribute = 'something'
return _xy
@_xywrap(X)
class X1():
pass
@_xywrap(Y)
class Y1():
pass
Sembra che mi manchi uno schema abbastanza comune e sarei molto obbligato a pensare, a dare input e a feedback.
Grazie per aver letto.
Brian
MODIFICA: Esempio:
Ecco un estratto rilevante che può illuminare. Le classi comuni sono le seguenti:
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
Ecco un sotto-documento:
class Thing(AccessExpando):
it = db.StringProperty()
A volte Cosa avrà le seguenti proprietà:
Thing { it: ... }
E altre volte:
Thing { it: ..., users_permitted:..., owner:... }
Non sono stato in grado di capire perché Thing avrebbe talvolta le sue proprietà _AccessParent, altre volte no.
Soluzione
Usa 3 argomenti type :
def makeSomeNicelyDecoratedSubclass(someclass):
return type('MyNiceName', (someclass,), {'new_attribute':'something'})
Questo è davvero, come hai ipotizzato, un linguaggio ragionevolmente popolare.
Modifica : nel caso generale se una sorteggio ha una metaclasse personalizzata, potrebbe essere necessario estrarla e usarla (con un tipo a 1 argomento
) al posto di digita
per conservarlo (questo potrebbe essere il caso dei tuoi modelli Django e App Engine):
def makeSomeNicelyDecoratedSubclass(someclass):
mcl = type(someclass)
return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})
Funziona anche dove funziona la versione più semplice sopra (poiché in casi semplici senza metaclassi personalizzati type (someclass) è type
).
Altri suggerimenti
Risposta ai tuoi commenti su risposta del viaggiatore :
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
L'esecuzione che risulta in
Buck Armstrong, Dinosaur Hunter 1 2 3
5000 1 2 3
Non è quello che avevi in ??mente?
Perché non puoi usare eredità multipla ?
class Origin:
new_attribute = 'something'
class X:
pass
class Y:
pass
class X1(Origin, X):
pass
class Y1(Origin, Y):
pass