Python decorate a class to change parent object type
decorator, multiple-inheritance, python
Solution
Use 3-arguments type:
def makeSomeNicelyDecoratedSubclass(someclass):
return type('MyNiceName', (someclass,), {'new_attribute':'something'})
This is indeed, as you surmised, a reasonably popular idiom.
Edit: in the general case if someclass has a custom metaclass you may need to extract and use it (with a 1-argument `type`) in lieu of `type` itself, to preserve it (this may be the case for your Django and App Engine models):
def makeSomeNicelyDecoratedSubclass(someclass):
mcl = type(someclass)
return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})
This also works where the simpler version above does (since in simple cases w/no custom metaclasses `type(someclass) is type`).
Problem
Suppose you have two classes X & Y. You want to decorate those classes by adding attributes to the class to produce new classes X1 and Y1. For example: ``` class X1(X): new_attribute = 'something' class Y1(Y): new_attribute = 'something' ``` new_attribute will always be the same for both X1 and Y1. X & Y are not related in any meaningful way, except that multiple inheritance is not possible. There are a set of other attributes as well, but this is degenerate to illustrate. I feel like I'm overcomplicating this, but I had thought to use a decorator, somewhat likeso: ``` def _xywrap(cls): class _xy(cls): new_attribute = 'something' return _xy @_xywrap(X) class X1(): pass @_xywrap(Y) class Y1(): pass ``` It feels like I'm missing a fairly common pattern, and I'd be much obliged for thoughts, input and feedback. Thank you for reading. Brian EDIT: Example: Here is a relevant extract that may illuminate. The common classes are as follows: ``` 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 ``` Here's a sub-document: ``` class Thing(AccessExpando): it = db.StringProperty() ``` Sometimes Thing will have the following properties: ``` Thing { it: ... } ``` And other times: ``` Thing { it: ..., users_permitted:..., owner:... } ``` I've been unable to figure out why Thing would sometimes have its _AccessParent properties, and other times not.