Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common practice of __new__ constructor? [closed]

I know (?) about theory behind __new__ constructor in Python, but what I ask about is common practice -- for what purpose is this constructor really (!) used?

I've read about initializing immutable objects (the logic is moved from __init__ to __new__), anything else? Factory pattern?

Once again, please note the difference:

  • for what task __new__ can be used -- I am not interested
  • for what tasks __new__ is used -- I am :-)

I don't write anything in Python, my knowledge is from reading, not from experience.

Where you can actually answer the question: Common practice of new constructor?

like image 866
greenoldman Avatar asked Oct 20 '22 12:10

greenoldman


1 Answers

The point of __new__ is to create an empty object instance that __init__ then initializes. Reimplementing __new__ you have full control of the instance you create, but you stop short of actually using the __init__ method to do any further processing. I can give you two cases where this is useful: automatic creation of methods and deserialization from disk of a class with a smart constructor. These are not the only ways you can solve these two problems. Metaclasses are another, more flexible way, but as any tool, you have different degrees of complexity you may want to get.

Automatic creation of methods

suppose you want to have a class that has a given set of properties. You can take control how these properties are initialized with code like this

class Foo(object):                                                                                                                                    
    properties = []                                                                                                                                   
    def __new__(cls, *args):                                                                                                                          
        instance = object.__new__(cls, *args)                                                                                                         
        for p in cls.properties:                                                                                                                      
            setattr(instance, p, 0)                                                                                                                   
        return instance                                                                                                                               

class MyFoo(Foo):                                                                                                                                     
    properties = ['bar', 'baz']                                                                                                                       

    def __init__(self):                                                                                                                               
        pass                                                                                                                                          



f=MyFoo()                                                                                                                                             
print dir(f)   

the properties you want are directly initialized to zero. You can do a lot of smart tricks, like doing the properties list dynamically. All objects instantiated will have those methods. A more complex case of this pattern is present in Django Models, where you declare the fields and get a lot of automatic stuff for free, thanks to __new__ big brother, metaclasses.

Deserialization from disk

Suppose you have a class with a given constructor that fills the fields of the class from an object, such as a process:

class ProcessWrapper(object):                                                                                                                         
    def __init__(self, process):                                                                                                                      
        self._process_pid = process.pid()                                                                                                             

    def processPid(self):                                                                                                                             
        return self._process_pid           

If you now serialize this information to disk and want to recover it, you can't initialize via the constructor. So you write a deserialization function like this, effectively bypassing the __init__ method you can't run.

def deserializeProcessWrapperFromFile(filename):                                                                                                      
    # Get process pid from file                                                                                                                       
    process = ProcessWrapper.__new__()                                                                                                                
    process._process_pid = process_pid                                                                                                                
    return process         
like image 190
Stefano Borini Avatar answered Oct 23 '22 11:10

Stefano Borini