3

I have a class players which have their name and experience as private attributes. I have 2 functions that returns each of them.

class Player:
    def __init__(self,name,experience):
        self.__name=name
        self.__experience=experience

    def get_name(self):
        return self.__name

    def get_experience(self):
        return self.__experience

    def __str__(self):
        return(self.__name + " " + str(self.__experience))

I created a game class that gets a list of players and it has a function that sorts the players based on their experience.

class Game:
    def __init__(self, players_list):
        self.players_list=players_list
        
    def sort_players_based_on_exp(self):
        # I don't know how to sort them

I know that the sort() method has a parameter key, but I don't know how to use that in this case.

2 Answers 2

3

The sort and sorted methods can take a callable of a single argument as a key function, and will sort on the results of it. So you need a callable that returns the attribute you want to sort on, given a Player instance. In this case, that's your accessor method.

def sort_players_based_on_exp(self):
    return sorted(self.players_list, key=Player.get_experience)

When sorting on an attribute, the operator module has useful methods that are faster than a lambda to resolve an attribute key, but as noted in comments you don't need them here. See the "Sorting HOW TO" docs for some more examples and explanation.

As a side note - in general Python doesn't bother with obfuscating attributes and using getters and setters. The Python idiom would be to just have experience present as an attribute on the class. If you need to change the behavior later, you can replace bare attribute access by something functional with the @property decorator while maintaining the access syntax.

Sign up to request clarification or add additional context in comments.

5 Comments

@KellyBundy. No only could but should. This answer is massive overkill
@PeterDeGlopper. That hasn't been the case since like python 2.5
Thank you, much better, and +1. Your last point is important: getters and setters are not idiomatic: properties are. operator.attrgetter('experience') would be the optimized search key here.
FWIW I still see the bound vs. unbound method distinction discussed in the 2.7.18 docs, but it's very much a moot point these days.
It's discussed because old style classes were still possible, but definitely not recommended. In new style classes (2.5+ if memory serves), and all classes in 3+, unbound methods don't exist, they're just plain function objects.
0

You can use sorted(self.players_list, key = Player.get_experience). You can also define the order relations and then you won't need to explicitly give a key.

  def __eq__(self, other):
      return self.experience() == other.experience()

  def __ge__(self, other):
      return self.experience() >= other.experience()

etc.

The latter may be overkill in this particular instance, but I thought you should be aware of the option.

4 Comments

sort/sorted needs __lt__ to be defined to work without a key
@Mark Tolonen Oh really? :-)
@KellyBundy Well, according to docs "This method sorts the list in place, using only < comparisons between items." but obviously __gt__ works too. but __eq__ and __ge__ as in this answer don't work. The error message is even "TypeError: '<' not supported between instances of 'C' and 'C'". Sorry I didn't test every combination to see if the docs were lying 😉
@Mark Tolonen I think i once pointed that lie out to Tim, forgot what he replied. Anyway, the answer does say "etc.", so that would need to not include two of the remaining four order relations in order to not suffice. Though yes, I would've explicitly included __lt__ as the first one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.