AchillesGames

Suppose Python/Inheritance – Wikibooks, open books for an open world

On this chapter we are going to develop lessons to symbolize taking part in playing cards,
decks of playing cards, and poker palms. When you don’t play poker, you possibly can
examine it at wikipedia.org/wiki/Poker, however you do not have
to; I will let you know what it’s good to know for the workouts.

In case you are not accustomed to Anglo-American taking part in playing cards,
you possibly can examine them at wikipedia.org/wiki/Playing_cards.

Card objects[edit]

There are fifty-two playing cards in a deck, every of which belongs to one in all
4 fits and one in all 13 ranks. The fits are Spades, Hearts,
Diamonds, and Golf equipment (in descending order in bridge). The ranks are
Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, and King. Relying on
the sport that you’re taking part in, an Ace could also be increased than King
or decrease than 2.

If we need to outline a brand new object to symbolize a taking part in card, it’s
apparent what the attributes must be: rank and
go well with. It isn’t as apparent what kind the attributes
must be. One chance is to make use of strings containing phrases like
'Spade' for fits and 'Queen' for ranks. One downside with
this implementation is that it will not be straightforward to check playing cards to
see which had a better rank or go well with.

An alternate is to make use of integers to encode the ranks and fits.
On this context, “encode” implies that we’re going to outline a mapping
between numbers and fits, or between numbers and ranks. This
type of encoding will not be meant to be a secret (that
can be “encryption”).

For instance, this desk exhibits the fits and the corresponding integer
codes:

Spades 3
Hearts 2
Diamonds 1
Golf equipment 0

This code makes it straightforward to check playing cards; as a result of increased fits map to
increased numbers, we will examine fits by evaluating their codes.

The mapping for ranks is pretty apparent; every of the numerical ranks
maps to the corresponding integer, and for face playing cards:

Jack 11
Queen 12
King 13

I’m utilizing the ↦ image to make it clear that these mappings
are usually not a part of the Python program. They’re a part of this system
design, however they don’t seem explicitly within the code.

The category definition for Card seems to be like this:

class Card:
    """represents a normal taking part in card."""

    def __init__(self, go well with=0, rank=2):
        self.go well with = go well with
        self.rank = rank

As ordinary, the init methodology takes an non-compulsory
parameter for every attribute. The default card is
the two of Golf equipment.

To create a Card, you name Card with the
go well with and rank of the cardboard you need.

queen_of_diamonds = Card(1, 12)

Class attributes[edit]

In an effort to print Card objects in a means that individuals can simply
learn, we’d like a mapping from the integer codes to the corresponding
ranks and fits. A pure solution to
do that’s with lists of strings. We assign these lists to class
attributes:

# inside class Card:

    suit_names = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
    rank_names = [None, 'Ace', '2', '3', '4', '5', '6', '7', 
              '8', '9', '10', 'Jack', 'Queen', 'King']

    def __str__(self):
        return '%s of %s' % (Card.rank_names[self.rank],
                             Card.suit_names[self.suit])

Variables like suit_names and rank_names, that are
outlined inside a category however outdoors of any methodology, are referred to as
class attributes as a result of they’re related to the category object
Card.

This time period distinguished them from variables like go well with and rank, that are referred to as occasion attributes as a result of they’re
related to a selected occasion.

Each sorts of attribute are accessed utilizing dot notation. For
instance, in __str__, self is a Card object,
and self.rank is its rank. Equally, Card
is a category object, and Card.rank_names is a
listing of strings related to the category.

Each card has its personal go well with and rank, however there
is just one copy of suit_names and rank_names.

Placing all of it collectively, the expression
Card.rank_names[self.rank] means “use the attribute rank
from the item self as an index into the listing rank_names
from the category Card, and choose the suitable string.”

The primary factor of rank_names is None as a result of there
isn’t any card with rank zero. By together with None as a place-keeper,
we get a mapping with the good property that the index 2 maps to the
string '2', and so forth. To keep away from this tweak, we might have
used a dictionary as an alternative of a listing.

With the strategies we’ve got to this point, we will create and print playing cards:

>>> card1 = Card(2, 11)
>>> print card1
Jack of Hearts

Here’s a diagram that exhibits the Card class object
and one Card occasion:

Card is a category object, so it has kind kind. card1 has kind Card. (To avoid wasting area, I didn’t draw the
contents of suit_names and rank_names).

