Search code examples
pythondjangofunctionooppython-rq

How to present a class as a function?


As it was unclear earlier I am posting this scenario:

class Scraper:
    def __init__(self,url):
      self.start_page = url

    def parse_html(self):
      pass

    def get_all_links(self):
      pass

    def run(self):
      #parse html, get all links, parse them and when done...
      return links

Now in a task queue like rq

from rq import Queue
from worker import conn

q = Queue(connection=conn)
result = q.enqueue(what_function, 'http://stackoverflow.com')

I want to know what this what_function would be? I remembered Django does something similar with their CBVs so I used that analogy but it wasn't so clear.


I have a class like

class A:
    def run(self,arg):
        #do something

I need to past this to a task queue, so I can do something like

a = A()
b = a.run
# q is the queue object
q.enqueue(b,some_arg)

I'd want to know what other method is there to do this, for example, Django does it in their Class Based Views,

class YourListView(ListView):
    #code for your view

which is eventually passed as a function

your_view = YourListView.as_view()

How is it done?

Edit: to elaborate, django's class based views are converted to functions because the argument in the pattern function expects a function. Similarly, you might have a function which accepts the following argument

task_queue(callback_function, *parameters):
    #add to queue and return result when done

but the functionality of callback_function might have been mostly implemented in a class, which has a run() method via which the process is ran.


Solution

  • I think you're describing a classmethod:

    class MyClass(object):
        @classmethod
        def as_view(cls):
            '''method intended to be called on the class, not an instance'''
            return cls(instantiation, args)
    

    which could be used like this:

    call_later = MyClass.as_view
    

    and later called:

    call_later()
    

    Most frequently, class methods are used to instantiate a new instance, for example, dict's fromkeys classmethod:

    dict.fromkeys(['foo', 'bar'])
    

    returns a new dict instance:

    {'foo': None, 'bar': None}
    

    Update

    In your example,

    result = q.enqueue(what_function, 'http://stackoverflow.com')
    

    you want to know what_function could go there. I saw a very similar example from the RQ home page. That's got to be your own implementation. It's going to be something you can call with your code. It's only going to be called with that argument once, so if using a class, your __init__ should look more like this, if you want to use Scraper for your what_function replacement:

    class Scraper:
        def __init__(self,url):
            self.start_page = url
            self.run()
            # etc...
    

    If you want to use a class method, that might look like this:

    class Scraper:
        def __init__(self,url):
            self.start_page = url
    
        def parse_html(self):
            pass
    
        def get_all_links(self):
            pass
    
        @classmethod
        def run(cls, url):
            instance = cls(url)
            #parse html, get all links, parse them and when done...
            return links
    

    And then your what_function would be Scraper.run.