5

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.

Here is a real-life example from Mercurial.

How to do that?

4
  • 3
    Clarification request: who will call this method? If you intend to call it from the derived class, you can do this with a class method. Commented Apr 1, 2016 at 15:23
  • 2
    In your example, why would you call Derived.new_obj() as opposed to Derived()?. Also new_obj should be a @classmethod as others have pointed out in their answers. Commented Apr 1, 2016 at 15:28
  • 1
    @abyss.7 your example from Mercurial has a hard coded class name of manifest. It isn't the same. You can use self.__class__ to get the class name of the current instance dynamically. Commented Apr 1, 2016 at 15:39
  • @JoshJ That is exactly what I want to replace it with. It shouldn't be hardcoded. Commented Apr 1, 2016 at 15:40

4 Answers 4

9
def new_obj(self):
    return self.__class__()
Sign up to request clarification or add additional context in comments.

Comments

5

I can't think of a really good reason to do this, but as D.Shawley pointed out:

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 (i.e. self).

All instances have a __class__ attribute, that refers to the class that they are an instance of. 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:

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

1 Comment

"I can't think of a really good reason to do this, but ..." Encapsulation of mathematical and bitwise operator overloading result (return new derived class instance instead of instance variable operation result itself, without having to redefine overloading on inheritance). obj3 = obj1 + obj2
1

You can use a 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>

Comments

0

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.

3 Comments

But __init__ methods will be called on object instantiating, nop?
@IronFist There are defaults automatically provided for you. They don't do much, but neither does defining an __init__ that takes no args and just passes :)
yea...just to give to the OP correct idea about the point of having __init___ .. ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.