Python украшает класс для изменения типа родительского объекта - PullRequest
3 голосов
/ 11 сентября 2009

Предположим, у вас есть два класса X & Y. Вы хотите украсить эти классы, добавив атрибуты в класс для создания новых классов X1 и Y1.

Например:

class X1(X):
  new_attribute = 'something'

class Y1(Y):
  new_attribute = 'something'

new_attribute всегда будет одинаковым для X1 и Y1. X & Y никак не связаны между собой, за исключением того, что множественное наследование невозможно. Существует также ряд других атрибутов, но это вырожденно для иллюстрации.

Мне кажется, что я слишком усложняю это, но я думал использовать декоратор, как-то так:

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

@_xywrap(X)
class X1():
   pass

@_xywrap(Y)
class Y1():
   pass

Такое ощущение, что мне не хватает довольно распространенного паттерна, и я был бы очень благодарен за мысли, отзывы и отзывы.

Спасибо, что прочитали.

Brian

РЕДАКТИРОВАТЬ: Пример:

Вот соответствующая выдержка, которая может загореться. Общие классы следующие:

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

Вот поддокумент:

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

Иногда Thing имеет следующие свойства:

 Thing { it: ... }

И другие времена:

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

Мне не удалось понять, почему иногда у Thing есть свойства _AccessParent, а иногда нет.

Ответы [ 3 ]

5 голосов
/ 12 сентября 2009

Использовать 3 аргумента тип :

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

Это действительно, как вы и предполагали, довольно популярная идиома.

Редактировать : в общем случае, если у некоторого класса есть собственный метакласс, вам может потребоваться извлечь и использовать его (с 1 аргументом type) вместо самого type, чтобы сохранить его (это может иметь место для ваших моделей Django и App Engine):

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

Это также работает там, где работает более простая версия выше (поскольку в простых случаях без пользовательских метаклассов type(someclass) is type).

3 голосов
/ 11 сентября 2009

Отвечая на ваши комментарии на ответ Voyager :

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

Запуск, который приводит к

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

Разве это не то, что вы имели в виду?

2 голосов
/ 11 сентября 2009

Почему вы не можете использовать множественное наследование ?

class Origin:
  new_attribute = 'something'

class X:
  pass

class Y:
  pass

class X1(Origin, X):
  pass

class Y1(Origin, Y):
  pass
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...