An invisible method! (A polymorphic aside)
Our code in playing_cards_1.py
is even runnable. Although it doesn't
do much, the output is instructive:
>>>
d after shuffling = <__main__.Deck object at 0x000002C52FF39010>
d has None cards
Your hand of None cards contains: <__main__.Hand object at 0x000002C52CF18AD0>
Your hand of None cards contains: <__main__.Hand object at 0x000002C52FF67950>
There are None cards left in the deck.
>>>
One thing to note is that functions without an
explicit return
statement, like all of ours here, return the special
value None
.
The more striking thing though is probably those inscrutable
strings <__main__.Deck instance at 0x000002C52FF39010>
and <__main__.Hand instance at 0x000002C52CF18AD0>
.
You can tell by where they appear that they are generated by
the print
statements. Since print doesn't know how to
output Deck
and Hand
objects it tells us what it can, which is the
type and memory location of the object it has been asked to print.
We can help print
out by providing methods that return string
representations of our Deck
and Hand
objects. By convention these
methods are called __str__
. When print
is called and passed an
object name it checks the object's class definition for
an __str__
method and if one is defined it calls it and displays the
output the method returns. If no __str__
method is found it displays
all it can, i.e. the object type and location as it did above.
This nicely illustrates the simple sleight of hand that lies behind
polymorphism. Until now it seemed that print
knew how to print
everything, but in fact it knows very little and just delegates the job
to each class' __str__
method while giving the impression that it is
masterful.