8-Bit Borges
8-Bit Borges

Reputation: 10043

Python class - chaining instance methods

I've started to build my class in this fashion (more like a regular function):

ex 1

  class Child(Parent):

    def __init__(self,user):
        Parent.__init__(self, user)     

        search = api.search() 
        filter = api.filter(search)
        output = api.output(filter)

        return output

this way I could run:

movies = Child('John')

and get my final output.

Then, I broke my global api methods into instance methods in order to have more control of data:

ex 2

  class Child(Parent):

    def __init__(self,user):
        Parent.__init__(self, user)     

    def search_api(self):
       search = api.search() 
       return search    

    def filter_api(self, search):
       filter = api.filter(search)
       return filter

    def output(self, filter):
       output = api.output(filter)  
       return output

and now I have to break it in different instances, to get the final output:

test = Child('John')
search = test.search_api()
filter = test.filter_api(search)
out = test.output(filter)

print (out)

Is there a decorator or built-in method that allows me to chain all instance methods so that ex2 can be run in one shot (instantiation)?

Upvotes: 0

Views: 323

Answers (4)

yorodm
yorodm

Reputation: 4461

No need for the magic stuff if you need to make objects behave like function calls you should implement __call__ instead of just packing everything in the constructor.:

class Child(Parent):

    def __init__(self,user):
        Parent.__init__(self, user)
        self.myuser = user


    def search_api(self):
       search = api.search() 
       return search    

    def filter_api(self, search):
       filter = api.filter()
       return filter

    def output(self, filter): 
       return output

    def __call__(self,user):
        search = self.search_api()
        filter = self.filter_api(search)
        return self.output(filter)

And now you can:

a = Child('Joe')
print(a())

Upvotes: 1

jbasko
jbasko

Reputation: 7330

I think what you are after is the builder pattern so you could write output = Search().filter().get_output() or something like that.

For this to work, you need to return the builder object from all the "intermediate" methods:

class Search(object):
    def __init__(self, *args, **kwargs):
        # apply args, kwargs

    def filter(self, *args, **kwargs):
        # apply args, kwargs
        self.filters.append(...)
        return self

    def paginate(self, *args, **kwargs):
        # apply args, kwargs
        self.pagination = ...
        return self

    def get_output(self, *args, **kwargs):
        # apply args, kwargs
        # build the search, find output ...
        return output

Upvotes: 2

steve chang
steve chang

Reputation: 54

You can use __call__(). I know it's not the same, but perhaps it might be better than your ex2:

class Child(Parent):

    def __init__(self, user):
        Parent.__init__(self, user)

    def search_api(self):
        search = api.search() 
        return search    

    def filter_api(self, search):
        filter = api.filter(search)
        return filter

    def output(self, filter):
        output = api.output(filter)  
        return output

    def __call__(self):
        search = self.search_api()
        filter = self.filter_api(search)
        return self.output(filter)

Then, you can do:

c = Child("john")
output = c()

Upvotes: 1

Mike Müller
Mike Müller

Reputation: 85612

Some helpers to make it compile:

class API:
    def __getattr__(self, attr):
        return API()
    def __call__(self, x=1):
        return 42

api = API()

class Parent(object):
     def __init__(self, user):
        self.user = user

Doing all steps in process method:

class Child(Parent):

    def __init__(self, user):
        super().__init__(user)     

    def search_api(self):
        search = api.search() 
        return search    

    def filter_api(self, search):
        filter = api.filter()
        return filter

    def output(self, filter):   
        return api.output

    def process(self):
        res = self.search_api() 
        res = self.filter_api(res)
        return self.output(res)

allows you to do all in one line:

movies = Child('John').process()

Upvotes: 1

Related Questions