简体   繁体   English

如何在Python中基类内创建派生类的对象?

[英]How to create object of derived class inside base class in Python?

I have a code like this: 我有这样的代码:

class Base:
    def __init__(self):
        pass

    def new_obj(self):
        return Base()  # ← return Derived()

class Derived(Base):
    def __init__(self):
        pass

In the line with a comment I actually want not exactly the Derived object, but any object of class that self really is. 在带注释的行中,我实际上并不想要Derived对象,而是self真正的类的任何对象。

Here is a real-life example from Mercurial . 以下是Mercurial的真实案例。

How to do that? 怎么做?

def new_obj(self):
    return self.__class__()

I can't think of a really good reason to do this, but as D.Shawley pointed out: 我想不出有这么好的理由, 正如D.Shawley指出的那样:

def new_obj(self):
    return self.__class__()

will do it. 会做的。

That's because when calling a method on a derived class, if it doesn't exist on that class, it will use the method resolution order to figure out which method to call on its inheritance chain. 这是因为在派生类上调用方法时,如果该类上不存在该方法,它将使用方法解析顺序来确定在其继承链上调用哪个方法。 In this case, you've only got one, so it's going to call Base.new_obj and pass in the instance as the first argument (ie self). 在这种情况下,你只有一个,所以它将调用Base.new_obj并将实例作为第一个参数传递(即self)。

All instances have a __class__ attribute, that refers to the class that they are an instance of. 所有实例都有一个__class__属性,该属性引用它们是其实例的类。 So given 所以给定

 class Base:
     def new_obj(self):
          return self.__class__()

 class Derived(Base): pass

 derived = Derived()

The following lines are functionally equivalent: 以下几行在功能上是等效的:

 derived.new_obj()
 # or
 Base.new_obj(derived)

You may have encountered a relative of this if you've either forgotten to add the self parameter to your function declaration, or not provided enough arguments to a function and seen a stack trace that looks like this: 如果您忘记将self参数添加到函数声明中,或者没有为函数提供足够的参数,并且看到如下所示的堆栈跟踪,则可能遇到过此函数的亲戚:

>>> f.bar()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes exactly 2 arguments (1 given)

You can use a classmethod: 你可以使用classmethod:

class Base:
    def __init__(self):
        pass

    @classmethod
    def new_obj(cls):
        return cls()

class Derived(Base):
    def __init__(self):
        pass

>>> b = Base()
>>> b.new_obj()
<__main__.Base at 0x10fc12208>
>>> d = Derived()
>>> d.new_obj()
<__main__.Derived at 0x10fdfce80>

You can also do this with a class method, which you create with a decorator. 您也可以使用类方法执行此操作,该方法是使用装饰器创建的。

In [1]: class Base:
   ...:     @classmethod
   ...:     def new_obj(cls):
   ...:         return cls()
   ...:

In [2]: class Derived(Base): pass

In [3]: print type(Base.new_obj())
<type 'instance'>

In [4]: print Base.new_obj().__class__
__main__.Base

In [5]: print Derived.new_obj().__class__
__main__.Derived

Incidentally (you may know this), you don't have to create __init__ methods if you don't do anything with them. 顺便说一句(你可能知道这一点),如果你不对它们做任何事情,就不必创建__init__方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM