【问题标题】:Python decorate a class to change parent object typePython 装饰一个类来改变父对象类型
【发布时间】:2009-09-11 17:18:05
【问题描述】:

假设您有两个类 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

感觉好像我错过了一个相当普遍的模式,我非常感谢你的想法、输入和反馈。

感谢您的阅读。

布赖恩

编辑:示例:

这是一个相关的摘录,可能会有所启发。常用的类如下:

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 属性,而有时却没有。

【问题讨论】:

  • 你能解释一下为什么直接在类中定义这些属性是一件坏事吗? (例如,如果有多个属性 - 但您声明 X/Y 是不相关的)在我看来,无论如何您都必须明确定义它们,并且将它们留在课堂上并不是那么糟糕。
  • @Fragsworth - 要添加的属性很多,实际上有 5+ 个 X / Y 类(X & Y 只是为了说明而退化),要添加的属性将始终相同。没有对重复属性进行某种重构来创建代码,这违反了 DRY。

标签: python decorator multiple-inheritance


【解决方案1】:

使用 3 参数 type:

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)。

【讨论】:

  • 嗨,亚历克斯!感谢您更新您的答案。实际上,我昨天看到这个后就开始发表评论,但我在等待回复之前尝试一下。 mcl 是我简要考虑的一个关键点。我会对此进行测试,并在本周的某个时候让你知道(我希望如此)。非常感谢您的想法和意见!这是一个有趣的问题。 :)
【解决方案2】:

voyager's answer回复你的cmets:

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

这不是你的想法吗?

【讨论】:

  • 这行得通-由于某种原因,当我有例如时它不起作用(即通过我的单元测试)类 Person(Mixin, db.Model),但我已经把它反转了(即类 Person(db.Model, Mixin)),它现在工作正常。这是我所期望和期望的行为,所以我很感谢您发布了您的答案。谢谢。
  • 我错了——这只有时有效。我希望为什么它有时有效而其他人无效,这是一个需要其他人解决的谜,但我只想说,有时我会得到具有 Mixin 属性的子类(例如 Person),而有时我会得到没有它们的子类。莫名其妙——如果我有什么发现,我会发布更多信息。
  • 你能展示一些表现出这种行为的代码吗?您的 mixin 的属性是否有可能会遮蔽(或被其他超类的属性遮蔽)?
  • @Will:感谢您对此的关注。我只是添加了一个示例。
  • @Will:目标是让 Mixin 对象包含 db.*Properties(即不仅仅是原语)。
【解决方案3】:

为什么不能使用multiple inheritance

class Origin:
  new_attribute = 'something'

class X:
  pass

class Y:
  pass

class X1(Origin, X):
  pass

class Y1(Origin, Y):
  pass

【讨论】:

  • 感谢您的回复。多重继承不起作用,因为在创建 X 和 Y 时使用反射(即 X 是 google.appengine.ext.db.Model,Y 是 django.db.model,Z 是 google.appengine.ext.db .polymodel.Polymodel 等)。这就是为什么我在问题中提到多重继承是不可能的。
  • ...或者澄清一下...我认为这是不可能的。 :o) 如果有人能证明它是,我会很高兴的。
  • 我不确定我是否理解为什么多重继承在这种情况下不起作用。在 voyager 的示例中,它可以很容易地成为 class X1(Origin, google.appengine.db.Model)class Y1(Origin, django.db.Model),不是吗?
  • 你会这么认为——但我遇到的问题是模型有时具有 Origin 的属性,有时则没有。当 Origins 的属性开始出现在我的模型中时,我非常高兴,但随后它们莫名其妙地停止了出现。这种不确定性非常令人不安!我不确定发生了什么,但我确定它不起作用。我认为有人(也许是我)将不得不深入研究 Google App Engine 代码以弄清楚它是如何向其 _entities 添加属性的。
猜你喜欢
  • 2021-07-16
  • 2019-10-17
  • 2013-09-19
  • 2022-10-07
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 2020-11-25
  • 2019-06-11
相关资源
最近更新 更多