Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use an object method with the Initializer (Same line)

I'm cleaning up a python object class, focusing mainly on how the object is created. The __init__ method creates a an empty dictionary that needs to be filled almost instantly. But this should NOT happen within the __init__, as the method used will vary widely. Here's an example:

class Storage:

    def __init__(self):
        self.data = {}

    def fill_1(self):
        self.data['solo'] = 'all alone'

    def fill_2(self, buddy, bff):
        self.data['buddy'] = buddy
        self.data['bff'] = bff

    def fill_3(self, that_guy, house):
        self.data[that_guy] = house

Normally, I can just call one after the other like so:

box = Storage.Storage()
box.fill_1()

However, this can be overwhelming when I create many of these objects sequentially. My goal is to use the __init__ method with one of the fill methods on the same line. I've tried using the call below:

box = Storage.Storage().fill_1()

But this does not create the object and instead returns None. So I have two questions:

Is my code returning a None object because the line is calling an instance method?

And how can I create the Storage object and then call it's fill method within the same line?

like image 389
Python Cheese Avatar asked Apr 07 '16 18:04

Python Cheese


2 Answers

This is not an idiom you tend to see that often in python (though it's quite prevalent in many other languages, especially javascript), but you could do this by returning self from the mutator functions. (It looks like you were missing the self argument to the instance methods as well). This means you could also chain mutator calls -- Storage().fill_1().fill_2()

class Storage(object):

    def __init__(self):
        super(Storage, self).__init__()
        data = {}

    def fill_1(self):
        data['solo'] = 'all alone'
        return self

    def fill_2(self, buddy, bff):
        data['buddy'] = buddy
        data['bff'] = bff
        return self

    def fill_3(self, that_guy, house):
        data[that_guy] = house
        return self

box = Storage().fill_1()
like image 142
Brendan Abel Avatar answered Sep 22 '22 17:09

Brendan Abel


Make alternate constructors:

class Storage(object):

    def __init__(self):
        self.data = {}

    @staticmethod
    def filled_1():
        obj = Storage()
        obj.data['solo'] = 'all alone'
        return obj

    @staticmethod
    def filled_2(self, buddy, bff):
        obj = Storage()
        obj.data['buddy'] = buddy
        obj.data['bff'] = bff
        return obj

    @staticmethod
    def filled_3(self, that_guy, house):
        obj = Storage()
        obj.data[that_guy] = house
        return obj

Then you don't need to worry about separate creation and initialization calls, or muddle command-query separation with call chaining:

obj1 = Storage.filled_1()
obj2 = Storage.filled_2('Jenny', 'Joe')
...
like image 36
user2357112 supports Monica Avatar answered Sep 22 '22 17:09

user2357112 supports Monica