Evaluating playing cards[edit]

For built-in sorts, there are conditional operators
(<, >, ==, and many others.)
that examine
values and decide when one is larger than, lower than, or equal to
one other. For user-defined sorts, we will override the habits of
the built-in operators by offering a technique named
__cmp__.

__cmp__ takes two parameters, self and different,
and returns a constructive quantity if the primary object is larger, a
unfavorable quantity if the second object is larger, and Zero if they're
equal to one another.

The proper ordering for playing cards will not be apparent.
For instance, which
is healthier, the three of Golf equipment or the two of Diamonds? One has a better
rank, however the different has a better go well with. In an effort to examine
playing cards, you must determine whether or not rank or go well with is extra vital.

The reply would possibly depend upon what recreation you're taking part in, however to maintain
issues easy, we’ll make the arbitrary selection that go well with is extra
vital, so the entire Spades outrank the entire Diamonds,
and so forth.

With that determined, we will write __cmp__:

# inside class Card:

    def __cmp__(self, different):
        # verify the fits
        if self.go well with > different.go well with: return 1
        if self.go well with < other.suit: return -1

        # suits are the same... check ranks
        if self.rank > different.rank: return 1
        if self.rank < different.rank: return -1

        # ranks are the identical... it is a tie
        return 0    

You may write this extra concisely utilizing tuple comparability:

# inside class Card:

    def __cmp__(self, different):
        t1 = self.go well with, self.rank
        t2 = different.go well with, different.rank
        return cmp(t1, t2)

The built-in operate cmp has the identical interface as
the tactic __cmp__: it takes two values and returns
a constructive quantity if the primary is bigger, a unfavorable quantity
of the second is bigger, and Zero if they're equal.

Train 1[edit]

Write a __cmp__ methodology for Time objects. Trace: you
can use tuple comparability, however you additionally would possibly think about using
integer subtraction.

Now that we've got Playing cards, the subsequent step is to outline Decks. Since a
deck is made up of playing cards, it's pure for every Deck to comprise a
listing of playing cards as an attribute.

The next is a category definition for Deck. The
init methodology creates the attribute playing cards and generates
the usual set of fifty-two playing cards:

class Deck:

    def __init__(self):
        self.playing cards = []
        for go well with in vary(4):
            for rank in vary(1, 14):
                card = Card(go well with, rank)
                self.playing cards.append(card)

The best solution to populate the deck is with a nested loop. The outer
loop enumerates the fits from Zero to three. The inside loop enumerates the
ranks from 1 to 13. Every iteration
creates a brand new Card with the present go well with and rank,
and appends it to self.playing cards.

Printing the deck[edit]

Here's a __str__ methodology for Deck:

#inside class Deck:

    def __str__(self):
        res = [str(card) for card in self.cards]
        return 'n'.be a part of(res)

This methodology demonstrates an environment friendly solution to accumulate a big
string: constructing a listing of strings after which utilizing be a part of.
The built-in operate str invokes the __str__
methodology on every card and returns the string illustration.

Since we invoke be a part of on a newline character, the playing cards
are separated by newlines. Right here’s what the end result seems to be like:

>>> deck = Deck()
>>> print deck
Ace of Golf equipment
2 of Golf equipment
Three of Golf equipment
...
10 of Spades
Jack of Spades
Queen of Spades
King of Spades

Despite the fact that the end result seems on 52 traces, it's
one lengthy string that accommodates newlines.

Add, take away, shuffle and type[edit]

To deal playing cards, we want a technique that
removes a card from the deck and returns it.
The listing methodology pop gives a handy means to do this:

#inside class Deck:

    def pop_card(self):
        return self.playing cards.pop()

Since pop removes the final card within the listing, we're
dealing from the underside of the deck. In actual life backside dealing is
frowned upon1,
however on this context it’s okay.

So as to add a card, we will use the listing methodology append:

#inside class Deck:

    def add_card(self, card):
        self.playing cards.append(card)

A technique like this that makes use of one other operate with out doing
a lot actual work is typically referred to as a veneer. The metaphor
comes from woodworking, the place it is not uncommon to connect a skinny
layer of fine high quality wooden to the floor of a less expensive piece of
wooden.

On this case we're defining a “skinny” methodology that expresses
a listing operation in phrases which are acceptable for decks.

