2

Assume the following code:

class NumStorage(object):

    def __new__(cls, *nargs):
        name = cls.__name__
        parents = cls.__bases__
        kwargs = {'num%i' % pos : i for pos, i in enumerate(nargs, 1)}
        if any(kwargs.values()) and len(kwargs.values()) >= 2:
            end = len(kwargs.values()) + 1
            kwargs['num%i' % end] = sum(kwargs.values())
        self = type(name, parents, kwargs)
        return self

This NumStorage object takes in an arbitrary amount of numbers, and if there are two or more numbers and their sum adds up to something greater than 0, then it creates a new kwarg key.

If the initialization of the instance of NumStorage can happen in __new__ then why on earth does python even need an __init__? Another thing that's confusing me; if we do add an __init__ method to the NumStorage class as so:

class NumStorage(object):

    def __new__(cls, *nargs):
        name = cls.__name__
        parents = cls.__bases__
        kwargs = {'num%i' % pos : i for pos, i in enumerate(nargs, 1)}
        if any(kwargs.values()) and len(kwargs.values()) >= 2:
            end = len(kwargs.values()) + 1
            kwargs['num%i' % end] = sum(kwargs.values())
        self = type(name, parents, kwargs)
        return self

    def __init__(self, *nargs):
        print("initializing")

It never prints "initializing" even though the __init__ should be called after __new__ since __new__ returned an instance of the object, no? If not, what is it I'm getting confused with?

Kara
  • 6,115
  • 16
  • 50
  • 57
user3002473
  • 4,835
  • 8
  • 35
  • 61
  • 3
    Does any of those answer your question? http://stackoverflow.com/q/3131488/218196, http://stackoverflow.com/q/4859129/218196, http://stackoverflow.com/q/8609153/218196, http://stackoverflow.com/q/674304/218196, http://stackoverflow.com/q/9367126/218196 – Felix Kling Feb 05 '14 at 01:51
  • Thanks for supplying those resources! I looked through a lot of stuff before posting this question but never came across those questions and they cleared up a lot of my confusion. – user3002473 Feb 05 '14 at 02:02

2 Answers2

3

__init__ came first. __new__ was added primarily to... well, I'll let the documentation explain:

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

__init__ was mostly good enough for the old-style class system. Even if you subclassed an "immutable" old-style class, you'd just provide the appropriate arguments to the superclass's __init__. That doesn't cut it with subclasses of, say, tuple.

As for __init__ not being called:

If __new__() returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to __new__().

If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Then how may I edit the above code so that `__new__` returns an instance of the class `NumStorage`, since I thought using type would be the way to do it? – user3002473 Feb 05 '14 at 01:56
  • 1
    @user3002473: What you're doing with `type` is creating and returning a new class. Instead, what you need to do is call `super(NumStorage, cls).__new__(cls, *nargs)` and then do whatever you need to initialize the object. – user2357112 Feb 05 '14 at 01:59
  • Ahh that makes a lot of sense now. Thank you very much! – user3002473 Feb 05 '14 at 02:02
1

does python even need an __init__?

No, python doesn't need __init__, but if there were only __new__, every time you created a class, you'd need to figure out all the bits and pieces that go into __new__.

It makes python much easier, and less error prone, to separate the two out.

Plus, historically __init__ precedes __new__.

Marcin
  • 48,559
  • 18
  • 128
  • 201