__new__ and __init__ in Python

前端 未结 1 1166
無奈伤痛
無奈伤痛 2020-12-12 14:09

I am learning Python and so far I can tell the things below about __new__ and __init__:

  1. __new__ is for object creation
1条回答
  •  南方客
    南方客 (楼主)
    2020-12-12 15:03

    how I should structure the class using __init__ and __new__ as they are different and both accepts arbitrary arguments besides default first argument.

    Only rarely will you have to worry about __new__. Usually, you'll just define __init__ and let the default __new__ pass the constructor arguments to it.

    self keyword is in terms of name can be changed to something else? But I am wondering cls is in terms of name is subject to change to something else as it is just a parameter name?

    Both are just parameter names with no special meaning in the language. But their use is a very strong convention in the Python community; most Pythonistas will never change the names self and cls in these contexts and will be confused when someone else does.

    Note that your use of def __new__(tuple) re-binds the name tuple inside the constructor function. When actually implementing __new__, you'll want to do it as

    def __new__(cls, *args, **kwargs):
        # do allocation to get an object, say, obj
        return obj
    

    Albeit I said I want to return tuple, this code works fine and returned me [1,2,3].

    MyClass() will have the value that __new__ returns. There's no implicit type checking in Python; it's the responsibility of the programmer to return the correct type ("we're all consenting adults here"). Being able to return a different type than requested can be useful for implementing factories: you can return a subclass of the type requested.

    This also explains the issubclass/isinstance behavior you observe: the subclass relationship follows from your use of class MyClass(tuple), the isinstance reflects that you return the "wrong" type from __new__.

    For reference, check out the requirements for __new__ in the Python Language Reference.

    Edit: ok, here's an example of potentially useful use of __new__. The class Eel keeps track of how many eels are alive in the process and refuses to allocate if this exceeds some maximum.

    class Eel(object):
        MAX_EELS = 20
        n_eels = 0
    
        def __new__(cls, *args, **kwargs):
            if cls.n_eels == cls.MAX_EELS:
                raise HovercraftFull()
    
            obj = super(Eel, cls).__new__(cls)
            cls.n_eels += 1
            return obj
    
        def __init__(self, voltage):
            self.voltage = voltage
    
        def __del__(self):
            type(self).n_eels -= 1
    
        def electric(self):
            """Is this an electric eel?"""
            return self.voltage > 0
    

    Mind you, there are smarter ways to accomplish this behavior.

    0 讨论(0)
提交回复
热议问题