As one other instance, we will write a Deck methodology named shuffle
utilizing the operate shuffle from the random module:

# inside class Deck:
            
    def shuffle(self):
        random.shuffle(self.playing cards)

Don’t neglect to import random.

Train 2[edit]

Write a Deck methodology named 'kind' that makes use of the listing methodology
'kind' to kind the playing cards in a 'Deck'. 'kind' makes use of
the __cmp__ methodology we outlined to find out kind order.

Inheritance[edit]

The language function most frequently related to object-oriented
programming is inheritance. Inheritance is the flexibility to
outline a brand new class that could be a modified model of an present
class.

It's referred to as “inheritance” as a result of the brand new class inherits the
strategies of the prevailing class. Extending this metaphor, the prevailing
class is named the dad or mum and the brand new class is
referred to as the little one.

For example, let’s say we wish a category to symbolize a “hand,”
that's, the set of playing cards held by one participant. A hand is just like a
deck: each are made up of a set of playing cards, and each require operations
like including and eradicating playing cards.

A hand can also be totally different from a deck; there are operations we wish for
palms that don’t make sense for a deck. For instance, in poker we
would possibly examine two palms to see which one wins. In bridge, we'd
compute a rating for a hand so as to make a bid.

This relationship between lessons—comparable, however totally different—lends
itself to inheritance.

The definition of a kid class is like different class definitions,
however the title of the dad or mum class seems in parentheses:

class Hand(Deck):
    """represents a hand of taking part in playing cards"""

This definition signifies that Hand inherits from Deck;
meaning we will use strategies like pop_card and add_card
for Arms in addition to Decks.

Hand additionally inherits __init__ from Deck, however
it doesn’t actually do what we wish: as an alternative of populating the hand
with 52 new playing cards, the init methodology for Arms ought to initialize
playing cards with an empty listing.

If we offer an init methodology within the Hand class, it overrides the
one within the Deck class:

# inside class Hand:

    def __init__(self, label=""):
        self.playing cards = []
        self.label = label

So whenever you create a Hand, Python invokes this init methodology:

>>> hand = Hand('new hand')
>>> print hand.playing cards
[]
>>> print hand.label
new hand

However the different strategies are inherited from Deck, so we will use
pop_card and add_card to deal a card:

>>> deck = Deck()
>>> card = deck.pop_card()
>>> hand.add_card(card)
>>> print hand
King of Spades

A pure subsequent step is to encapsulate this code in a technique
referred to as move_cards:

#inside class Deck:

    def move_cards(self, hand, num):
        for i in vary(num):
            hand.add_card(self.pop_card())

move_cards takes two arguments, a Hand object and the variety of
playing cards to deal. It modifies each self and hand, and
returns None.

In some video games, playing cards are moved from one hand to a different,
or from a hand again to the deck. You need to use move_cards
for any of those operations: self might be both a Deck
or a Hand, and hand, regardless of the title, can be a Deck.

Train 3  

Write a Deck methodology referred to as deal_hands that takes two
parameters, the variety of palms and the variety of playing cards per
hand, and that creates new Hand objects, offers the suitable
variety of playing cards per hand, and returns a listing of Hand objects.

Inheritance is a helpful function. Some packages that might be
repetitive with out inheritance might be written extra elegantly
with it. Inheritance can facilitate code reuse, since you possibly can
customise the habits of dad or mum lessons with out having to switch
them. In some circumstances, the inheritance construction displays the pure
construction of the issue, which makes this system simpler to
perceive.

Then again, inheritance could make packages troublesome to learn.
When a technique is invoked, it's typically not clear the place to seek out its
definition. The related code could also be scattered amongst a number of modules.
Additionally, most of the issues that may be completed utilizing inheritance might be
completed as effectively or higher with out it.

Class diagrams[edit]

Up to now we've got seen stack diagrams, which present the state of
a program, and object diagrams, which present the attributes
of an object and their values. These diagrams symbolize a snapshot
within the execution of a program, so they modify as this system
runs.

They're additionally extremely detailed; for some functions, too
detailed. A category diagrams is a extra summary illustration
of the construction of a program. As a substitute of exhibiting particular person
objects, it exhibits lessons and the relationships between them.

