Garth5689
Garth5689

Reputation: 622

How do I handle partially initialized classes

My question concerns a class that I am writing that may or may not be fully initialized. The basic goal is to take a match_id and open the corresponding match_url (example: http://dota2lounge.com/match?m=1899) and then grab some properties out of the webpage. The problem is some match_ids will result in 404 pages (http://dota2lounge.com/404).

When this happens, there won't be a way to determine the winner of the match, so the rest of the Match can't be initialized. I have seen this causing problems with methods of the Match, so I added the lines to initialize everything to None if self._valid_url is False. This works in principal, but then I'm adding a line each time a new attribute is added, and it seems prone to errors down the pipeline (in methods, etc.) It also doesn't alert the user that this class wasn't properly initialized. They would need to call .is_valid_match() to determine that.

tl;dr: What is the best way to handle classes that may be only partially initiated? Since this is a hobby project and I'm looking to learn, I'm open to pretty much any solutions (trying new things), including other classes or whatever. Thanks.

This is an abbreviated version of the code containing the relevant portions (Python 3.3):

from urllib.request import urlopen
from bs4 import BeautifulSoup


class Match(object):
    def __init__(self, match_id):
        self.match_id = match_id
        self.match_url = self.__determine_match_url__()
        self._soup = self.__get_match_soup__()
        self._valid_match_url = self.__determine_match_404__()
        if self._valid_match_url:
            self.teams, self.winner = self.__get_teams_and_winner__()

        # These lines were added, but I'm not sure if this is correct.
        else:
            self.teams, self.winner = None, None

    def __determine_match_url__(self):
        return 'http://dota2lounge.com/match?m=' + str(self.match_id)

    def __get_match_soup__(self):
        return BeautifulSoup(urlopen(self.match_url))

    def __get_match_details__(self):
        return self._soup.find('section', {'class': 'box'})

    def __determine_match_404__(self):
        try:
            if self._soup.find('h1').text == '404':
                return False
        except AttributeError:
            return True

    def __get_teams_and_winner__(self):
        teams = [team.getText() for team in
                 self._soup.find('section', {'class': 'box'}).findAll('b')]
        winner = False
        for number, team in enumerate(teams):
            if ' (win)' in team:
                teams[number] = teams[number].replace(' (win)', '')
                winner = teams[number]

        return teams, winner

    def is_valid_match(self):
        return all([self._valid_match_url, self.winner])

Upvotes: 1

Views: 343

Answers (1)

mhlester
mhlester

Reputation: 23211

I would raise an exception, handle that in your creation code (wherever you call some_match = Match(match_id)), and probably don't add it to whatever list you may or may not be using...

For a better answer, you might want to include in your question the code that instantiates all your Match objects.

Upvotes: 4

Related Questions