Pergunta

Suponha que você tenha duas classes X & Y. Você quer decorar essas classes, adicionando atributos para a classe para produzir novas classes X1 e Y1.

Por exemplo:

class X1(X):
  new_attribute = 'something'

class Y1(Y):
  new_attribute = 'something'

new_attribute será sempre o mesmo para ambos X1 e Y1. X e Y não estão relacionados de qualquer modo significativo, excepto que a herança múltipla não é possível. Há um conjunto de outros atributos, bem como, mas isso é degenerado para ilustrar.

Eu sinto que estou complicar isso, mas eu tinha pensado em usar um decorador, um pouco likeso:

def _xywrap(cls):
  class _xy(cls):
    new_attribute = 'something'
  return _xy

@_xywrap(X)
class X1():
   pass

@_xywrap(Y)
class Y1():
   pass

Parece que eu estou sentindo falta de um padrão bastante comum, e eu ficaria muito grato por pensamentos, opiniões e comentários.

Obrigado pela leitura.

Brian

EDIT: Exemplo:

Aqui está um extrato relevante que possa iluminar. As classes comuns são as seguintes:

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

Aqui está um sub-documento:

 class Thing(AccessExpando):
     it = db.StringProperty()

Às vezes coisa vai ter as seguintes propriedades:

 Thing { it: ... }

e outras vezes:

 Thing { it: ..., users_permitted:..., owner:... }

Eu fui incapaz de descobrir por que coisa, às vezes, tem suas propriedades _AccessParent, e outras vezes não.

Foi útil?

Solução

Use 3-argumentos digite :

def makeSomeNicelyDecoratedSubclass(someclass):
  return type('MyNiceName', (someclass,), {'new_attribute':'something'})

Esta é, de facto, como você imaginou, uma linguagem razoavelmente popular.

Editar : no caso geral se SomeClass tem uma metaclass personalizado que você pode precisar para extrair e usá-lo (com um type 1-argumento) em vez de si type, para preservá-lo (pode ser o caso para os seus modelos Django e Google App Engine):

def makeSomeNicelyDecoratedSubclass(someclass):
  mcl = type(someclass)
  return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})

Isso também funciona onde a versão mais simples acima faz (uma vez que em casos simples w / não metaclasses personalizados type(someclass) is type).

Outras dicas

Em resposta a seus comentários sobre a resposta :

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

Running que resulta em

Buck Armstrong, Dinosaur Hunter 1 2 3
5000 1 2 3

Não é isso que você tinha em mente?

Por que você não pode usar herança múltipla ?

class Origin:
  new_attribute = 'something'

class X:
  pass

class Y:
  pass

class X1(Origin, X):
  pass

class Y1(Origin, Y):
  pass
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top