在Python中动态地将基类与实例混合

2024-10-06 11:17:52 发布

您现在位置:Python中文网/ 问答频道 /正文

是否可以将基类添加到对象实例(不是类!)在运行时?类似于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"

Tags: 对象nameselfhelloobjectismydef
3条回答

稍微干净的版本:

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

虽然已经有答案了,但这里有一个函数:

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

这将动态定义一个新类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)。


虽然在这个问题中没有直接问到这个问题,但是我要补充的是,对于Google和好奇者来说,也可以动态地改变一个类的基,但是(AFAIK)只有当这个类没有直接从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

相关问题 更多 >