Python:是否可以从父类的实例构造子类的实例?

6
这可能是一个糟糕的想法(如果是,请随意告诉我),但我正在探索Python的边界,我可以看到它如何有用(事实上,我现在正在考虑潜在的案例)。
以下是设置信息:

---(API文件)---

class APINode(object):
    def __init__(self, *args, **kwargs):
        # initialize some instance variables

    def render(self, arg1, arg2):
        # do some stuff and return something

def api_function( arg1, arg2 ):
    # do some stuff
    return APINode(args, kwargs)

---- (我的文件)----

class MyNode(APINode):
    def render(self, arg1, arg2):
        #My override of APINode's render 


def my_function( arg1, arg2 ):
    api_parent_instance = api_function( arg1, arg2 )
    #Can I some how create an instance of MyNode from api_parent_instance here?

我希望稍微修改api_function的输出,基本上只是覆盖它返回的对象中的render函数。我觉得我的选项有:(1)复制api_function的内容到my_function中,但是构造并返回一个MyNode而不是APINode;或者(2)从my_function中调用api_function,让它完成工作——构造并返回一个APINode类型的对象,然后我可以从该对象中创建一个MyNode以覆盖那个方法。
归根结底:在Python中,是否可能从父类的实例构造子类的实例?
(看起来很熟悉或想知道实际情况是什么?我正在尝试扩展Django模板标签。)
6个回答

7
我认为使用MyNode包装APINode会比继承它更好。你可以实现自己的render()方法,并将其他所有方法委托给被包装的APINode。这样,你就能够从现有的APINode创建一个新的MyNode。
无法从父实例创建子实例。父实例是APINode的一个实例,你不能改变对象的类。

2

请勿在家中进行此操作。

>>> class A:
...     def hi(self):
...         print "I am an A!"
... 
>>> class B:
...     def hi(self):
...         print "I am a B!"
... 
>>> a = A()
>>> a.hi()
I am an A!
>>> # Doing this will likely lead to hard to find bugs.
>>> a.__class__ = B
>>> a.hi()
I am a B!
>>> 

改写 API,而不是使用 Monkey Patch 技术!

def render(self, arg1, arg2):
    #My override of APINode's render 
APINode.render = render
#congratulations, now APINode uses your render function.

这仍然可能导致难以找到的错误,但代码更加简洁。


第一个例子绝对是值得一笑的。Monkey patch 的想法很酷,而且可以相对轻松地解决我的问题。最终我使用了一个包装类,如上所建议,似乎更适合长期使用,但我喜欢你的回应(在添加后)。 - B Robster

1

重载分配器。

class B(object):
  def __new__(cls, val):
    if val:
      return D()
    return super(B, cls).__new__(cls)

  def foo(self):
    return 'bar'

class D(object):
  def foo(self):
    return 'baz'

b1 = B(False)
b2 = B(True)
print b1.foo()
print b2.foo()

有趣。在我的情况下不适用,因为我正在处理API类,但我肯定学到了一些东西。 - B Robster

1

这不是我会推荐的事情,但无论如何:

>>> class Monkey(object):
...     def eat(self, smth):
...             if self.likes(smth):
...                     print "Yummy!"
...             else:
...                     print "Yuck!"
...     def likes(self, smth):
...             return smth == "banana"
... 
>>> m = Monkey()
>>> m.eat("banana")
Yummy!
>>> m.eat("cheezburger")
Yuck!
>>> def patch(self, smth):
...     return True
...
>>> m.likes = type(m.likes)(patch, m.likes, Monkey)
>>> m.eat("cheezburger")
Yummy!
>>> 

在你的特定情况下,它会像这样:
def my_render(self, arg1, arg2):
    #My override of APINode's render 

def my_function( arg1, arg2 ):
    api_parent_instance = api_function( arg1, arg2 )
    api_parent_instance.render = type(api_parent_instance.render)(
        api_parent_instance,
        api_parent_instance.render,
        api_parent_instance.__class__)

    ...

我最终选择了一个包装类,因为它看起来是一个不错的方式来解决问题,但这个例子很酷也很有趣。谢谢。 - B Robster
@Ben - 包装器类是做这种事情的最佳选择 :-) - Mike Ivanov

1
这是一种非常简单且安全的方法,可以从父类的方法中生成子类的新实例:
class Parent(object):
    def __init__(self):
        pass

    def generate_new_child_object(self):
        print "Generating a new object of type " + str(type(self))
        return type(self)()

class Child(Parent):
    pass

你可以在终端中按照以下方式检查:

>>> child = Child()
>>> type(child)
<class 'Child'>
>>> generated_child = child.generate_new_child_object()
Generating a new object of type <class 'Child'>
>>> type(generated_child)
<class 'Child'>

0

我认为你想做的是查看超类或者什么东西。就像这样: a = obj._class_() 我记不太清了,但你应该在 Python 文档中查找。

除非这不是你想要的。但是 obj._class_() 应该会生成一个相同类别的新对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接