简体   繁体   中英

Why not just __new__ and not __new__ and __init__ in python?

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?

__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.

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__ .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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