Python decora una clase para cambiar el tipo de objeto primario
-
05-07-2019 - |
Pregunta
Suponga que tiene dos clases X & amp; Y. Desea decorar esas clases agregando atributos a la clase para producir nuevas clases X1 e Y1.
Por ejemplo:
class X1(X):
new_attribute = 'something'
class Y1(Y):
new_attribute = 'something'
new_attribute siempre será igual para X1 e Y1. X & amp; Y no están relacionados de ninguna manera significativa, excepto que la herencia múltiple no es posible. También hay un conjunto de otros atributos, pero esto es degenerado para ilustrar.
Siento que estoy complicando demasiado esto, pero pensé en usar un decorador, algo así como:
def _xywrap(cls):
class _xy(cls):
new_attribute = 'something'
return _xy
@_xywrap(X)
class X1():
pass
@_xywrap(Y)
class Y1():
pass
Parece que me falta un patrón bastante común, y estaría muy agradecido por pensamientos, aportes y comentarios.
Gracias por leer.
Brian
EDITAR: Ejemplo:
Aquí hay un extracto relevante que puede iluminar. Las clases comunes son las siguientes:
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
Aquí hay un subdocumento:
class Thing(AccessExpando):
it = db.StringProperty()
A veces, Thing tendrá las siguientes propiedades:
Thing { it: ... }
Y otras veces:
Thing { it: ..., users_permitted:..., owner:... }
No he podido entender por qué Thing a veces tendría sus propiedades _AccessParent, y otras veces no.
Solución
Utilice 3 argumentos tipo :
def makeSomeNicelyDecoratedSubclass(someclass):
return type('MyNiceName', (someclass,), {'new_attribute':'something'})
Esto es, como supusiste, un idioma razonablemente popular.
Editar : en el caso general, si alguna clase tiene una metaclase personalizada, es posible que deba extraerla y utilizarla (con un tipo
de 1 argumento) en lugar de
def makeSomeNicelyDecoratedSubclass(someclass):
mcl = type(someclass)
return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})
Esto también funciona donde la versión más simple anterior funciona (ya que en casos simples sin metaclases personalizadas type (someclass) es type
).
Otros consejos
Respondiendo a sus comentarios sobre respuesta del viajero :
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
Ejecución que da como resultado
Buck Armstrong, Dinosaur Hunter 1 2 3
5000 1 2 3
¿No es eso lo que tenías en mente?
¿Por qué no puede usar herencia múltiple ?
class Origin:
new_attribute = 'something'
class X:
pass
class Y:
pass
class X1(Origin, X):
pass
class Y1(Origin, Y):
pass