在Python中动态混入基类到实例

50 投票
3 回答
14755 浏览
提问于 2025-04-17 08:33

在运行时,是否可以给一个对象实例(不是类哦)添加一个基类?就像Ruby里的Object#extend那样,能做到吗?

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 个回答

8

虽然这个问题已经有人回答了,但我还是给你提供一个函数:

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

稍微更简洁的版本:

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),{})
61

这段话的意思是,动态地定义了一个新的类叫做 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 实例不会受到影响(如果调用 introduce_self,会出现 AttributeError 错误)。


虽然问题中没有直接问到,但我想补充一下,出于好奇或者方便搜索,实际上也可以动态地改变一个类的基类,但(据我所知)只有在这个类不是直接从 object 继承的情况下才能做到:

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

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

p = Person("John")
Person.__bases__=(Gentleman,object,)
print(p.introduce_self())
# "Hello, my name is John"

q = Person("Pete")
print(q.introduce_self())
# Hello, my name is Pete

撰写回答