Search code examples
pythonclassstatic-methodsfactory-pattern

How to dynamically choose subclass from inherited class while defining global methods


This is my first real foray into Python classes, so please excuse any misuse of terms.

I'm trying to use the Factory Pattern approach to choosing a subclass dynamically, based on a URL provided by the user. Here's the setup I have:

import requests
from bs4 import BeautifulSoup as BS

class Templates(object):
    def __init__(self, url):
        self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0'}
        self.url = url

    def url(self):
        return self.url

    def response(self):
        return self.response

    def text(self):
        return self.text

    def dom(self):
        return self.dom

    @staticmethod
    def get_template(url):
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0'}
        response = requests.get(url, headers=headers)
        text = response.text
        if 'Website by Dealer.com' in text:
            return Dealer(url)
        else:
            return None

class Dealer(Templates):
    def __init__(self, url):
        Templates.__init__(self, url)
        self.new_vehicle_url = "{}/new-inventory/index.htm".format(self.url.rstrip('/'))
        self.used_vehicle_url = "{}/used-inventory/index.htm".format(self.url.rstrip('/'))

What I want to be able to do is call Templates.get_template(url) and have it return the appropriate subclass. This question made it look really easy, but I'm missing something in the process because I also want to define general methods in my Templates class, which requires me to pass url to Template.

What is the Pythonic way of setting this up such that the following code will work?

template = Templates().get_template(url) # assume returns Dealer()
template.url
# 'http://www.some-website.com'
template.response.status_code
# 200

Solution

  • In your code you use Templates() but that actually tries to create an instance of Templates - which fails because it's missing the url parameter for in Templates.__init__.

    But you don't need an instance to call a staticmethod:

    template = Templates.get_template(url) # assume returns Dealer()
    template.url
    # 'http://www.some-website.com'
    template.response.status_code
    # 200
    

    I just removed the () after Templates there.