There are a number of sorts of relationship between lessons:

  • Objects in a single class would possibly comprise references to things in one other class. For instance, every Rectangle accommodates a reference to a Level, and every Deck accommodates references to many Playing cards. This type of relationship is named HAS-A, as in, “a Rectangle has a Level.”
  • One class would possibly inherit from one other. This relationship is named IS-A, as in, “a Hand is a type of a Deck.”
  • One class would possibly depend upon one other within the sense that modifications in a single class would require modifications within the different.

A class diagram is a graphical illustration of those
relationships2. For instance, this diagram exhibits the
relationships between Card, Deck and Hand.

The arrow with a hole triangle head represents an IS-A
relationship; on this case it signifies that Hand inherits
from Deck.

The usual arrow head represents a HAS-A
relationship; on this case a Deck has references to Card
objects.

The star (*) close to the arrow head is a
multiplicity; it signifies what number of Playing cards a Deck has.
A multiplicity is usually a easy quantity, like 52, a spread,
like 5..7 or a star, which signifies {that a} Deck can
have any variety of Playing cards.

A extra detailed diagram would possibly present {that a} Deck really
accommodates a listing of Playing cards, however built-in sorts
like listing and dict are normally not included in school diagrams.

Train 4[edit]

Learn 'TurtleWorld.py', 'World.py' and 'Gui.py'
and draw a category diagram that exhibits the relationships amongst
the lessons outlined there.

Debugging[edit]

Inheritance could make debugging a problem as a result of whenever you
invoke a technique on an object, you may not know which methodology
can be invoked.

Suppose you're writing a operate that works with Hand objects.
You want to it to work with all types of Arms, like
PokerHands, BridgeHands, and many others. When you invoke a technique like
shuffle, you would possibly get the one outlined in Deck,
but when any of the subclasses override this methodology, you’ll
get that model as an alternative.

Any time you're not sure concerning the stream of execution by way of your
program, the only answer is so as to add print statements on the
starting of the related strategies. If Deck.shuffle prints a
message that claims one thing like Operating Deck.shuffle, then as
this system runs it traces the stream of execution.

As a substitute, you could possibly use this operate, which takes an
object and a technique title (as a string) and returns the category that
gives the definition of the tactic:

def find_defining_class(obj, meth_name):
    for ty in kind(obj).mro():
        if meth_name in ty.__dict__:
            return ty

Right here’s an instance:

>>> hand = Hand()
>>> print find_defining_class(hand, 'shuffle')

So the shuffle methodology for this Hand is the one in Deck.

find_defining_class makes use of the mro methodology to get the listing
of sophistication objects (sorts) that can be looked for strategies. “MRO”
stands for “methodology decision order.”

Right here’s a program design suggestion: everytime you override a technique,
the interface of the brand new methodology must be the identical because the outdated. It
ought to take the identical parameters, return the identical kind, and obey the
identical preconditions and postconditions. When you obey this rule, you
will discover that any operate designed to work with an occasion of a
superclass, like a Deck, can even work with cases of subclasses
like a Hand or PokerHand.

When you violate this rule, your code will collapse like (sorry)
a home of playing cards.

Glossary[edit]

encode:
To symbolize one set of values utilizing one other
set of values by developing a mapping between them.
class attribute:
An attribute related to a category
object. Class attributes are outlined inside
a category definition however outdoors any methodology.

occasion attribute:
An attribute related to an
occasion of a category.

veneer:
A technique or operate that gives a special
interface to a different operate with out doing a lot computation.
inheritance:
The power to outline a brand new class that could be a
modified model of a beforehand outlined class.
dad or mum class:
The category from which a baby class inherits.
little one class:
A brand new class created by inheriting from an
present class; additionally referred to as a “subclass.”
IS-A relationship:
The connection between a baby class
and its dad or mum class.
HAS-A relationship:
The connection between two lessons
the place cases of 1 class comprise references to cases of
the opposite.
class diagram:
A diagram that exhibits the lessons in a program
and the relationships between them.

multiplicity:
A notation in a category diagram that exhibits, for
a HAS-A relationship, what number of references there are to cases
of one other class.

Workout routines[edit]

Train 5[edit]

The next are the potential palms in poker, in growing order
of worth (and reducing order of chance):

