2

Using python 3.x, I would like to have a method of a class that returns an instance of the same class; it should be an inheritable method such that sub-classes of the class can call the function to return an instance of the sub-class, not the super-class.

What I would like to see is something like this

class MyClass():
...
    def newInstance():##return a new instance of MyClass

class subClass(MyClass):##inherits newInstance from MyClass, but will return an instance of subClass
...
a = MyClass()
b = subClass()
c = a.newInstance()##a new instance of MyClass
d = b.newInstance()##a new instance of subClass

The following isn't inheritable in the right way

class MyClass()
.
.
.
def newInstance(self)##return a new instance...
    out = MyClass()
    return out##a sub-class would return an instance of the superclass, not it's own class...

I tried this

class MyClass()
.
.
.
def newInstance(self)##return a new instance...
    x = self.__class__ ##doesn't work, returns NoneType
    out = x()
    return out

which gives a TypeError 'NoneType' object is not callable.

I also tried

def newInstance(self)##return a new instance...
    out = self.__init__()
    return out

which also returns a NoneType object.

philosofool
  • 773
  • 4
  • 12
  • 3
    `return type(self)()`? – jonrsharpe Jun 06 '19 at 16:11
  • 1
    jonrsharpe's solution (in Python 3, at least) should be equivalent to your `__class__` solution, and afaict both should work. Though I do find `type` cleaner. – Silvio Mayolo Jun 06 '19 at 16:13
  • so is `newInstance` an instance method on the class? Also, `__init__` shouldn't return anything, so `out = self.__init__()` would raise errors for NoneType anyways – C.Nivs Jun 06 '19 at 16:15
  • 1
    Your second example (essentially `return self.__class__()` works fine for me and returns the subclassed type as you want. I'm not sure where you're getting NoneTypes error from. – SyntaxVoid Jun 06 '19 at 16:16
  • As hinted to in Silvio Mayolo's comment, the version of Python could matter. See also https://stackoverflow.com/questions/54867/what-is-the-difference-between-old-style-and-new-style-classes-in-python – Leporello Jun 06 '19 at 16:27

1 Answers1

4

Use the classmethod decorator.

class A:
    def __init__(self):
        print('Creating a new A')

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

class B(A):
    def __init__(self):
        print('Creating a new B')

# Create new instances directly from the desired class    
a = A.newInstance()
b = B.newInstance()

# Create new instances from existing instances
a2 = a.newInstance()
b2 = b.newInstance()

print(type(a), type(b))
print(type(a2), type(b2))

This results in the following output:

Creating a new A
Creating a new B
Creating a new A
Creating a new B
<class '__main__.A'> <class '__main__.B'>
<class '__main__.A'> <class '__main__.B'>
brady
  • 2,227
  • 16
  • 18