3

假设您有两个类 X 和 Y。您想通过向类添加属性来装饰这些类以生成新的类 X1 和 Y1。

例如:

class X1(X):
  new_attribute = 'something'

class Y1(Y):
  new_attribute = 'something'

对于 X1 和 Y1, new_attribute将始终相同。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 会具有以下属性:

 Thing { it: ... }

其他时候:

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

我一直无法弄清楚为什么 Thing 有时会有它的 _AccessParent 属性,而其他时候则没有。

4

3 回答 3

5

使用 3 参数类型

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

正如您所推测的那样,这确实是一个相当流行的成语。

编辑:在一般情况下,如果 someclass 有一个自定义元类,您可能需要提取并使用它(使用 1-argument type)来代替type它自己,以保留它(这可能是您的 Django 和 App Engine 模型的情况):

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

这也适用于上面更简单的版本(因为在简单的情况下没有自定义元类type(someclass) is type)。

于 2009-09-12T00:58:23.797 回答
3

回应您对航海者回答的评论:

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

这不是你的想法吗?

于 2009-09-11T19:33:21.887 回答
2

为什么不能使用多重继承

class Origin:
  new_attribute = 'something'

class X:
  pass

class Y:
  pass

class X1(Origin, X):
  pass

class Y1(Origin, Y):
  pass
于 2009-09-11T17:43:37.953 回答