0

I have a Python dict that has keys as credit ratings, and the values are lists of integers for credit scores:

class Account:
    credit_score_dict = {
        'Excellent': [*range(830, 900)],
        'Good': [*range(750, 830)],
        'Decent': [*range(670, 750)],
        'Bad': [*range(0, 670)],
    }

    def __init__(self, account_number, credit_score=None):
        self.account_number = account_number
        self.credit_score = credit_score
        self.credit_rating = None

    def get_credit_rating(self, credit_score):
        self.credit_score = credit_score
        for rating, score in self.credit_score_dict.items():
            if score == credit_score:
                self.credit_rating = self.credit_score_dict[rating]

I am having trouble assigning the credit rating (key) to the object using the credit score (value) that is passed to the get_credit_rating method. There may be an easier or more efficient way to do this. Any advice is appreciated!

NUSav77
  • 62
  • 6
  • 2
    You want `if credit_score in score:` – Barmar Jun 11 '21 at 18:56
  • 1
    And then `self.credit_rating = rating` – Barmar Jun 11 '21 at 18:59
  • Could also `if score < 670: return 'Bad' elif score < 750: return 'Decent'...` etc – Cory Kramer Jun 11 '21 at 18:59
  • 1
    It would be better to just store the `range` objects into the dictionary instead of converting them to lists. – Barmar Jun 11 '21 at 18:59
  • 2
    Note that a `dict` that you only use to look up keys via their values is kinda useless; value lookups are `O(n)` instead of `O(1)`. You might want to make an inverted version of your `dict`, e.g. `score_to_rating = {score: rating for rating, scores in credit_score_dict.items() for score in scores}` up front, so you can replace the entire `for` loop with `self.credit_rating = self.score_to_rating[credit_score]` and operate *significantly* more efficiently (at the expense of the moderately large `dict` for lookup). – ShadowRanger Jun 11 '21 at 19:01
  • @Barmar: Yeah, if they don't make the inverted `dict`, using raw `range`s would at least make it `O(n)` where `n` is the number of ratings (4) and have minimal memory requirements, rather than `O(n)`, where `n` is the number of individual possible scores (900). – ShadowRanger Jun 11 '21 at 19:02
  • @ShadowRanger given that their original dict is unnecessarily large, I doubt they'll be deterred by the size of the reverse dictionary. – Mark Ransom Jun 11 '21 at 19:05
  • @ShadowRanger although since the reverse dictionary will be indexed by relatively small and unique integers, a `list` might work better. – Mark Ransom Jun 11 '21 at 19:07
  • 1
    @MarkRansom: True; not just small and unique, but 0-based as well, so no empty indices or index adjustment required at all. `('Bad',) * 670 + ('Decent',) * (750 - 670) + ...etc....` (using `tuple` instead of `list` on assumption it's logically immutable and we may as well save a tiny bit of memory and reduce memory fragmentation). – ShadowRanger Jun 11 '21 at 19:09
  • @ShadowRanger - I had initially used this method, however, I kept getting an error "KeyError: 123" when trying to pass credit score of 123. – NUSav77 Jun 11 '21 at 19:19
  • Thank you all for this advice. I am learning a lot about efficient coding and your comments are very helpful. I plan to try it a few different ways, then use pytest to test the runtime of each. Once I get a few different methods working, I will keep you all posted with results. – NUSav77 Jun 11 '21 at 19:22
  • 1
    @NUSav77: I'm guessing a type mismatch, like the inputs being `str` from a user or file, not `int`. The inverted `dict` will work, if initialized properly. – ShadowRanger Jun 11 '21 at 20:08

0 Answers0