动态地将基类混合到Python中的实例

时间:2011-12-17 13:11:02

标签: python oop mixins

是否可以在运行时向对象实例(不是类!)添加基类?关于Object#extend在Ruby中的工作方式:

class Gentleman(object):
  def introduce_self(self):
    return "Hello, my name is %s" % self.name

class Person(object):
  def __init__(self, name):
    self.name = name

p = Person("John")
# how to implement this method?
extend(p, Gentleman)
p.introduce_self() # => "Hello, my name is John"

3 个答案:

答案 0 :(得分:38)

这会动态定义一个新类GentlePerson,并将p的类重新分配给它:

class Gentleman(object):
  def introduce_self(self):
    return "Hello, my name is %s" % self.name

class Person(object):
  def __init__(self, name):
    self.name = name

p = Person("John")
p.__class__ = type('GentlePerson',(Person,Gentleman),{})
print(p.introduce_self())
# "Hello, my name is John"

根据您的请求,这会修改p的基础,但不会更改p的原始类Person。因此,Person的其他实例不受影响(如果AttributeError被调用,则会引发introduce_self


虽然在问题中没有直接询问,但我会为googlers和好奇心寻求者添加,只有当类不直接从{{1}继承时,才可以动态更改类的基础但是(AFAIK) }}:

object

答案 1 :(得分:10)

稍微清洁的版本:

def extend_instance(obj, cls):
    """Apply mixins to a class instance after creation"""
    base_cls = obj.__class__
    base_cls_name = obj.__class__.__name__
    obj.__class__ = type(base_cls_name, (base_cls, cls),{})

答案 2 :(得分:5)

虽然已经回答了,但这是一个功能:

def extend(instance, new_class):
    instance.__class__ = type(
          '%s_extended_with_%s' % (instance.__class__.__name__, new_class.__name__), 
          (instance.__class__, new_class), 
          {},
          )