Python украшает класс, чтобы изменить тип родительского объекта
-
05-07-2019 - |
Вопрос
Предположим , у вас есть два класса X и Y.Вы хотите украсить эти классы, добавив атрибуты к классу, чтобы создать новые классы X1 и Y1.
Например:
class X1(X):
new_attribute = 'something'
class Y1(Y):
new_attribute = 'something'
новый атрибут всегда будет одинаковым как для 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
Такое ощущение, что я упускаю из виду довольно распространенный шаблон, и я был бы очень признателен за мысли, вклад и обратную связь.
Спасибо вам за чтение.
Брайан
Редактировать: Пример:
Вот соответствующий отрывок, который может пролить свет.Распространенными классами являются следующие:
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 { it: ... }
И в другие разы:
Thing { it: ..., users_permitted:..., owner:... }
Я не смог понять, почему Thing иногда имеет свои свойства _AccessParent, а в других случаях нет.
Решение
Используйте 3 аргумента Тип:
def makeSomeNicelyDecoratedSubclass(someclass):
return type('MyNiceName', (someclass,), {'new_attribute':'something'})
Это действительно, как вы и предположили, достаточно популярная идиома.
Редактировать:в общем случае, если someclass имеет пользовательский метакласс, вам может потребоваться извлечь и использовать его (с аргументом 1 type
) вместо type
сам по себе, чтобы сохранить его (это может иметь место для ваших моделей Django и App Engine):
def makeSomeNicelyDecoratedSubclass(someclass):
mcl = type(someclass)
return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})
Это также работает там, где работает более простая версия выше (поскольку в простых случаях без пользовательских метаклассов type(someclass) is type
).
Другие советы
Отвечая на ваши комментарии по ответ "вояджера":
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
Разве это не то, что вы имели в виду?
Почему вы не можете использовать множественное наследование?
class Origin:
new_attribute = 'something'
class X:
pass
class Y:
pass
class X1(Origin, X):
pass
class Y1(Origin, Y):
pass