CS101 - Spring 2025
Object Construction and User Interface
Programming
Lecture 10
School of Computing, KAIST
Roadmap
Last week we learned
• Objects
- Object creation
- Object attributes
This week we will learn
• Objects
- Object methods
- Object constructors
- String conversion
• User Interface programming
CS101 Copyright (c) School of Computing, KAIST 2
Blackjack – continued
There are 52 cards.
Each card has a face and a suit.
• Suits: clubs, spades, hearts and diamonds
• Faces: Ace, 2, 3, . . . , 10, Jack, Queen, and King
class Card(object):
"""A Blackjack card."""
pass
card = Card()
card.face = "Ace"
card.suit = "Spades"
card.value = 11
CS101 Copyright (c) School*ofobject
Computing,could
KAIST be another class for Inheritance
3
"Card" inherits attributes and methods from "object"
class Card(object): class object
"""A Blackjack card.""" __doc__
pass ...
__str__()
__eq__()
By specifying "object" as shown, ...
the Card class inherits the attributes and methods
of the object class.
class Card
__doc__
This is not required in Python 3. face
• All classes in Python 3 inherit from object suit
implicitly. value
...
class Card(object): __str__()
"""A Blackjack card.""" __eq__()
pass ...
Spring 2020 CS101 Copyright (c) School of Computing, KAIST 4
Object methods
We do not really need the value attribute, since the value can be computed
from the face attribute.
So, we add a method, value(), to our Card class:
class Card(object):
"""A Blackjack card."""
method of Card
def value(self):
if type(self.face) == int:
return self.face
elif self.face == "Ace":
return 11 self refers to the object itself
else:
inside the method
return 10
CS101 Copyright (c) School of Computing, KAIST 5
self?
card1 = Card()
card1.face = "Ace"
card1.suit = "Spades"
card2 = Card()
card2.face = 2
card2.suit = "Spades"
card1.value()
def value(self):
if type(self.face) == int:
return self.face
elif self.face == "Ace":
return 11 if type(card1.face) == int:
else: return card1.face
return 10 elif card1.face == "Ace":
return 11
else:
return 10
6
The value() method works like this
>>> card1 = Card()
class Card(object):
>>> card1.face = "Ace" """A Blackjack card."""
>>> card1.suit = "Spades"
>>> card1.value() def value(self):
11 if type(self.face) == int:
return self.face
>>> card2 = Card()
elif self.face == "Ace":
>>> card2.face = 2 return 11
>>> card2.suit = "Clubs" else:
>>> card2.value() return 10
2
CS101 Copyright (c) School of Computing, KAIST 7
Better syntax to create a card?
We can create a card and add attributes to it as follows:
>>> card1 = Card()
>>> card1.face = "Ace"
>>> card1.suit = "Spades"
How about this: doing both in a single line?
>>> card1 = Card("Ace", "Spades")
How?
CS101 Copyright (c) School of Computing, KAIST 8
Constructors
Objects can have a special method __init__, called a constructor.
Whenever an object of this type is created, the constructor is automatically
called.
Class Card(object):
"""A Blackjack card."""
def __init__(self, face, suit):
self.face = face
self.suit = suit
CS101 Copyright (c) School of Computing, KAIST 9
Now creating cards is elegant!
class Card(object):
"""A Blackjack card."""
def __init__(self, face, suit):
self.face = face
self.suit = suit
hand = [Card("Ace", "Spades"), Card(8, "Diamonds"),
Card("Jack", "Hearts"), Card(10, "Clubs")]
CS101 Copyright (c) School of Computing, KAIST 10
Constructor is a good place to validate the attributes
FACES = list(range(2, 11)) +
['Jack', 'Queen', 'King', 'Ace']
SUITS = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
Class Card(object):
"""A Blackjack card."""
def __init__(self, face, suit):
assert face in FACES and suit in SUITS
self.face = face
self.suit = suit Check if the face and suit values are
valid. Otherwise, it throws an
AssertionError.
CS101 Copyright (c) School of Computing, KAIST 11
assert keyword
“assert <Boolean expression>” is used for checking your expectations
in the debugging phase of programming.
def mysqrt(x):
assert x >= 0.0
return math.sqrt(x)
print(mysqrt(1))
print(mysqrt(-1))
<The output of the above program>
1.0
Traceback (most recent call last):
File “....py", line 8, in <module>
print(mysqrt(-1))
File “....py", line 4, in mysqrt
assert x >= 0.0
AssertionError
12
Better syntax for printing a card?
We can use card_string to print a card:
>>> card_string(card1)
'an Ace of Spades'
>>> card_string(card2)
'a 2 of Clubs'
However, this looks better!
>>> card1.string()
'an Ace of Spades'
>>> card2.string()
'a 2 of Clubs'
How?
CS101 Copyright (c) School of Computing, KAIST 13
card_string(card) into card.string()
Define the card.string() method:
class Card(object):
"""A Blackjack card."""
...
def string(self):
article = "a "
if self.face in [8, "Ace"]:
article = "an "
return (article + str(self.face) +
" of " + self.suit)
Then, you can do this:
>>> for card in hand:
... print(card.string(), "has value", card.value())
CS101 Copyright (c) School of Computing, KAIST 14
Even nicer syntax
>>> for card in hand:
... print(str(card), "has value", card.value())
>>> for card in hand:
... print(card, "has value", card.value())
print automatically converts card’s arguments to str
How?
Define method __str__, which is called when str(card) is called:
class Card(object):
"""A Blackjack card."""
"""Already defined __init__ and value methods"""
def __str__(self):
article = "a "
if self.face in [8, "Ace"]:
article = "an "
return (article + str(self.face) + " of " + self.suit)
CS101 Copyright (c) School of Computing, KAIST 15
Chickens again
CS101 Copyright (c) School of Computing, KAIST 16
Creating a Chicken object (from Lecture 9)
def make_chicken(hen = False):
layer = Layer()
if hen:
body = Ellipse(70,80)
body.setFillColor("white")
else:
body = Ellipse(40,50)
body.setFillColor("yellow")
body.move(0, 10)
body.setBorderColor("yellow")
body.setDepth(20)
layer.add(body)
# similarly for wing, eye, beak, dots
...
# finally, create a chicken, add attributes, and return it
ch = Chicken()
ch.layer = layer
ch.body = body
...
CS101 Copyright (c) School of Computing, KAIST 17
Using Chicken objects (from Lecture 9)
We use Chicken objects by accessing their attributes:
hen = make_chicken(True)
chick1 = make_chicken()
chick1.layer.move(120, 0)
chick2 = make_chicken()
chick2.layer.move(800, 200)
18
How about this?
hen = Chicken(True)
chick1 = Chicken()
chick1.move(120, 0)
chick2 = Chicken()
chick2.move(800, 200)
Looks better!
Then, how?
19
More elegant way to make a Chicken
class Chicken(object):
"""Graphic representation of a chicken."""
def __init__(self, hen = False):
layer = Layer()
# make all the parts
self.layer = layer
self.body = body
self.wing = wing
self.eye = eye
...
We can also add methods for Chicken like this:
class Chicken(object):
"""Graphic representation of a chicken."""
def move(self, dx, dy):
self.layer.move(dx, dy)
CS101 Copyright (c) School of Computing, KAIST 20
Blackjack with a command-line interface
You are dealt a 6 of Hearts
Dealer is dealt a hidden card
You are dealt a 3 of Spades
Dealer is dealt a 9 of Hearts
Your total is 9
Would you like another card? (y/n) y
You are dealt an Ace of Clubs
Your total is 20
Would you like another card? (y/n) n
The dealer's hidden card was a 10 of Spades
The dealer's total is 19
Your total is 20
The dealer's total is 19
You win!
Let’s learn Blackjack: L10_05.py
CS101 Copyright (c) School of Computing, KAIST 21
Deck object
Let’s create an object that represents a shuffled deck of 52 cards.
We only need one method: drawing a card from the top of the deck:
class Deck(object):
"""A deck of cards."""
def __init__(self):
"""Create a deck of 52 cards and shuffle them."""
self.cards = []
for suit in SUITS:
for face in FACES:
self.cards.append(Card(face, suit))
random.shuffle(self.cards)
def draw(self):
"""Draw the top card from the deck."""
return self.cards.pop() # returns the last
CS101 Copyright (c) School of Computing, KAIST 22
Drawing the cards from the Deck
num_players = 3
num_cards = 5
deck = Deck() A list of lists (one for each player)
hands = []
for j in range(num_players):
hands.append([])
for i in range(num_cards):
for j in range(num_players):
card = deck.draw()
hands[j].append(card)
print("Player", j+1, "draws", card)
for j in range(num_players):
print ("Player %d's hand (value %d):" %
(j+1, hand_value(hands[j])))
for card in hands[j]:
print (" ", card)
CS101 Copyright (c) School of Computing, KAIST 23
Then, you need a way to compare cards
You may need to use the comparison operators: ==, !=, <, etc.
But, they do not work automatically for objects:
>>> Card(8, "Diamonds") == Card(9, "Diamonds")
False
>>> Card(8, "Diamonds") == Card(8, "Diamonds")
False
By default, “==” is same as “is”
24
To make “==” more useful ...
Define the special method __eq__ :
class Card(object):
"""A Blackjack card."""
...
def __eq__(self, rhs):
return (self.face == rhs.face and
self.suit == rhs.suit)
def __ne__(self, rhs):
return not self == rhs
These special methods are called when you say
card1 == card2 card1.__eq__(card2)
card1 != card2
card1.__ne__(card2)
25
Blackjack with a graphical interface (GUI)
CS101 Copyright (c) School of Computing, KAIST 26
Table object
A Table represents the Blackjack table. It provides the following methods:
• clear() clears everything
• close() closes window and end game
• set_score(which, text) where which in [ 0, 1 ]
• set_message(text)
• ask(prompt) waits for y or n and returns True or False
Table has two attributes dealer and player.
These are Hand objects that represent the hand on the table.
Methods of Hand objects:
• clear()
• add(card, hidden = False)
• show() shows all hidden cards
• value() returns the value of hand
CS101 Copyright (c) School of Computing, KAIST 27
Ask and wait for a response
def ask(self, prompt):
self.question.setMessage(prompt)
while True:
e = self.canvas.wait() wait() wait for an input and
d = e.getDescription() return with “an event object”
if d == "canvas close":
sys.exit(1)
if d == "keyboard":
key = e.getKey()
if key == 'y':
return True
if key == 'n':
return False
while True:
if t.ask('Want more card? (y/n)'):
t.set_message('You said Yes')
else:
t.set_message('You said No')
28
More generally - Event Loop!
while True:
e = t.canvas.wait()
if e == None:
sys.exit(1)
d = e.getDescription()
if d == "keyboard":
k = e.getKey()
d = d + '-' + k Handles an event
if k == 'p':
t.player.add(Card("King", "Clubs"))
if k == 'q':
t.close()
elif d == "mouse click":
d = d + '-' + str(e.getMouseLocation())
t.set_message(d)
29
Separating tasks (event handlers) from the loop
while True:
e = t.canvas.wait()
if e == None:
sys.exit(1)
d = e.getDescription()
if d == "keyboard":
k = e.getKey()
d = d + '-' + k
onKey(k) Event Handler
elif d == "mouse click":
onMouseClick() Event Handler
elif ...
With this separation, you are only to provide event handlers in GUI
programming.
An event loop is usually embedded in a GUI programing framework, so
you do not usually see an event loop when you do a GUI programming.
30
GUI programing framework
https://gist.github.com/kassane/f233
GUI application framework 0ef44b070f4a5fa9d59c770f68e9
Spring 2020 CS101 Copyright (c) School of Computing, KAIST 31
Event-based programming
A GUI program is usually an "event-based" program.
That is, it is structured around events.
The program waits for an event to happen and execute an event handler.
For instance, events are
• key presses
• window is minimized, maximized, or closed
• mouse is moved
• mouse button is pressed
• cursor enters window or leaves window
A program doesn’t have a sequential flow of control but consists of event
handlers -- functions that are called by events.
CS101 Copyright (c) School of Computing, KAIST 32
Questions?
CS101 Copyright (c) School of Computing, KAIST 33