161

I have a class with an __init__ function.

How can I return an integer value from this function when an object is created?

I wrote a program, where __init__ does command line parsing and I need to have some value set. Is it OK set it in global variable and use it in other member functions? If so how to do that? So far, I declared a variable outside class. and setting it one function doesn't reflect in other function ??

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
webminal.org
  • 44,948
  • 37
  • 94
  • 125
  • 9
    If you were considering returning an error code, raise an exception instead. – JoeG Mar 22 '10 at 11:48
  • 1
    Please remove your comment and update your question. You own the question. It's your question. Please fix the question to correctly show what your real problem is. You're misusing `__init__`; we can help you if you describe what you're really trying to accomplish. – S.Lott Mar 22 '10 at 14:47
  • 2
    `__init__` probably should *not* be doing command-line parsing. Define a class method that does the actual parsing, and pass the parsed values to `__init__`. Let `__init__` worry about creating the necessary attributes, not figuring out how to produce the values for those attributes. – chepner Jul 13 '21 at 20:45
  • Note for future readers: If you want to get generic information back as a result of calling `__init__`, see the answers given here. If you want to *signal that something went wrong*, raise an exception. That doesn't answer the question that was asked here, but might be what you have in mind. – Karl Knechtel Jul 02 '22 at 02:47

13 Answers13

195

If you want to return some other object when a class is called, then use the __new__() method:

class MyClass:
    def __init__(self):
        print("never called in this case")

    def __new__(cls):
        return 42

obj = MyClass()
print(obj)
# Output: 42
STerliakov
  • 4,983
  • 3
  • 15
  • 37
Jacek Konieczny
  • 8,283
  • 2
  • 23
  • 35
  • 14
    Yeah, __new__ is the right way of returning something other than a class instance when using a class... I'm just wondering - is there any reason you might actually want to DO that? – weronika Sep 26 '11 at 17:28
  • 49
    @weronika One idea: in any situation where you'd normally use a factory, but you have some reason to want to present an interface that looks like normal class instantiation. Example: when adding some new optional parameters into your class's `__init__`, you realise that really, to provide the flexibility you want, you need a class factory that returns instances of specialised subclasses. But your library's users are already using your existing API. To preserve it, you override `__new__` to return instances of your specialised subclasses. – Mark Amery Jan 13 '14 at 22:13
  • 18
    If you want to see an example of what Mark Amery said, check out the source code of the `datetime` module from the Standard Library. It uses `__new__` in exactly this fashion. – Zearin May 14 '15 at 14:44
  • Also if anyone wants to do this make sure to inherit from object otherwise it won't work. – Mino_e Jul 26 '17 at 16:42
  • I kind of think at this pount, just using a regular function makes more sense. Might be a bit alien to folks from the Java dimension (functions not in classes? heresy!) but its pythonic. (Also you can assign properties to functions as in funtionName.val =.. which is kind of wild but it works) – Shayne Sep 01 '19 at 00:03
165

