Een Date
klasse#
Data
dag
maand
jaar
class Date:
"""Date is a user-defined data structure --
a class that stores and manipulates dates
"""
def __init__(self, day, month, year):
"""The constructor for objects of type Date
"""
self.day = day
self.month = month
self.year = year
def __repr__(self):
"""This method returns a string representation for the
object of type Dat that calls it (named self)
"""
return f"{self.day:02d}/{self.month:02d}/{self.year:04d}"
def is_leap_year(self):
"""Returns True if self, the calling object, is
in a leap year; False otherwise
"""
if self.year % 400 == 0: return True
if self.year % 100 == 0: return False
if self.year % 4 == 0: return True
return False
Een object d
#
Stap voor stap#
class Date:
"""Date is a user-defined data structure --
a class that stores and manipulates dates
"""
Dit is het begin van een nieuw type Date
aangeven door het class
keyword
Let op de dubbele punt, dit betekent dat alles wat volgt ingesprongen moet worden omdat het bij de klasse hoort.
def __init__(self, day, month, year):
"""The constructor for objects of type Date
"""
self.day = day
self.month = month
self.year = year
Dit is de constructor voor Date
objecten. Dit is de plek voor waar input data wordt toegekend aan de (data) velden.
d = Date(11, 12, 2013)
De velden zijn de informatie die in elk Date
object aanwezig zijn.
def __repr__(self):
"""This method returns a string representation for the
object of type Dat that calls it (named self)
"""
return f"{self.day:02d}/{self.month:02d}/{self.year:04d}"
Dit is de string representatie van Date
objecten, het vertelt Python hoe een Date
object moet worden geprint.
f"strings"
#
Strings formatteren, handig!
klassen = 12
studenten = 25
f"{klassen} klassen met {studenten} studenten is in totaal {klassen * studenten}"
'12 klassen met 25 studenten is in totaal 300'
x = 1
f"{x:02d}"
'01'
02d
formatteert de integer x
tot een string met een minimale breedte van 2 posities, en “zero-padding” (voorloopmullen) links, indien nodig.
def is_leap_year(self):
"""Returns True if self, the calling object, is
in a leap year; False otherwise
"""
if self.year % 400 == 0:
return True
if self.year % 100 == 0:
return False
if self.year % 4 == 0:
return True
return False
Waarom wordt self
gebruikt en niet d
?
self
#
Is de variabele die de methode aanroept
Misschien heb je al kennisgemaakt met andere programmeertalen en zal je herkennen dat self
overeenkomt met wat je kent als this
in deze talen (bijvoorbeeld in Java of C++). Guido van Rossum geeft hier antwoord op de vraag waarom niet voor this
is gekozen, en legt het uit als een daad van speels verzet.
Het is hier misschien ook van belang om stil te staan bij het feit dat programmeertalen niet zomaar zijn ontstaan, het is mensenwerk en wij bouwen weer voort op het werk van anderen!
wd = Date(11, 12, 2013)
print(wd)
11/12/2013
wd.is_leap_year()
False
d = Date(11, 12, 2020)
print(d)
11/12/2020
d.is_leap_year()
True
Quiz#
De anatomie van een klasse
class Date: # (1)
def __init__(self, day, month, year): # (2)
self.day = day # (3)
self.month = month # (4)
self.year = year # (5)
def __repr__(self): # (6)
return f"{self.day:02d}/{self.month:02d}/{self.year:04d}" # (7)
def is_leap_year(self): # (8)
if self.year % 400 == 0: return True
if self.year % 100 == 0: return False
if self.year % 4 == 0: return True
return False
# (9)
wd = Date(11, 12, 2013) # (10)
ny = Date(1, 1, 2021) # (11)
Probeer de volgende onderdelen aan te wijzen:
class
keywordwaar eindigt de klassedefinitie?
objectdefinities, 2 totaal
methoden, 3 totaal
constructor
datavelden (attributen), 3 totaal
wat print
Date
’s?
Oplossing#
class
keyword: (1)waar eindigt de klassedefinitie?: (9)
objectdefinities, 2 totaal: (11, 12)
methoden, 3 totaal: (2, 6, 8)
constructor: (2)
datavelden (attributen), 3 totaal: (3, 4, 5)
wat print
Date
’s?: (6)
Methoden en operatoren#
Als alles een object is …
21 < 42
True
"🥚" > "🐔"
True
history = Date(1, 1, 1970)
epoch = Date(1, 1, 1970)
epoch == history
False
Dit werkt niet en dat is jammer! Dit gaan we straks oplossen, je zal Python moeten vertellen dat de operator ==
(en anderen) betekenis heeft als we objecten van type Date
willen gaan vergelijken.
Operatoren#
methode |
operator |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
What’s the diff
?#
epoch = Date(1, 1, 1970)
today = Date(6, 12, 2020)
Via een methode
today.diff(epoch)
18602
epoch.diff(today)
-18602
Where’s the dow
?#
sm1 = Date(28, 10, 1929)
sm2 = Date(19, 10, 1987)
Gebruikt een named object
sm1.dow()
'Monday'
sm2.dow()
'Monday'
Zonder naam, unnamed!
Date(1,1,1).dow()
'Monday'
Date(1,1,2021).dow()
'Friday'
str("Astronaut wordt snel oud tijdens een reis naar Mars").split()
['Astronaut', 'wordt', 'snel', 'oud', 'tijdens', 'een', 'reis', 'naar', 'Mars']
"Astronaut wordt snel oud tijdens een reis naar Mars".split()
['Astronaut', 'wordt', 'snel', 'oud', 'tijdens', 'een', 'reis', 'naar', 'Mars']
Het ==
probleem#
wd = Date(11, 12, 2013)
wd
11-12-2013
wd2 = Date(11, 12, 2013)
wd2
11-12-2013
wd == wd2
True
Waarde versus identiteit#
id(wd)
139902871396944
id(wd2)
139902871403152
==
zal standaard controleren op identiteit, de geheugenlokatie!
Vergelijken op waarde#
Laten we een eigen test voor gelijkwaardigheid schrijven!
class Date:
def __init__(self, day, month, year):
"""The constructor for objects of type Date
"""
self.day = day
self.month = month
self.year = year
def __repr__(self):
return f"{self.day:02d}/{self.month:02d}/{self.year:04d}"
def is_leap_year(self):
if self.year % 400 == 0: return True
if self.year % 100 == 0: return False
if self.year % 4 == 0: return True
return False
def equals(self, other):
"""Returns True if they represent
the same date; False otherwise
"""
if (
self.year == other.year
and self.month == other.month
and self.day == other.day
):
return True
else:
return False
wd = Date(11, 12, 2013)
wd2 = Date(11, 12, 2013)
wd.equals(wd2)
True
wd2.equals(wd)
True
Maar …
wd == wd2
False
__eq__
#
Vertel Python wat wij met gelijkwaardigeid bedoelen!
class Date:
def __init__(self, day, month, year):
"""The constructor for objects of type Date
"""
self.day = day
self.month = month
self.year = year
def __repr__(self):
return f"{self.day:02d}/{self.month:02d}/{self.year:04d}"
def is_leap_year(self):
if self.year % 400 == 0: return True
if self.year % 100 == 0: return False
if self.year % 4 == 0: return True
return False
def __eq__(self, other):
"""Returns True if they represent
the same date; False otherwise
"""
if (
self.year == other.year
and self.month == other.month
and self.day == other.day
):
return True
else:
return False
wd = Date(11, 12, 2013)
wd2 = Date(11, 12, 2013)
wd == wd2
True
Hergebruik#
De methode equals
blijven gebruiken maar ook Python vertellen over gelijkwaardigheid (__eq__
)?
class Date:
def __init__(self, day, month, year):
"""The constructor for objects of type Date
"""
self.day = day
self.month = month
self.year = year
def __repr__(self):
return f"{self.day:02d}/{self.month:02d}/{self.year:04d}"
def is_leap_year(self):
if self.year % 400 == 0: return True
if self.year % 100 == 0: return False
if self.year % 4 == 0: return True
return False
def equals(self, other):
"""Returns True if they represent
the same date; False otherwise
"""
if (
self.year == other.year
and self.month == other.month
and self.day == other.day
):
return True
else:
return False
def __eq__(self, other):
return self.equals(other)
Operator overloading#
Python duidelijk maken wat een type bedoelt!
__eq__(self, other)
definieert de gelijkheid operatator==
__ne__(self, other
definieert de ongelijkheid operatator!=
__lt__(self, other)
definieert de kleiner dan operatator<
__gt__(self, other)
definieert de groter dan operatator>
__le__(self, other)
definieert de kleiner of gelijk aan operatator<=
__ge__(self, other)
definieert de groter of gelijk aan operatator>=
__add__(self, other)
definieert de optelling operatator+
__sub__(self, other)
definieert de aftrekking operatator-
Morgen en gisteren#
class Date:
...
def tomorrow(self):
"""Moves the self date ahead 1 day
"""
DIM = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
self.day += 1 # first, add 1 to self.day
if ...: # test if we have gone "out of bounds"!
self.month ...
self.day ...
if ...: # then adjust the month and year, but only as needed!
self.year ...
self. month ...
Februari is variabel#
class Date:
...
def tomorrow(self):
"""Moves the self date ahead 1 day
"""
if self.is_leap_year():
fdays = 29
else:
fdays = 28
DIM = [0, 31, fdays, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
self.day += 1 # add 1 to the day
if self.day > DIM[self.month]: # check day
self.month += 1
self.day = 1
if self.month > 12: # check month
self.year += 1
self.month = 1