extend class: include factories functions inside constructor

Peter Otten __peter__ at web.de
Thu Aug 18 10:45:34 EDT 2011


aspineux wrote:

> Hi
> I have a closed class and 2 factories function
> 
> class Data:
>   def __init__(self):
>     self.payload=None
> 
> def data_from_string(payload):
>   data=Data()
>   data.payload=payload
>   return data
> 
> def data_from_file(f):
>   data=Data()
>   data.payload=f.read()
>   return data
> 
> And I want to extend the class, by first including the factories
> function inside the constructor,
> second add some method to the class.
> 
> class MyData(Data):
> 
>   def __init__(self, arg):
>     # I know this coke is not working, this is to show you
>     # what I expect
>     if isinstance(arg, file):
>         self=data_from_file(arg)
>     else:
>         self=data_from_string(arg)
>     return self
> 
>   def len(self):
>     return len(self.payload)
> 
> And how I want to use it
> 
>>>> m=MyData('hello')
>>>> print m.len()
> 5
> 
> any idea ?

Assuming that Data is an oldstyle class you can either copy the Data 
instance's state

class MyData(Data):
    def __init__(self, arg):
        if hasattr(arg, "read"):
            factory = data_from_file
        else:
            factory = data_from_string
        obj = factory(arg)
        self.__dict__.update(obj.__dict__)

    def __len__(self):
        return len(self.payload)

or use another factory function and manually set the __class__:

class MyData(Data):
    def __len__(self):
        return len(self.payload)

def make_mydata(arg):
    if hasattr(arg, "read"):
        factory = data_from_file
    else:
        factory = data_from_string
    obj = factory(arg)
    obj.__class__ = MyData
    return obj

If Data were a newstyle class you could move the hand-made polymorphism into 
the __new__() method:

class MyData(Data):
    def __new__(class_, arg):
        if hasattr(arg, "read"):
            factory = data_from_file
        else:
            factory = data_from_string
        obj = factory(arg)
        obj.__class__ = class_
        return obj
    def __init__(self, arg):
        pass
    def __len__(self):
        return len(self.payload)

if __name__ == "__main__":
    m = MyData("hello")
    print len(m)


Nothing of the above strikes me as pretty. Perhaps we could come up with a 
neater solution if you tell us more about your use-case...



More information about the Python-list mailing list