__init__ is required to return None. You cannot (or at least shouldn't) return something else.

Try making whatever you want to return an instance variable (or function).

>>> class Foo:
...     def __init__(self):
...         return 42
... 
>>> foo = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None
Bachsau
  • 1,213
  • 14
  • 21
Can Berk Güder
  • 109,922
  • 25
  • 130
  • 137
  • 36
    +1: You **cannot** return something else. It doesn't make any sense. – S.Lott Mar 22 '10 at 14:45
  • 83
    __init__ doesn't return the newly created object - as seen in the TypeError, it is required to return None, right? The newly created object is returned by __new__, __init__ just sets some of its attributes. But yes, as you said, changing __init__, or __new__, to return something else really makes no sense. – weronika Sep 26 '11 at 17:25
  • Where is `new` here? Is `new` implicit in Python? I assumed Python's semantics were different from Java and the other languages that do use this word. – cs95 Jul 20 '16 at 06:06
  • 1
    @Shiva AFAIK, by new weronika meant __new__(self) not the general java semantic. – Harsh Daftary Dec 16 '16 at 18:45
  • 2
    Just because it can't be done doesn't mean it doesn't make sense. It would, for instance, be nice to pass data from `super().__init__` to the derived class without having to relay it through an instance variable. – c z Mar 28 '18 at 15:06
  • __init__ should not return anything, included None. If you are adding typing, the ones for __init__ must be NoReturn. – Lucas Vazquez Apr 18 '20 at 15:37
  • May I know how the `pd.DataFrame({something})` returns output? How that can be able to call other class methods – Parvathirajan Natarajan Jul 15 '20 at 09:54
43

From the documentation of __init__:

As a special constraint on constructors, no value may be returned; doing so will cause a TypeError to be raised at runtime.

As a proof, this code:

class Foo(object):
    def __init__(self):
        return 2

f = Foo()

Gives this error:

Traceback (most recent call last):
  File "test_init.py", line 5, in <module>
    f = Foo()
TypeError: __init__() should return None, not 'int'
nosklo
  • 217,122
  • 57
  • 293
  • 297
24

Sample Usage of the matter in question can be like:

class SampleObject(object):

    def __new__(cls, item):
        if cls.IsValid(item):
            return super(SampleObject, cls).__new__(cls)
        else:
            return None

    def __init__(self, item):
        self.InitData(item) #large amount of data and very complex calculations

...

ValidObjects = []
for i in data:
    item = SampleObject(i)
    if item:             # in case the i data is valid for the sample object
        ValidObjects.append(item)
Neuron
  • 5,141
  • 5
  • 38
  • 59
PMN
  • 493
  • 5
  • 11
16

The __init__ method, like other methods and functions returns None by default in the absence of a return statement, so you can write it like either of these:

class Foo:
    def __init__(self):
        self.value=42

class Bar:
    def __init__(self):
        self.value=42
        return None

But, of course, adding the return None doesn't buy you anything.

I'm not sure what you are after, but you might be interested in one of these:

class Foo:
    def __init__(self):
        self.value=42
    def __str__(self):
        return str(self.value)

f=Foo()
print f.value
print f

prints:

42
42
quamrana
  • 37,849
  • 12
  • 53
  • 71
11

__init__ doesn't return anything and should always return None.

gruszczy
  • 40,948
  • 31
  • 128
  • 181
6

You can just set it to a class variable and read it from the main program:

class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode
PythonPro
  • 291
  • 2
  • 11
4

We can not return value from init. But we can return value using new.

class Car:
    def __new__(cls, speed, unit):
        return (f"{speed} with unit {unit}")


car = Car(42, "km")
print(car)
Suraj Garg
  • 41
  • 2
  • Yes, but you can't really return arbitrary values from `__new__` and still have the class "protocol" make sense. – chepner Jul 13 '21 at 20:34
2

init() return none value solved perfectly

class Solve:
def __init__(self,w,d):
    self.value=w
    self.unit=d
def __str__(self):
    return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)

output: my speed is 21 kmh

0

Just wanted to add, you can return classes in __init__

@property
def failureException(self):
    class MyCustomException(AssertionError):
        def __init__(self_, *args, **kwargs):
            *** Your code here ***
            return super().__init__(*args, **kwargs)

    MyCustomException.__name__ = AssertionError.__name__
    return MyCustomException

The above method helps you implement a specific action upon an Exception in your test

  • 5
    `super().__init__` is returning `None`, so you are returning `None`, which is fine, but redundant. – c z Mar 28 '18 at 15:04
0

Met this case when tried to parse some string data into a recursive data structure, and had a counter to be passed through.

Python does not allow to return anything from __init__, but you may write a factory function, or a class method, or a Parser class, depending on the code structure and complexity of parsing, which will parse your data into data objects.

Global variable is not a good solution, as it may be changed somewhere else, breaking the parsing logic.

Function example:

class MyClass():
    def __init__(self, a, b, c):
        # only assignments here
        self.a = a
        self.b = b
        self.c = c
        # return None


def parse(data):
    # parsing here
    a = ...
    b = ...
    c = ...

    # status, counter, etc.
    i = ...

    # create an object
    my_obj = MyClass(a, b, c)
    
    # return both
    return my_obj, i


# get data and parse
data = ...
my_obj, i = parse(data)

Class method example:

class MyClass():
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    @classmethod
    def parse(cls, data):
        a = ...
        b = ...
        c = ...

        i = ...

        obj = cls(a, b, c)
        return obj, i


data = ...
my_obj, i = MyClass.parse(data)
Som-1
  • 601
  • 7
  • 16
-3

solution here Yes, trying to return from the init method in python returns errors as it is a constructor of the class you can only assign values for the scope of the class but not return a specific value. if you want to return a value but do not wish to create a method, you can use str method

def __init__(self,a):
    self.value=a

   def __str__(self):
    return str("all my return values are possible here")`
reema dass
  • 33
  • 7
-4

Well, if you don't care about the object instance anymore ... you can just replace it!

class MuaHaHa():
def __init__(self, ret):
    self=ret

print MuaHaHa('foo')=='foo'
cosmo
  • 1