Python Object-Oriented Python Dice Roller Giving a Hand

Akshaan Mazumdar
Akshaan Mazumdar
2,356 Points

How does self.sort() work??? how does self.sort automatically sort on the basis of class.values and not anything else?

self.sort() should technically sort objects in a list , but when objects become classes , how does it sort on the basis of values ?

Does it have something to do with int or repr? does self.sort pull values from int? A bit confused here :/

2 Answers

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 23,731 Points

That is a good question. What Kenneth is demonstrating is that since the class he built has "list" as its parent, it benefits from being able to perform list operations without explicitly being programmed. No explicit repr is needed since it behaves like a list. It inherits the list methods: append(), extend(), insert(), remove(), pop(), clear(), index(), count(), sort(), reverse(), copy() as well as some of the primitive type operators.

In the example below, I create a new class called SpiderClass -- in homage to Stan Lee's superhero Spider Man.

:-)

Uncle Ben says... "with great (Pythonic) power there must also come great (Pythonic) responsibility"

SpiderClass, SpiderClass, does whatever its parent class can. Spins a web, can append, and sort. pop and push without retort.

Can it swing from a thread? Take a look at the CPU overhead. Look out! Here comes the SpiderClass!

class SpiderClass(list):
    def spins_web(self):
        print("Gotcha with my web!")

x = SpiderClass() # instantiate-- e.g. bitten by a radioactive spider

x.spins_web()
x.append(3.14)
x.append(2.718)
x.append(0)
x.append(42)
print(len(x))
print(x)

x.sort()
print(x)

Output.

Gotcha with my web!
4
[3.14, 2.718, 0, 42]
[0, 2.718, 3.14, 42]
Akshaan Mazumdar
Akshaan Mazumdar
2,356 Points

Thanks ! this was perhaps the only answer I could sing along to :D !

Akshaan Mazumdar
Akshaan Mazumdar
2,356 Points

There is still one thing sir which I did not understand. In the video example , the "objects" in the list are "class instances" .

So, when we are using sort() on class instances on what basis are they being sorted ? I mean why isn't "side"
(which is =6 ) being considered as a parameter for sort to sort the "class instances "?

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 23,731 Points

Yes... that is a good question! The items that are stored (via append(), extend(), insert(), or element assignment will keep their type.

Here I rewrite the class with a new method called item_value_types(), a repr(), and an init()

class SpiderClass(list):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return self.name # this allows PRINT to access the name

    def spins_web(self):
        print("Gotcha with my web!")

    def item_value_types(self):
        print("Item values/types {} is holding".format(self.name))
        for i in range(0, len(self)):
            print("item {}: {} {}".format(i, self[i], type(self[i])))


spider_man = SpiderClass('Peter Parker') # instantiate our object

spider_woman = SpiderClass('Spider Woman') # instantiate the radioactive spider at work

spider_man.append(22) # int
spider_man.append("Green Goblin") # string
spider_man.append("Doctor Octopus") # string
spider_man.append("Electro") # string
spider_man.append(spider_woman) # object

spider_man.item_value_types()

spider_man.sort() # this throws an error if different types are present

Here is the output. Notice the type going in, is the type going out. When we try to sort() an error will be thrown by Python since we inherited the sort of list, which does not have a way to sort diverse types.

Item values/types Peter Parker is holding
item 0: 22 <class 'int'>
item 1: Green Goblin <class 'str'>
item 2: Doctor Octopus <class 'str'>
item 3: Electro <class 'str'>
item 4: Spider Woman <class '__main__.SpiderClass'>

ERROR: line 29, in <module> spider_man.sort() # this throws an error if different types are present
TypeError: '<' not supported between instances of 'str' and 'int'

Here is another example... suppose we create a new class called 'ArchEnemy'. It is the same as the spider class and inherits all methods/data. And this time, we put ONLY objects into the spider_man list

class ArchEnemy(SpiderClass):
    # this class inherits all the SpiderClass methods/data
    pass

spider_man = SpiderClass('Peter Parker') # instantiate our object

spider_woman = SpiderClass('Spider Woman') # instantiate the radioactive spider at work

spider_man.append(ArchEnemy("Green Goblin")) # object
spider_man.append(ArchEnemy("Doctor Octopus")) # object
spider_man.append(ArchEnemy("Electro")) # object
spider_man.append(spider_woman) # object

print("--BEFORE SORT--")
spider_man.item_value_types()

print()
spider_man.sort() # this throws an error if different types are present
print("--AFTER SORT--")
spider_man.item_value_types()
--BEFORE SORT--
Item values/types Peter Parker is holding
item 0: Green Goblin <class '__main__.ArchEnemy'>
item 1: Doctor Octopus <class '__main__.ArchEnemy'>
item 2: Electro <class '__main__.ArchEnemy'>
item 3: Spider Woman <class '__main__.SpiderClass'>

--AFTER SORT--
Item values/types Peter Parker is holding
item 0: Green Goblin <class '__main__.ArchEnemy'>
item 1: Doctor Octopus <class '__main__.ArchEnemy'>
item 2: Electro <class '__main__.ArchEnemy'>
item 3: Spider Woman <class '__main__.SpiderClass'>

Notice nothing changes after sort() is performed. If we want sort to work, we can write our own sort or include comparison operations into our objects. The comparison operations could depend on repr() or whatever else we decide -- it is up to the develper to make a choice on implementation.

Let's fix that. All we need to do is create an operator method for the SpiderClass that goes with "less than". This will allow comparison operations based on the "name" data.

class SpiderClass(list):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return self.name # this allows PRINT to access the name

    def spins_web(self):
        print("Gotcha with my web!")

    def item_value_types(self):
        print("Item values/types {} is holding".format(self.name))
        for i in range(0, len(self)):
            print("item {}: {} {}".format(i, self[i], type(self[i])))

    def __lt__(self, cls):
        if self.name < cls.name:
            return True
        else:
            return False


class ArchEnemy(SpiderClass):
    # this class inherits all the SpiderClass methods/data
    pass

spider_man = SpiderClass('Peter Parker') # instantiate our object

spider_woman = SpiderClass('Spider Woman') # instantiate the radioactive spider at work

spider_man.append(ArchEnemy("Green Goblin")) # object
spider_man.append(ArchEnemy("Doctor Octopus")) # object
spider_man.append(ArchEnemy("Electro")) # object
spider_man.append(spider_woman) # object

print("--BEFORE SORT--")
spider_man.item_value_types()

print()
spider_man.sort() # this throws an error if different types are present
print("--AFTER SORT--")
spider_man.item_value_types()

Since we included the less than operation, you can see it can now sort alphabetically ascending by the name.

--BEFORE SORT--
Item values/types Peter Parker is holding
item 0: Green Goblin <class '__main__.ArchEnemy'>
item 1: Doctor Octopus <class '__main__.ArchEnemy'>
item 2: Electro <class '__main__.ArchEnemy'>
item 3: Spider Woman <class '__main__.SpiderClass'>

--AFTER SORT--
Item values/types Peter Parker is holding
item 0: Doctor Octopus <class '__main__.ArchEnemy'>
item 1: Electro <class '__main__.ArchEnemy'>
item 2: Green Goblin <class '__main__.ArchEnemy'>
item 3: Spider Woman <class '__main__.SpiderClass'>

I hope this helps your understanding! It is pretty impressive that we can so easily create new classes based on a parent and get all the benefits.

Akshaan Mazumdar
Akshaan Mazumdar
2,356 Points

Got it !. there is a lot going on behind the scenes in python !, perhaps this bit got missed out in the video.

Thank you for the great reply !

Spider-man will feel good if he reads this :)