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.

¿Fue útil?

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 escriba para preservarlo (este puede ser el caso de sus modelos Django y App Engine):

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top