Jon Phillips
Jon Phillips

Reputation: 21

Method __init__ has too many parameters

I'm super new to Python (I started about 3 weeks ago), and I'm trying to make a script that scrapes web pages for information. After it's retrieved the information, it runs through a function to format it and then passes it to a class that takes 17 variables as parameters. The class uses this information to calculate some other variables and currently has a method to construct a dictionary. The code works as intended, but a plugin I'm using with Pycharm called SonarLint highlights that 17 variables is too many to use as parameters.

I've had a look for alternate ways to pass the information to the class, such as in a tuple or a list but couldn't find much information that seemed relevant. What's the best practice for passing many variables to a class as parameters? Or shouldn't I be using a class for this kind of thing at all?

I've reduced the amount of variables and code for legibility, but here is the class:

Class GenericEvent:

    def __init__(self, type, date_scraped, date_of_event, time, link, 
                 blurb):

      countdown_delta = date_of_event - date_scraped
      countdown = countdown_delta.days

      if countdown < 0:
          has_passed = True
      else:
          has_passed = False

      self.type = type
      self.date_scraped = date_scraped
      self.date_of_event = date_of_event
      self.time = time
      self.link = link
      self.countdown = countdown
      self.has_passed = has_passed
      self.blurb = blurb

    def get_dictionary(self):

      event_dict = {}
      event_dict['type'] = self.type
      event_dict['scraped'] = self.date_scraped
      event_dict['date'] = self.date_of_event
      event_dict['time'] = self.time
      event_dict['url'] = self.link
      event_dict['countdown'] = self.countdown
      event_dict['blurb'] = self.blurb
      event_dict['has_passed'] = self.has_passed

      return event_dict

I've been passing the variables as key:value pairs to the class after I've cleaned up the data the following way:

event_info = GenericEvent(type="Lunar"
                          date_scraped=30/01/19
                          date_of_event=28/07/19
                          time=12:00
                          link="www.someurl.com"
                          blurb="Some string.")

and retrieving a dictionary by calling:

event_info.get_dictionary()

I intend to add other methods to the class to be able to perform other operations too (not just to create 1 dictionary) but would like to resolve this before I extend the functionality of the class.

Any help or links would be much appreciated.

Upvotes: 2

Views: 2448

Answers (2)

CryptoFool
CryptoFool

Reputation: 23129

I don't think there's anything wrong with what you're doing. You could, however, take your parameters in as a single dict object, and then deal with them by iterating over the dict or doing something explicitly with each one. Seems like that would, in your case, make your code messier.

Since all of your parameters to your constructor are named parameters, you could just do this:

def __init__(self, **params):

This would give you a dict named params that you could then process. The keys would be your parameter names, and the values the parameter values.

If you aligned your param names with what you want the keys to be in your get_dictionary method's return value, saving off this parameter as a whole could make that method trivial to write.

Here's an abbreviated version of your code (with a few syntax errors fixed) that illustrates this idea:

from pprint import pprint

class GenericEvent:

    def __init__(self, **params):
        pprint(params)

event_info = GenericEvent(type="Lunar",
                          date_scraped="30/01/19",
                          date_of_event="28/07/19",
                          time="12:00",
                          link="www.someurl.com",
                          blurb="Some string.")

Result:

{'blurb': 'Some string.',
 'date_of_event': '28/07/19',
 'date_scraped': '30/01/19',
 'link': 'www.someurl.com',
 'time': '12:00',
 'type': 'Lunar'}

Upvotes: 0

Ry-
Ry-

Reputation: 225203

One option is a named tuple:

from typing import Any, NamedTuple


class GenericEvent(NamedTuple):
    type: Any
    date_scraped: Any
    date_of_event: Any
    time: Any
    link: str
    countdown: Any
    blurb: str

    @property
    def countdown(self):
        countdown_delta = date_of_event - date_scraped
        return countdown_delta.days

    @property
    def has_passed(self):
        return self.countdown < 0

    def get_dictionary(self):
        return {
            **self._asdict(),
            'countdown': self.countdown,
            'has_passed': self.has_passed,
        }

(Replace the Anys with the fields’ actual types, e.g. datetime.datetime.)

Or, if you want it to be mutable, a data class.

Upvotes: 3

Related Questions