pair:
two playing cards with the identical rank
''two pair:''
two pairs of playing cards with the identical rank
''three of a form:''
three playing cards with the identical rank
''straight:''
5 playing cards with ranks in sequence (aces can
be excessive or low, so 'Ace-2-3-4-5' is a straight and so is '10-Jack-Queen-King-Ace', however 'Queen-King-Ace-2-3' will not be.)
''flush:''
5 playing cards with the identical go well with
''full home:''
three playing cards with one rank, two playing cards with one other
''4 of a form:''
4 playing cards with the identical rank
''straight flush:''
5 playing cards in sequence (as outlined above) and
with the identical go well with


The objective of those workouts is to estimate
the chance of drawing these numerous palms.

  • Obtain the next recordsdata from 'thinkpython.com/code':
    Card.py
    : A whole model of the 'Card', 'Deck' and 'Hand' lessons on this chapter.
    ''PokerHand.py''
    : An incomplete implementation of a category

that represents a poker hand, and a few code that assessments it.

  • 'When you run '''PokerHand.py''', it offers six 7-card poker palms

and checks to see if any of them accommodates a flush. Learn this
code rigorously earlier than you go on.'

  • 'Add strategies to '''PokerHand.py''' named ''has_pair'',

''has_twopair'', and many others. that return True or False in accordance with
whether or not or not the hand meets the related standards. Your code ought to
work appropriately for “palms” that comprise any variety of playing cards
(though 5 and seven are the most typical sizes).'

  • 'Write a technique named '''classify''' that figures out

the highest-value classification for a hand and units the
'''label''' attribute accordingly. For instance, a 7-card hand
would possibly comprise a flush and a pair; it must be labeled “flush”.'

  • 'When you find yourself satisfied that your classification strategies are

working, the subsequent step is to estimate the chances of the assorted
palms. Write a operate in '''PokerHand.py''' that shuffles a deck of
playing cards, divides it into palms, classifies the palms, and counts the
variety of occasions numerous classifications seem.'

  • 'Print a desk of the classifications and their chances.

Run your program with bigger and bigger numbers of palms till the
output values converge to an inexpensive diploma of accuracy. Examine
your outcomes to the values at '''wikipedia.org/wiki/Hand_rankings'''.'

Train 6[edit]

This train makes use of TurtleWorld from Chapter '4'.
You'll write code that makes Turtles play tag. When you
are usually not accustomed to the foundations of tag, see
'wikipedia.org/wiki/Tag_(recreation)'.

  • Obtain 'thinkpython.com/code/Wobbler.py' and run it. You

ought to see a TurtleWorld with three Turtles. When you press the
'Run' button, the Turtles wander at random.

  • Learn the code and be sure to perceive the way it works.

The 'Wobbler' class inherits from 'Turtle', which implies
that the 'Turtle' strategies 'lt', 'rt', 'fd'
and 'bk' work on Wobblers.
The 'step' methodology will get invoked by TurtleWorld. It invokes
'steer', which turns the Turtle within the desired route,
'wobble', which makes a random flip in proportion to the Turtle’s
clumsiness, and 'transfer', which strikes ahead just a few pixels,
relying on the Turtle’s velocity.

  • Create a file named 'Tagger.py'. Import every thing from

'Wobbler', then outline a category named 'Tagger' that inherits
from 'Wobbler'. Name make_world passing the 'Tagger' class object as an argument.

  • Add a 'steer' methodology to 'Tagger' to override the one in

'Wobbler'. As a beginning place, write a model that at all times
factors the Turtle towards the origin. Trace: use the mathematics operate
'atan2' and the Turtle attributes 'x', 'y' and
'heading'.

  • Modify 'steer' in order that the Turtles keep in bounds.

For debugging, you would possibly need to use the 'Step' button,
which invokes 'step' as soon as on every Turtle.

  • Modify 'steer' so that every Turtle factors towards its nearest

neighbor. Trace: Turtles have an attribute, 'world', that could be a
reference to the TurtleWorld they stay in, and the TurtleWorld has
an attribute, 'animals', that could be a listing of all Turtles within the
world.

  • Modify 'steer' so the Turtles play tag. You may add strategies

to 'Tagger' and you may override 'steer' and
__init__, however you could not modify or override 'step', 'wobble' or 'transfer'. Additionally, 'steer' is allowed to alter the
heading of the Turtle however not the place.
Modify the foundations and your 'steer' methodology for good high quality play;
for instance, it must be potential for the sluggish Turtle to tag the
quicker Turtles ultimately.

You will get my answer from 'thinkpython.com/code/Tagger.py'.

Related posts

Leave a Comment