Klassen en objecten in Python: objectgeoriënteerd programmeren

Leer je eigen klassen in Python te schrijven. Definieer een klasse met een constructor en attributen, maak er objecten van en geef die methoden die hun gegevens veilig gebruiken en wijzigen. Zorg met speciale methoden dat objecten duidelijk worden weergegeven en werken met ==, sorteren en +. Bouw programma’s waarin objecten andere objecten bevatten en aanroepen, en beoordeel wanneer een klasse een programma duidelijker maakt dan functies en dictionary’s.

BeginnerLes 10 van 10 in Cursus Inleiding tot programmeren met Python

Wat je leert

  1. Ontdek dat elke Pythonwaarde een object is met eigen gegevens en methoden. Schrijf vervolgens zelf een klasse en maak er objecten van.
    • Herken de objecten die je al gebruikt
      Beschrijf strings, lijsten en dictionary’s als objecten die een type hebben, gegevens bevatten en methoden bieden die je met puntnotatie aanroept.
    • Definieer een klasse en maak instanties
      Schrijf een klasse-instructie, maak er meerdere afzonderlijke objecten van en stel hun attributen in en lees ze met puntnotatie.
  2. Gebruik een constructor om elk nieuw object de nodige attributen te geven, kies tussen instantie- en klasseattributen en voorkom dat ongeldige objecten worden gemaakt.
    • Schrijf een constructor met __init__ en self
      Definieer __init__ zodat elk nieuw object begint met zijn eigen attributen, afkomstig uit de argumenten of ingesteld op beginwaarden.
    • Kies tussen instantieattributen en klasseattributen
      Bepaal of een waarde bij elk object afzonderlijk of bij de klasse als geheel hoort en voorspel hoe Python beide soorten vindt en wijzigt.
    • Zorg dat objecten vanaf het begin geldig blijven
      Controleer de argumenten die een constructor ontvangt, werp een duidelijke exceptie op bij ongeldige waarden en handhaaf de regels die een object betekenis geven.
  3. Schrijf methoden die de gegevens van een object gebruiken en wijzigen, en bescherm die gegevens tegen wijzigingen die het object ongeldig maken.
    • Definieer instantiemethoden en roep ze aan
      Schrijf methoden die met self werken, roep ze aan op objecten en geef resultaten terug in plaats van ze af te drukken.
    • Wijzig de toestand van een object met methoden
      Schrijf methoden die attributen bijwerken terwijl het object geldig blijft, en voorspel wanneer een wijziging zichtbaar is via andere namen voor hetzelfde object.
    • Bescherm attributen met naamgevingsconventies en properties
      Markeer attributen als intern met een laag streepje en gebruik properties om nieuwe waarden te controleren of om waarden te berekenen die actueel blijven.
  4. Schrijf speciale methoden waarmee je objecten leesbare tekst tonen, met == en < worden vergeleken en met operatoren en ingebouwde functies werken.
    • Geef objecten leesbare stringrepresentaties
      Schrijf __str__ en __repr__ zodat objecten bruikbare tekst tonen wanneer ze worden afgedrukt, bekeken of in een lijst opgeslagen.
    • Vergelijk en combineer objecten met operatoren
      Definieer __eq__, __lt__, __add__ en __len__ zodat je objecten werken met ==, sorteren, + en len(), en bepaal wanneer een operator duidelijker is dan een methode met een naam.
  5. Combineer objecten zodat elk object zijn eigen gegevens verwerkt, volg programma’s waarin objecten elkaar aanroepen en bepaal wanneer een klasse een programma duidelijker maakt.
    • Maak objecten die andere objecten bevatten
      Sla objecten op als attributen of in lijsten binnen een ander object en schrijf methoden die op de hele collectie werken.
    • Laat objecten samenwerken via methoden
      Geef objecten door aan methoden en functies, geef nieuwe objecten terug en volg een kort programma waarin meerdere objecten samenwerken.
    • Bepaal wanneer een klasse een programma duidelijker maakt
      Beoordeel wanneer het helpt om gegevens en gedrag in een klasse te bundelen, ontwerp een kleine klasse op basis van een beschrijving en herschrijf code met dictionary’s als een klasse.

Klassen en objecten in Python: uitleg

5 hoofdstukken

1

Begrijp objecten en definieer je eerste klasse

Objecten komen al voor in elk Pythonprogramma dat je schrijft: een string heeft methoden, een lijst verandert haar inhoud en een dictionary geeft antwoord op zoekopdrachten. Door die bekende bewerkingen als objectgedrag te lezen, krijg je een vertrekpunt voor je eigen klassen. Leer hoe typen, identiteit en gedeelde referenties een programma beïnvloeden. Definieer daarna een kleine klasse en geef afzonderlijke instanties hun eigen attributen.

1.1 Herken de objecten die je al gebruikt

Je hebt al objecten gebruikt wanneer je met een getal, string, lijst of dictionary werkte. Een object heeft een type, een waarde of toestand en bewerkingen die het ondersteunt. Zelfs functies en None zijn objecten. Als je je eigen klasse schrijft, breid je dit bekende systeem uit.

Zoek het type en de methoden van een object

type("hello") geeft <class 'str'> terug; type([1, 2]) geeft <class 'list'> terug. De woorden type en klasse beschrijven hier dezelfde rol. isinstance(3.5, float) is True, terwijl isinstance("3.5", float) False is: de tweede waarde is tekst, ook al lijkt die op een getal.

Een methode is een functie die een type biedt. In "ada lovelace".title() is de string vóór de punt het object, is title de methode en roepen de ronde haakjes die aan. Het resultaat is "Ada Lovelace". dir(value) geeft een lijst met namen die een object biedt; namen zoals __len__ zijn speciale methoden die objecten verbinden met Pythonbewerkingen zoals len(value).

Volg het resultaat en het oorspronkelijke object

Een methodeaanroep kan een resultaat teruggeven, een object wijzigen of beide doen. Controleer het gedrag van de methode voordat je beslist wat je toekent.

word = "level"
print(word.count("l"))  # 2
print(word.upper())     # LEVEL
print(word)             # level

nums = [3, 1, 2]
result = nums.sort()
print(nums)             # [1, 2, 3]
print(result)           # None

Strings zijn onwijzigbaar: hun inhoud kan niet veranderen. upper() geeft een andere string terug, dus word behoudt zijn oorspronkelijke waarde. Om het resultaat in hoofdletters onder die naam te bewaren, schrijf je word = word.upper().

Lijsten zijn wijzigbaar. sort() wijzigt de lijst zelf en geeft None terug. Als je nums = nums.sort() schrijft, verliest nums de referentie naar de lijst en krijgt het de waarde None. Gebruik nums.sort() op een eigen regel of nums = sorted(nums) om een nieuwe gesorteerde lijst te krijgen. Bij een dictionary geeft {"a": 1}.get("b", 0) 0 terug omdat de gevraagde sleutel ontbreekt.

Ook ronde haakjes zijn van belang. word.upper is een methodeobject; word.upper() voert het uit. Veel objecten kunnen hetzelfde gedrag bieden: "cat".upper() en "dog".upper() gebruiken dezelfde soort methode met verschillende stringgegevens.

Maak onderscheid tussen gelijkheid en identiteit

Gelijkheid gaat over de vraag of waarden overeenkomen. Identiteit gaat over de vraag of twee namen naar één object verwijzen.

a = [1, 2]
b = [1, 2]
c = a
print(a == b)  # True
print(a is b)  # False
print(c is a)  # True
c.append(3)
print(a)       # [1, 2, 3]
print(b)       # [1, 2]

a en b beginnen met een gelijke inhoud, maar zijn afzonderlijke lijsten. c = a maakt een alias, een andere naam voor dezelfde lijst. Toevoegen via c wijzigt het object waar ook a naar verwijst. Het wijzigt niet de afzonderlijke lijst die b bevat. Teken bij het volgen van een programma één vak per object en een pijl van elke naam naar het bijbehorende vak.

Belangrijkste punten

  • Elke Pythonwaarde is een object met een type, toestand en ondersteunde bewerkingen.
  • Roep een methode aan met ronde haakjes; alleen een referentie naar een methode voert die niet uit.
  • Controleer of een methode een nieuwe waarde teruggeeft of het bestaande object wijzigt.
  • == vergelijkt waarden; is vergelijkt identiteit.
  • Door een toekenning kunnen twee namen verwijzen naar hetzelfde wijzigbare object.

1.2 Definieer een klasse en maak instanties

Een klasse definieert een type dat je in je eigen programma kunt gebruiken. Elk object dat ervan wordt gemaakt, is een instantie. Eén klasse beschrijft de soort; instanties bevatten de gegevens van afzonderlijke dingen. Een leeg formulier en de ingevulde exemplaren zijn een bruikbare vergelijking.

Schrijf een klasse en roep die aan

Een klasse-instructie heeft het gereserveerde woord class, een naam, een dubbele punt en een ingesprongen inhoud. Met pass geef je een lege inhoud op terwijl je de structuur uitprobeert.

class Book:
    pass

b1 = Book()
b2 = Book()
print(b1 is b2)           # False
print(isinstance(b1, Book))  # True

Elke aanroep van Book() maakt een afzonderlijke instantie. In een script toont type(b1) <class '__main__.Book'>. De klasse-instructie moet worden uitgevoerd voordat code Book probeert te gebruiken. Je kunt een klasse ook in een module definiëren en met from library import Book importeren, waarna je instanties maakt in het aanroepende programma.

Volg de naamgevingsconventies van Python: Book, BankAccount en ShoppingCart gebruiken CapWords, waarbij elk woord met een hoofdletter begint. Namen van variabelen en methoden gebruiken kleine letters met lage streepjes tussen de woorden, zoals book_count en add_item. Gebruik vier spaties voor elk inspringniveau.

Sla gegevens op elke instantie op

Een attribuut is een benoemde waarde die je met een punt benadert. Door een waarde aan een attribuut toe te kennen, sla je die op; door dezelfde naam te lezen, haal je die op.

b1.title = "Dune"
b2.title = "Emma"
b1.pages = 412
print(b1.title)  # Dune
print(b2.title)  # Emma
print(b1.pages)  # 412

De gegevens horen bij de gekozen instantie. Als je b1 een attribuut pages geeft, krijgt b2 dat niet. Het lezen van b2.pages werpt nu AttributeError op, omdat dat object geen attribuut met de naam pages heeft.

Toekenningen kunnen nieuwe namen maken zonder te controleren wat je bedoelde. Na b1.titel = "X" bevat het oorspronkelijke b1.title nog steeds "Dune"; het object heeft er een tweede attribuut met een verkeerd gespelde naam bij gekregen. Als een waarde niet lijkt te veranderen, vergelijk dan de spelling op de plek waar de waarde is toegekend en waar die wordt gelezen.

Houd de klasse en haar instanties uit elkaar
ExpressieBetekenis
BookHet klasseobject dat het type definieert
Book()Een aanroep die een instantie maakt
b1.titleDe titel die op dit boek is opgeslagen
Book.titleEen attribuut dat op de klasse zelf wordt opgevraagd

b = Book geeft de klasse een andere naam. Het maakt geen boek. Als titels alleen op instanties zijn ingesteld, werpt het opvragen van Book.title AttributeError op; er is geen enkele titel die door het type wordt gedeeld.

Geef elk object een betrouwbaar begin

Attributen van buitenaf instellen is mogelijk, maar daardoor raakt de inrichting verspreid over het programma. Het ene boek krijgt misschien een titel en een aantal pagina’s, terwijl het andere alleen een titel krijgt. Latere code kan er niet veilig van uitgaan dat beide pages hebben.

Een inrichtingsmethode met de naam __init__ plaatst de begintoekenningen binnen de klasse. Elke aanroep om een object te maken volgt dan hetzelfde inrichtingsproces. De klasse kan een titel verplicht stellen en andere attributen met zinvolle beginwaarden maken, zodat de aanroepende code geen afzonderlijke reeks toekenningen hoeft te onthouden.

Belangrijkste punten

  • Een klasse definieert een type; een instantie is één object dat ervan is gemaakt.
  • Gebruik ClassName() om een instantie te maken en puntnotatie om haar attributen te benaderen.
  • Elke instantie kan onder dezelfde attribuutnamen andere gegevens bevatten.
  • Een ontbrekend attribuut werpt AttributeError op; een toekenning met een verkeerd gespelde naam kan een nieuw attribuut maken.
2

Richt objecten in met constructors en attributen

Een object heeft een betrouwbare begintoestand nodig voordat zijn methoden nuttig werk kunnen doen. Initialisatie verbindt de argumenten in een klasseaanroep met attributen die op de nieuwe instantie worden opgeslagen. Kies welke waarden bij één object horen en welke bij de klasse, en valideer invoer voordat je die accepteert. Door opzoekingen en fouten bij de inrichting te volgen, herken je onbedoeld delen en ontbrekende gegevens.

2.1 Schrijf een constructor met __init__ en self

Elke nieuw gemaakte rekening heeft een eigenaar en een beginsaldo nodig. Door die inrichting in __init__ te zetten, krijgt elk object de attributen die latere methoden verwachten. Python maakt eerst de instantie en roept daarna __init__ aan om die te initialiseren.

Verbind argumenten met attributen
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance
        self.transactions = []

acct = BankAccount("Maya", 50)
other = BankAccount("Leo")

Bij de eerste aanroep geeft Python de nieuwe rekening door als self, "Maya" als owner en 50 als balance. Door de toekenningen wordt acct.owner gelijk aan "Maya" en acct.balance aan 50. De tweede aanroep gebruikt het standaardsaldo, dus other.balance is 0.

self is de parameter die het huidige object ontvangt. Het is een conventie, geen gereserveerd woord in Python. Gebruik deze naam zodat lezers het object meteen herkennen. Aanroepende code laat deze parameter weg: BankAccount("Maya", 50) geeft twee argumenten door, geen drie.

Houd lokale namen en opgeslagen gegevens apart

In self.owner = owner is de naam rechts een lokale parameter. De naam links is een attribuut dat op het object wordt opgeslagen. Wanneer de initialisatie eindigt, kunnen andere methoden self.owner nog steeds gebruiken.

Als je balance = balance schrijft, ken je alleen opnieuw een waarde toe aan de lokale naam. Er ontstaat geen attribuut, dus het latere lezen van acct.balance mislukt. Zet self. vóór elk attribuut dat deel van het object moet blijven.

Plan de initialisatie door op een rij te zetten wat elke instantie nodig heeft. Verplichte waarden worden parameters na self; optionele waarden kunnen standaardwaarden krijgen. Waarden die altijd hetzelfde beginnen, kun je in de inhoud toekennen, zoals self.visits = 0. Een lijst die met self.transactions = [] wordt gemaakt, wordt bij elke aanroep opnieuw aangemaakt.

Voorkom een gedeelde standaardlijst

Een standaardargument wordt geëvalueerd wanneer Python de methode definieert. Met def __init__(self, items=[]) ontvangen aanroepen die items weglaten dezelfde lijst. Als de initialisatiemethode die lijst rechtstreeks opslaat, verandert een wijziging van de elementen van het ene object ook de elementen die een ander object ziet.

Gebruik None als standaardwaarde en maak bij elke aanroep een nieuwe lijst:

class Cart:
    def __init__(self, items=None):
        self.items = [] if items is None else list(items)

a = Cart()
b = Cart()
a.items.append("pen")
print(b.items)  # []

list(items) maakt ook een nieuwe buitenlijst wanneer de aanroepende code een lijst doorgeeft. De objecten in die lijst worden nog steeds via referenties gedeeld; door de lijst te maken, wordt niet elk element opnieuw gemaakt.

Lees fouten bij de inrichting

Bij BankAccount() ontbreekt het verplichte argument owner en wordt TypeError opgeworpen. Vergelijk de aanroep met de parameters na self.

De spelling __init__ heeft aan beide kanten twee lage streepjes. _init_ is een gewone methodenaam en voert deze inrichting niet automatisch uit. __init__ moet None teruggeven, dus laat je een return-instructie normaal gesproken weg. Als je een saldo teruggeeft, wordt TypeError opgeworpen; de klasseaanroep zelf geeft de nieuwe instantie aan de aanroepende code.

Belangrijkste punten

  • __init__ initialiseert de instantie nadat Python die heeft gemaakt.
  • Python levert self; de aanroepende code levert de overige argumenten.
  • self.name = name slaat een parameter op als instantieattribuut.
  • Maak lijsten per instantie tijdens de initialisatie; gebruik None in plaats van een wijzigbare standaardwaarde.
  • __init__ moet None teruggeven.

2.2 Kies tussen instantieattributen en klasseattributen

Sommige waarden beschrijven één object; andere beschrijven het type als geheel. De grootte van een pizza hoort bij die pizza. Een maximum voor het beleg of een telling van gemaakte pizza’s kan bij de klasse horen. De plaats van een toekenning bepaalt welk soort attribuut die maakt.

Zet de waarde op de juiste plek
class Pizza:
    MAX_TOPPINGS = 5
    count = 0

    def __init__(self, size):
        self.size = size
        self.toppings = []
        Pizza.count += 1

p1 = Pizza("large")
p2 = Pizza("small")

size en toppings zijn instantieattributen, ingesteld op self. Elke pizza heeft zijn eigen waarden. MAX_TOPPINGS en count zijn klasseattributen, toegekend in de klasse-inhoud buiten een methode. Hoofdletters markeren een waarde die als constante is bedoeld; ze voorkomen geen hernieuwde toekenning.

Na deze aanroepen is Pizza.count gelijk aan 2. Elke initialisatiemethode werkt hetzelfde klasseattribuut bij. p1.size is "large", terwijl p2.size "small" is.

Volg opzoeking en naamverhulling

Bij gewone gegevensattributen zoals deze controleert Python bij het lezen van p1.MAX_TOPPINGS eerst de instantie en daarna de klasse. Omdat op p1 geen waarde is opgeslagen, vindt Python Pizza.MAX_TOPPINGS, met de waarde 5.

Een toekenning via een instantie heeft een ander effect:

p1.MAX_TOPPINGS = 8
Pizza.MAX_TOPPINGS = 6
print(p1.MAX_TOPPINGS)     # 8
print(p2.MAX_TOPPINGS)     # 6
print(Pizza.MAX_TOPPINGS)  # 6

De eerste regel maakt een instantieattribuut op p1. Dat verhult de klassewaarde voor dat object. Een latere wijziging van de klassewaarde bereikt p2, dat nog steeds van de klasse leest, maar vervangt de eigen waarde van p1 niet.

ToekenningWat verandert
self.size = sizeGegevens op de huidige instantie
Pizza.count += 1De gedeelde klasseteller
p1.MAX_TOPPINGS = 8Een instantiewaarde die de klassewaarde verbergt
Let op twee vormen van onbedoeld delen

Als de initialisatiemethode self.count += 1 zou gebruiken, zou Python de 0 van de klasse lezen, er één bij optellen en een instantieattribuut opslaan. Elke nieuwe pizza zou zijn eigen count van 1 krijgen, terwijl Pizza.count 0 bleef. Gebruik de klassenaam wanneer je een teller voor de hele klasse bijwerkt.

Een lijst in de klasse-inhoud veroorzaakt een ander probleem. Met toppings = [] vinden instanties die geen afzonderlijk attribuut voor beleg hebben allemaal dezelfde lijst. p1.toppings.append("olives") wijzigt die gedeelde lijst; het kent geen nieuw instantieattribuut toe. Zet self.toppings = [] in __init__ wanneer elke pizza zijn eigen beleg nodig heeft.

Bekijk de eigen gegevens van een object

Voor de oorspronkelijke p2 geeft vars(p2) {'size': 'small', 'toppings': []}. De klassewaarden ontbreken omdat ze op Pizza staan. Dit is nuttig bij het debuggen van een onverwacht opzoekresultaat: controleer of de instantie een eigen waarde heeft en bekijk daarna de klassewaarde. Een gedeelde instelling hoort op de klasse; een naam, grootte, saldo of persoonlijke collectie hoort op de instantie.

Belangrijkste punten

  • Instantieattributen bevatten gegevens voor één object; klasseattributen bevatten gedeelde instellingen of gegevens voor de hele klasse.
  • Een instantiegegevensattribuut kan een klasseattribuut met dezelfde naam verhullen.
  • Werk een gedeelde teller bij via de klassenaam.
  • Als je een lijst op klasseniveau wijzigt, wijzig je de ene gedeelde lijst.
  • vars(obj) toont de eigen opgeslagen attributen, niet de klasseattributen die het kan vinden.

2.3 Zorg dat objecten vanaf het begin geldig blijven

Een object moet beginnen in een toestand die zijn methoden kunnen gebruiken. Een rechthoek met een negatieve breedte kan de bedoelde vorm niet voorstellen. Een regel die voor elk object van een klasse waar moet blijven, is een invariant. Validatie controleert die regels voordat gegevens worden geaccepteerd.

Controleer vóór het opslaan
class Rectangle:
    def __init__(self, width, height):
        if width <= 0:
            raise ValueError("width must be positive")
        if height <= 0:
            raise ValueError("height must be positive")
        self.width = width
        self.height = height

Rectangle(3, 4) doorstaat beide controles en geeft een geïnitialiseerd object terug. Rectangle(-2, 4) werpt bij de eerste controle ValueError op. De latere toekenningen worden niet uitgevoerd. Als het programma die exceptie niet opvangt, stopt de uitvoering daar.

Stel dat r al naar een geldige rechthoek verwijst. In r = Rectangle(-2, 4) mislukt de aanroep rechts vóór de toekenning. r behoudt zijn eerdere waarde. Als r vóór de mislukte aanroep geen waarde had, maakt de toekenning er ook geen aan.

Kies een bruikbare exceptie
ExceptieProbleem dat ze beschrijft
ValueErrorEen aanvaardbare soort invoer heeft een onaanvaardbare waarde
TypeErrorDe invoer heeft het verkeerde type voor de bewerking

Een negatieve numerieke breedte is een waardefout. Tekst die wordt doorgegeven waar een getal nodig is, is een typefout. De vergelijking met 0 in dit voorbeeld werpt voor tekst al TypeError op. Een klasse kan een type ook expliciet met isinstance controleren als een duidelijkere melding nodig is.

Schrijf meldingen die de regel noemen, zoals "width must be positive". Bij een melding met alleen "bad input" moet de aanroepende code raden welke waarde moet worden hersteld.

Laat de aanroepende code het herstel afhandelen
while True:
    try:
        width = float(input("Width: "))
        room = Rectangle(width, 3)
        break
    except ValueError as error:
        print("Try again:", error)

Invoer van abc mislukt bij float; invoer van -2 doorstaat de conversie maar mislukt in Rectangle. Beide werpen ValueError op, dus deze lus handelt beide af. De klasse stelt haar gegevensregel vast, terwijl de aanroepende code beslist om opnieuw om invoer te vragen.

Een waarschuwing afdrukken binnen __init__ wijst de aanroep niet af. Als de uitvoering doorgaat, kan het programma een ongeldig object ontvangen en later bij het gebruik ervan mislukken. Een exceptie opwerpen stopt de mislukte inrichting waar het probleem optreedt.

Schoon gegevens bewust op en handhaaf de regel

Een gedocumenteerde opschoning kan nuttig zijn. self.name = name.strip() verwijdert spaties aan de randen; valideer de opgeschoonde naam als lege namen verboden zijn. self.items = list(items) maakt een afzonderlijke buitenlijst, zodat toevoegen aan de lijst van de aanroepende code niets aan deze lijst toevoegt. Een ongeldige breedte veranderen in haar absolute waarde zou de betekenis van de invoer veranderen en vereist dus een expliciete ontwerpregel.

Initialisatiecontroles worden uitgevoerd bij het maken van het object. Een gewone toekenning zoals r.width = -5 omzeilt ze later nog steeds. Methoden die een breedte wijzigen, moeten die opnieuw controleren. Een property kan een controle op de attribuuttoekenning zelf plaatsen, zodat dezelfde regel tijdens de inrichting en bij latere wijzigingen wordt uitgevoerd.

Belangrijkste punten

  • Een invariant is een regel waaraan de toestand van een geldig object moet voldoen.
  • Valideer voordat je gegevens accepteert en werp bij een fout een duidelijke exceptie op.
  • Een mislukte aanroep om een object te maken kent geen nieuw object toe aan de naam van de aanroepende code.
  • Controles in de constructor hebben ook ondersteuning nodig in latere methoden of properties die de toestand wijzigen.
3

Geef objecten gedrag met instantiemethoden

Methoden zetten opgeslagen gegevens om in nuttig gedrag. Een rechthoek kan zijn oppervlakte berekenen en een rekening kan zijn saldo bijwerken terwijl een transactie wordt vastgelegd. Volg hoe Python het ontvangende object aan elke methode doorgeeft en maak daarna onderscheid tussen een teruggegeven resultaat en een wijziging van de toestand. Met properties kan een klasse leesbare toegang tot attributen behouden en tegelijk toekenningen controleren of waarden op aanvraag berekenen.

3.1 Definieer instantiemethoden en roep ze aan

Een instantiemethode is een functie die binnen een klasse is gedefinieerd en werkt met het object dat als self wordt doorgegeven. Het object levert zijn opgeslagen gegevens; extra parameters leveren eventuele aanvullende informatie die voor de actie nodig is.

Lees attributen via self

Voeg deze methoden toe binnen de gevalideerde klasse Rectangle, op hetzelfde inspringniveau als __init__:

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

    def is_square(self):
        return self.width == self.height

Met r = Rectangle(3, 4) geeft r.area() 12 terug, geeft r.perimeter() 14 terug en geeft r.is_square() False terug. Elke methode leest de attributen van hetzelfde object. Een tweede rechthoek gebruikt dezelfde methodedefinities met zijn eigen breedte en hoogte.

Binnen een methode duidt self.width een attribuut aan. Een losse width duidt een lokale of andere toegankelijke variabele aan; Python zoekt die niet automatisch op het huidige object. Als zo’n variabele niet bestaat, werpt return width * height NameError op. Door self. te schrijven, maak je expliciet bij welk object de bedoelde gegevens horen.

Volg de aanroep

Voor deze klasse werkt r.area() als Rectangle.area(r). Python vindt de functie op de klasse en levert r als eerste argument. Een methodereferentie zoals r.area is een gebonden methode: die onthoudt de functie en deze rechthoek. Door () toe te voegen, voer je de aanroep uit.

Als een methode is gedefinieerd als def resize(self, factor), roep je die aan als r.resize(2). r vult self in en 2 vult factor in. Je geeft r niet nogmaals door. Als een instantiemethode per ongeluk als def area(): is geschreven, werpt een aanroep op r TypeError op, omdat Python het object nog steeds doorgeeft aan een functie die geen argumenten accepteert.

De ene methode kan via self een andere gebruiken:

    def double_area(self):
        return self.area() * 2

Hier berekent self.area() met dezelfde rechthoek. Als je self. weglaat, vraag je om een afzonderlijke functie met de naam area, niet om de methode van het object.

Geef resultaten terug aan de aanroepende code

Een berekeningsmethode hoort haar resultaat normaal gesproken terug te geven. Zo krijgt de aanroepende code een waarde om op te slaan, te combineren, te toetsen of weer te geven:

r1 = Rectangle(3, 4)
r2 = Rectangle(2, 5)
total = r1.area() + r2.area()
print(total)  # 22

Als area het antwoord alleen zou afdrukken, zou elke aanroep None teruggeven. De optelling zou dan mislukken met TypeError, ook al waren er twee getallen op het scherm verschenen. Afdrukken is een actie; teruggeven levert een waarde aan de expressie die de aanroep bevat.

Gebruik methodenamen die de taak laten zien. deposit en resize duiden acties aan; is_square en has_room suggereren booleaanse controles. Een methode heeft geen parameters nodig voor gegevens die al op haar object zijn opgeslagen. Ze heeft wel parameters nodig voor nieuwe invoer, zoals een vergrotingsfactor of een stortingsbedrag.

Belangrijkste punten

  • Zet self vooraan in een instantiemethode; Python levert het ontvangende object.
  • Lees attributen en roep andere methoden aan via self..
  • Ronde haakjes voeren een gebonden methode uit.
  • Geef berekende waarden terug zodat aanroepende code ze kan combineren, toetsen of weergeven.

3.2 Wijzig de toestand van een object met methoden

De toestand van een object is de huidige verzameling waarden in zijn attributen. Een uitleesmethode geeft informatie over die toestand. Een wijzigingsmethode verandert die. Een bruikbare wijzigingsmethode controleert haar invoer en houdt alle bijbehorende attributen bij, zodat de aanroepende code niet meerdere wijzigingen hoeft te coördineren.

Valideer eerst de hele wijziging

Voeg deze methoden toe binnen de klasse BankAccount met haar eigenaar, saldo en transactielijst:

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("deposit must be positive")
        self.balance += amount
        self.transactions.append(("deposit", amount))

    def withdraw(self, amount):
        if amount <= 0:
            raise ValueError("withdrawal must be positive")
        if amount > self.balance:
            raise ValueError("insufficient funds")
        self.balance -= amount
        self.transactions.append(("withdraw", amount))

Een storting wijzigt het saldo en legt de gebeurtenis vast. Een opname controleert zowel het teken van het bedrag als het beschikbare saldo voordat het bedrag wordt afgetrokken. Deze controles voorkomen dat een afgewezen opname het saldo of de transactiegeschiedenis wijzigt.

Als je begint met BankAccount("Maya", 50), geeft een storting van 25 het saldo 75 en een opname van 30 het saldo 45. Een latere poging om 100 op te nemen werpt ValueError op; het saldo blijft 45 en er wordt geen transactie toegevoegd. Als de aftrekking vóór de saldocontrole zou staan, zou de toestand ook bij een fout veranderen.

Maak onderscheid tussen een wijziging en een retourwaarde

Deze wijzigingsmethoden hebben geen return-instructie, dus geven ze None terug. Na new_balance = acct.deposit(25) heeft de storting plaatsgevonden, maar is new_balance gelijk aan None. Lees daarna acct.balance om het bijgewerkte getal te krijgen.

Een klasse kan ook een ander soort methode bieden die een nieuw object teruggeeft. resize suggereert dat een rechthoek wordt gewijzigd; resized kan worden gekozen voor een methode die een nieuwe rechthoek teruggeeft en het oorspronkelijke object ongemoeid laat. Lees het contract van de methode: de naam helpt, maar de definitie bepaalt het gedrag.

Volg gedeelde referenties
a = BankAccount("Maya", 50)
b = a
b.deposit(10)
print(a.balance)  # 60
print(a is b)     # True

Een toekenning bindt een naam aan een object; ze kopieert dat object niet. Beide namen verwijzen naar de rekening waarvan het saldo is gewijzigd. Als je a aan een functie doorgeeft, geef je ook toegang tot dat object door. Een functie die account.withdraw(5) aanroept, kan daardoor de rekening wijzigen die de aanroepende code ziet.

Maak voor een onafhankelijke rekening met dezelfde eigenaar en hetzelfde saldo BankAccount(a.owner, a.balance). Die constructor levert ook een nieuwe, lege transactiegeschiedenis. Het is een nieuwe rekening, geen volledige kopie van de geschiedenis.

copy.copy(a) maakt een nieuw buitenste object, maar behoudt referenties naar dezelfde binnenliggende objecten, waaronder de transactielijst. copy.deepcopy(a) kopieert ook geneste objecten. Als onafhankelijkheid van belang is, controleer dan zowel de objecten binnen de attributen als de buitenste instantie.

Een rechtstreekse toekenning acct.balance = -500 slaat de controles in de twee methoden over. Conventies voor interne attributen en properties helpen om duidelijk te maken hoe wijzigingen bedoeld zijn en om validatie dicht bij toestandswijzigingen te houden.

Belangrijkste punten

  • Controleer een gevraagde wijziging voordat je attributen bijwerkt.
  • Een wijzigingsmethode kan de toestand wijzigen en tegelijk None teruggeven.
  • Bij toekenning en het doorgeven van argumenten blijven referenties naar hetzelfde object behouden.
  • Een ondiepe kopie kan nog steeds geneste wijzigbare objecten delen.
  • Houd samenhangende wijzigingen van de toestand bij elkaar in de methode die ervoor verantwoordelijk is.

3.3 Bescherm attributen met naamgevingsconventies en properties

Aanroepende code heeft een duidelijke manier nodig om een object te lezen en te wijzigen. Inkapseling houdt de regels voor de gegevens bij de methoden die ze beheren. Python gebruikt conventies en properties om die interface vorm te geven.

Markeer interne opslag

Een laag streepje aan het begin van _balance duidt een intern attribuut aan. Aanroepende code hoort de methoden van de rekening te gebruiken, maar Python staat rechtstreekse toegang nog steeds toe. Er is geen gereserveerd woord private dat de waarde afschermt.

Een naam zoals __balance, met twee lage streepjes aan het begin en geen dubbele lage streepjes aan het einde, leidt tot naamvervorming. Binnen class Acc wordt self.__balance opgeslagen onder _Acc__balance. Buiten de klasse mislukt obj.__balance, maar obj._Acc__balance kan nog steeds werken. Naamvervorming voorkomt botsingen tussen namen; ze beveiligt geen gevoelige gegevens.

Voer een methode uit via attribuutsyntaxis

Een property voert een methode uit wanneer een attribuut wordt gelezen. De regel @property is een decorator: die verandert hoe Python de methode beschikbaar maakt. Een property zonder setter staat lezen toe, maar wijst toekenning af.

class Account:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self._balance = balance

    @property
    def balance(self):
        return self._balance

Lees na acct = Account("Maya", 50) de waarde van acct.balance zonder ronde haakjes. De toekenning acct.balance = 10 werpt AttributeError op omdat deze property geen setter heeft. Een stortingsmethode binnen de klasse zou _balance na haar controles kunnen bijwerken.

Controleer toekenning met een setter
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not 0 <= value <= 100:
            raise ValueError("score must be between 0 and 100")
        self._score = value

De getter en setter delen de naam score; de opgeslagen waarde gebruikt _score. Bij het maken van het object voert self.score = score de setter uit.

Voor s = Student("Ana", 88) slaat de toekenning s.score = 92 de waarde 92 op. De toekenning s.score = -1 werpt vóór het opslaan ValueError op, dus de score blijft 92. Student("Ana", 105) mislukt tijdens de initialisatie.

Binnen de setter zou self.score = value de setter opnieuw aanroepen, en dat herhaalt zich tot RecursionError. De getter loopt hetzelfde risico als die self.score teruggeeft. Gebruik de afzonderlijke opslagnaam _score in beide methode-inhouden.

Bereken waarden wanneer ze worden gelezen

Een property kan een waarde uit andere attributen berekenen:

    @property
    def area(self):
        return self.width * self.height

Als deze property binnen een rechthoekklasse staat, kun je r.area gebruiken. Bij breedte 3 en hoogte 4 is de waarde 12. Als je de breedte wijzigt in 5, geeft de volgende leesactie 20 terug. Als je tijdens de initialisatie één keer een oppervlakte zou opslaan, blijft na een wijziging van de breedte een oude waarde staan.

Begin met een gewoon attribuut als eenvoudige opslag volstaat.

Belangrijkste punten

  • Een laag streepje aan het begin markeert volgens conventie interne opslag; het blokkeert de toegang niet.
  • Naamvervorming verandert een attribuutnaam om botsingen te voorkomen.
  • Een property voert een getter uit via attribuutsyntaxis.
  • Een setter kan initialisatie en latere toekenningen op één plek valideren.
  • Gebruik een afzonderlijk opslagattribuut om te voorkomen dat de property zichzelf recursief aanroept.
  • Een berekende property leidt haar waarde af wanneer ze wordt gelezen.
4

Gebruik speciale methoden om objecten goed weer te geven en te vergelijken

Een bruikbaar object hoort vanzelfsprekend in gewone Pythonexpressies te passen. Zijn speciale methoden kunnen leesbare tekst, waardegelijkheid, een ordening, rekenresultaten of een lengte leveren. Leer welke methode Python in elke situatie opvraagt en wat die methode moet teruggeven. Let vooral op weergave binnen containers, stabiele dictionarysleutels en het verschil tussen een bewerking en de gespiegelde vorm ervan.

4.1 Geef objecten leesbare stringrepresentaties

Een object is gemakkelijker te onderzoeken als het zijn eigen gegevens kan beschrijven. Speciale methoden laten Python die beschrijving opvragen via bekende acties zoals print, str en repr. Hun namen beginnen en eindigen met twee lage streepjes en worden vaak dunder-namen genoemd.

Kies tekst voor twee doelgroepen

__str__ levert leesbare tekst voor gebruikers van een programma. __repr__ levert een nauwkeurige beschrijving voor programmeurs. Beide geven strings terug; geen van beide hoort het resultaat af te drukken in plaats van terug te geven.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"({self.x}, {self.y})"

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

p = Point(3, 4)
print(p)        # (3, 4)
print(repr(p))  # Point(3, 4)

str(p) geeft de string "(3, 4)" terug. repr(p) geeft "Point(3, 4)" terug. Waar mogelijk lijkt een representatie op een klasseaanroep waarmee je de waarde opnieuw zou maken. Het blijft tekst: de aanroep van repr maakt zelf geen ander punt.

Zonder zelf gedefinieerde representatie toont een gewone instantie doorgaans een klassenaam en een identificatie die op een adres lijkt. Dat helpt om objecten uit elkaar te houden, maar toont hun bruikbare gegevens niet. Je roept deze speciale methoden zelden rechtstreeks aan; definieer ze één keer en gebruik de gewone weergavebewerkingen van Python.

Voorspel wat een container weergeeft
ExpressieOpgevraagde representatie
print(p) of str(p)__str__
repr(p)__repr__
f"{p}"De gebruikelijke stringvorm voor deze klasse
f"{p!r}"__repr__
print([p])De weergave van de lijst, met repr voor het element

Met de klasse hierboven toont print([Point(3, 4), Point(0, 0)]) [Point(3, 4), Point(0, 0)]. De lijst gebruikt de representaties van haar elementen, ook al heeft elk element ook __str__.

Als je alleen __repr__ definieert, gebruikt de standaardversie van __str__ die ook. Als je alleen __str__ definieert, verandert de weergave van repr of containers niet. Als je maar één weergavemethode toevoegt, is __repr__ daarom in meer situaties bruikbaar om objecten te onderzoeken.

Maak stringvelden ondubbelzinnig

Voor een boek dat title, author en year al opslaat, geven deze methoden verschillende bruikbare weergaven:

    def __str__(self):
        return f"{self.title} by {self.author} ({self.year})"

    def __repr__(self):
        return f"Book({self.title!r}, {self.author!r}, {self.year})"

Voor het boek met titel "Dune", auteur "Frank Herbert" en jaar 1965 geeft de eerste methode "Dune by Frank Herbert (1965)". De tweede geeft "Book('Dune', 'Frank Herbert', 1965)". !r vraagt de representaties van de stringvelden op, inclusief aanhalingstekens.

Een methode-inhoud met alleen print(self.x) geeft None terug, dus mislukt str(p) met TypeError. Ook een geheel getal teruggeven mislukt. Stel de vereiste tekst samen en geef die string terug.

Belangrijkste punten

  • __str__ levert tekst voor gebruikers; __repr__ levert een bruikbare representatie voor programmeurs.
  • Containers geven hun elementen weer met repr.
  • __repr__ kan de standaardstringvorm leveren; __str__ vervangt repr niet.
  • Beide methoden moeten strings teruggeven.
  • Gebruik !r in een f-string om representaties van stringvelden met aanhalingstekens te tonen.

4.2 Vergelijk en combineer objecten met operatoren

Speciale methoden verbinden een klasse met operatoren en ingebouwde functies. Definieer alleen bewerkingen die een duidelijke betekenis hebben voor dat type: vectoren optellen is begrijpelijk; een speler aan een team toevoegen is duidelijker als team.add_player(player).

Vergelijk waarden en houd hashes veilig

Twee afzonderlijke gewone instanties zijn standaard ongelijk bij een vergelijking. Voeg waardegelijkheid toe aan een puntklasse met:

    def __eq__(self, other):
        if not isinstance(other, Point):
            return NotImplemented
        return self.x == other.x and self.y == other.y

Nu zijn twee punten op (3, 4) bij vergelijking gelijk, ook al verschilt hun identiteit. in, count, index en remove kunnen bij lijsten zulke gelijke waarden vinden. Het gebruikelijke resultaat van != volgt uit __eq__.

NotImplemented is een retourwaarde waarmee Python de andere operand of een terugvalmogelijkheid kan proberen. Het is geen exceptie die je moet opwerpen. Wanneer geen van beide operanden waardegelijkheid ondersteunt, valt == terug op identiteit; een punt en de string "3,4" zijn bij vergelijking ongelijk.

Als je __eq__ zonder __hash__ definieert, worden instanties niet-hashbaar. Ze kunnen dan geen elementen van een verzameling of sleutels in een dictionary zijn. Gelijke objecten moeten gelijke hashes hebben en de hash van een sleutel moet stabiel blijven. Als de vergeleken attributen nooit veranderen, kan een passende hashmethode hash((self.x, self.y)) teruggeven. Houd wijzigbare waardeobjecten niet-hashbaar wanneer hun gelijkheidsvelden kunnen veranderen.

Definieer een ordening

__lt__ levert <. Een studentklasse kan scores vergelijken met return self.score < other.score. De scores 88, 72 en 95 worden dan gesorteerd als 72, 88, 95. min kiest de laagste; max kiest de hoogste met > en de gespiegelde vergelijking met <.

Met alleen __lt__ kan a > b gebruikmaken van b < a. Python leidt <= of >= niet uit die definitie af; die hebben hun eigen methoden nodig. Als een volgorde alleen voor één taak nuttig is, geef je in plaats daarvan een sleutelfunctie door:

def by_score(student):
    return student.score

ordered = sorted(students, key=by_score)
Geef nieuwe resultaten van rekenbewerkingen terug

Binnen een vectorklasse met de attributen x en y:

    def __add__(self, other):
        if not isinstance(other, Vector):
            return NotImplemented
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, factor):
        if not isinstance(factor, (int, float)):
            return NotImplemented
        return Vector(self.x * factor, self.y * factor)

    def __rmul__(self, factor):
        return self * factor

Vector(1, 2) + Vector(3, 4) levert een nieuwe vector (4, 6) op. Als je de eerste vector met 3 vermenigvuldigt, krijg je (3, 6) en blijft de oorspronkelijke vector ongewijzigd. __mul__ handelt de vector links af; __rmul__ ondersteunt een getal links. Python gaat er niet van uit dat de twee volgordes hetzelfde betekenen.

Lever een zinvolle lengte

Definieer voor een afspeellijst die self.songs opslaat __len__ om len(self.songs) terug te geven. Het resultaat moet een niet-negatief geheel getal zijn. len(playlist) telt dan de nummers. In deze klasse maakt lengte nul ook if playlist: onwaar; een zelf gedefinieerde __bool__ krijgt bij het toetsen van de waarheidswaarde voorrang op de lengte.

Belangrijkste punten

  • __eq__ definieert waardegelijkheid; geef NotImplemented terug voor niet-ondersteunde operandtypen.
  • Gelijke hashbare objecten hebben gelijke, stabiele hashes nodig.
  • __lt__ ondersteunt sorteren, maar levert geen <= of >=.
  • Gebruik een sleutelfunctie voor een sorteervolgorde die bij een specifieke taak hoort.
  • Rekenkundige methoden kunnen nieuwe objecten maken zonder de operanden te wijzigen.
  • __rmul__ ondersteunt vermenigvuldiging met het object rechts.
  • __len__ geeft een niet-negatief geheel getal terug en kan de waarheidsinterpretatie bepalen als __bool__ niet bestaat.
5

Bouw programma’s met samenwerkende objecten

Grotere programma’s verbinden objecten met verschillende taken. Een winkelwagen kan artikelen om subtotalen vragen; de ene rekening kan een andere vragen een storting te ontvangen. Volg de referenties en de volgorde van aanroepen, zodat je ziet welke toestand verandert en waar een fout de uitvoering stopt. Gebruik die ideeën daarna om een duidelijk ontwerp te kiezen, een kleine klasse te plannen en haar openbare gedrag in overzichtelijke stappen te testen.

5.1 Maak objecten die andere objecten bevatten

De attributen van een object kunnen naar andere objecten verwijzen. Een winkelwagen bevat artikelen, een bibliotheek bevat boeken en een cursus heeft cursisten. Compositie bouwt via deze heeft-een-relatie een groter object op uit kleinere objecten.

Geef elk object zijn eigen verantwoordelijkheid
class Item:
    def __init__(self, name, price, quantity):
        self.name = name
        self.price = price
        self.quantity = quantity

    def subtotal(self):
        return self.price * self.quantity

class ShoppingCart:
    def __init__(self):
        self.items = []

    def add(self, item):
        if not isinstance(item, Item):
            raise TypeError("a cart holds Item objects")
        self.items.append(item)

    def total(self):
        total = 0
        for item in self.items:
            total += item.subtotal()
        return total

De winkelwagen heeft een afzonderlijke lijst die tijdens de initialisatie wordt gemaakt. De methode add controleert het binnenkomende object voordat ze het toevoegt. cart.add("pen") werpt TypeError op in plaats van tekst op te slaan die tot een fout leidt wanneer een subtotaal wordt opgevraagd.

Maak de artikelen vóór of tijdens de aanroepen:

cart = ShoppingCart()
cart.add(Item("notebook", 2.50, 4))
cart.add(Item("pen", 1.25, 3))
print(cart.total())         # 13.75
print(cart.items[0].name)   # notebook

De subtotalen zijn 10.0 en 3.75; de winkelwagen telt ze op tot 13.75. De keten cart.items[0].name bereikt eerst de lijst van de winkelwagen, dan het eerste object daarin en daarna de naam van dat object.

Draag werk over aan het object dat het kent

De winkelwagen vraagt elk artikel om subtotal(). Dit is delegatie: één object roept voor een deel van een taak de methode van een ander object aan. Als een kwantumkorting verandert hoe een subtotaal wordt berekend, hoort die regel in Item.subtotal. De winkelwagen kan de teruggegeven subtotalen blijven optellen zonder prijsregels te herhalen.

Als je Item doorgeeft in plaats van Item(...), geef je de klasse door, geen gekocht artikel. De typecontrole wijst dat klasseobject af. Laat alle toevoegingen via de gecontroleerde route lopen; rechtstreekse toegang via cart.items.append(...) zou add omzeilen.

Zoek een object

Voeg deze methode toe binnen ShoppingCart:

    def find(self, name):
        for item in self.items:
            if item.name == name:
                return item
        return None

Bij de eerste overeenkomst wordt het bestaande artikel teruggegeven. Zonder overeenkomst wordt None teruggegeven. Controleer found is None voordat je found.name gebruikt; None heeft dat attribuut niet. Een methode __len__ die len(self.items) teruggeeft, kan er ook voor zorgen dat len(cart) de opgeslagen artikelobjecten telt, terwijl __str__ artikelregels kan samenvoegen tot een bon.

Volg referenties binnen collecties

Een lijst slaat referenties op, dus als je hetzelfde artikel in twee winkelwagens plaatst, wordt het niet gekopieerd. Een wijziging van de prijs van dat artikel beïnvloedt het volgende totaal dat beide winkelwagens berekenen. Afzonderlijke winkelwagenlijsten voorkomen dat de lijst onbedoeld wordt gedeeld, maar maken de objecten erin niet onafhankelijk. Maak afzonderlijke artikelen wanneer de winkelwagens onafhankelijke gegevens moeten bevatten.

Belangrijkste punten

  • Compositie slaat objecten op binnen een ander object.
  • Bij delegatie vraag je een opgenomen object om zijn deel van een taak uit te voeren.
  • Controleer een object voordat je het opslaat als latere methoden het type ervan nodig hebben.
  • Een zoekactie kan het overeenkomende object of None teruggeven.
  • Afzonderlijke containers kunnen nog steeds naar hetzelfde opgenomen object verwijzen.

5.2 Laat objecten samenwerken via methoden

Objecten kunnen net als getallen of strings argumenten en retourwaarden van methoden zijn. Volg het ontvangende object, de argumenten en het resultaat afzonderlijk: een methode kan een bestaand object wijzigen, een nieuw object teruggeven of alleen een waarde melden.

Gebruik een ander object als invoer

Binnen een puntklasse met x en y kan een methode beide punten lezen:

    def midpoint(self, other):
        return Point((self.x + other.x) / 2,
                     (self.y + other.y) / 2)

Voor p = Point(3, 4) en q = Point(1, 0) maakt middle = p.midpoint(q) een derde punt op (2.0, 2.0). Tijdens de aanroep verwijst self naar p en other naar q. De methode berekent coördinaten en maakt een nieuw punt; ze kent niets toe aan de oorspronkelijke punten.

Met import math kan een afstandsmethode math.hypot(self.x - other.x, self.y - other.y) teruggeven. Point(0, 0).distance_to(Point(3, 4)) geeft dan 5.0. Deze aanroep geeft een getal terug, terwijl midpoint een object teruggeeft.

Laat elk ontvangend object zijn wijzigingen beheren

Binnen een rekeningklasse met gecontroleerde methoden withdraw en deposit:

    def transfer_to(self, other, amount):
        self.withdraw(amount)
        other.deposit(amount)

Als Maya 100 heeft en Leo 20, neemt maya.transfer_to(leo, 30) eerst geld op van Maya, zodat 70 overblijft, en stort het daarna bij Leo, die dan 50 heeft. In de eerste aanroep is self Maya’s rekening. In de stortingsaanroep is de eigen self Leo’s rekening.

Een latere overboeking van 500 mislukt in withdraw, omdat Maya nog maar 70 heeft. De uitvoering stopt vóór deposit, dus beide saldi behouden hun eerdere waarden. De volgorde van de aanroepen is van belang. Python maakt een eerdere toestandswijziging niet ongedaan als een latere aanroep een exceptie opwerpt; deze korte methode hangt ervan af dat de ontvangende rekening het bedrag kan accepteren.

De aanroep other.deposit(amount) voert de regels van de ontvangende rekening op één plek uit. Als je other.balance rechtstreeks zou wijzigen, zou je die regels overslaan.

Volg de objecten, niet alleen de variabelenamen

Teken elke instantie als een vak met haar attributen. Teken een pijl van elke variabele naar het bijbehorende vak. Bepaal bij een aanroep welk vak self ontvangt en welke vakken als argumenten worden doorgegeven. Werk het betreffende vak bij na elke geslaagde regel die de toestand wijzigt. Twee pijlen naar één vak betekenen dat een wijziging via beide namen hetzelfde object bereikt.

Een gewone functie kan ook met meerdere objecten werken. total_balance(accounts) kan rekeningen doorlopen en hun saldi optellen. Die berekening over de hele lijst hoeft niet bij één rekening te horen.

Geef een ontbrekende relatie weer

Een boek kan beginnen met self.borrower = None en later een lidobject opslaan. Controleer de relatie voordat je een attribuut van het lid leest:

if book.borrower is not None:
    print(book.borrower.name)

Anders mislukt book.borrower.name wanneer het boek geen lener heeft. Klassen kunnen boven een functie main() worden gedefinieerd die de objecten maakt en verbindt. Door main() aan te roepen onder if __name__ == "__main__": voorkom je dat die acties worden uitgevoerd wanneer de klassen worden geïmporteerd.

Belangrijkste punten

  • Herken het ontvangende object als self en het objectargument als zijn eigen parameter.
  • Een methode kan een nieuw object teruggeven terwijl de invoer ongewijzigd blijft.
  • Aanroepen vinden op volgorde plaats; een exceptie stopt latere aanroepen, maar maakt eerdere wijzigingen niet ongedaan.
  • Gebruik de openbare methoden van een ander object om zijn regels toe te passen.
  • Controleer op None voordat je een optionele objectrelatie volgt.
  • Een functie kan berekeningen organiseren die meerdere objecten omvatten.

5.3 Bepaal wanneer een klasse een programma duidelijker maakt

Een klasse is op haar plaats wanneer samenhangende gegevens en herhaalde bewerkingen samen gemakkelijker te begrijpen zijn. Je hoeft niet elke functie of elk record in een klasse om te zetten. Kies de structuur die de verantwoordelijkheden van het programma duidelijk maakt.

Zoek gegevens en gedrag die samen voorkomen

Klassen helpen wanneer meerdere functies steeds dezelfde groep waarden ontvangen, veel records een structuur delen en toestandswijzigingen gemeenschappelijke regels moeten volgen. Meerdere rekeningen die allemaal stortingen en opnames ondersteunen, passen hier goed bij. Eén berekening kan een functie blijven. Een vast record dat alleen wordt gelezen, kan een tuple of dictionary blijven.

Een klasse met alleen inrichting en een eenmalige bewerking voegt vaak meer omslachtigheid dan nuttige structuur toe. Vraag je af wat één instantie voorstelt en welke terugkerende acties erbij horen. Als je die vragen niet eenvoudig kunt beantwoorden, heroverweeg dan het ontwerp.

Zet een bewerking bij haar gegevens

Een rekening met een dictionary kan zo beginnen:

account = {"owner": "Maya", "balance": 50}

def deposit(account, amount):
    account["balance"] += amount

De klasseversie kan dezelfde bewerking bij haar toestand en regels plaatsen:

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("deposit must be positive")
        self.balance += amount

    def __repr__(self):
        return f"BankAccount({self.owner!r}, {self.balance})"

Na acct = BankAccount("Maya", 50) en acct.deposit(25) is de representatie BankAccount('Maya', 75). De regel dat stortingen positief moeten zijn, wordt nu uitgevoerd telkens wanneer aanroepende code die methode gebruikt. Het lezen van account["balence"] zou KeyError opwerpen; het lezen van acct.balence werpt AttributeError op. Een klasse neemt spelfouten niet weg, maar geeft de gegevens en hun bewerkingen een plek met een naam.

Ontwerp op basis van een korte beschrijving

Bij “Een bibliotheek leent boeken uit aan leden. Een lid kan maximaal 3 boeken lenen” suggereren de zelfstandige naamwoorden Book, Member en Library. De werkwoorden suggereren methoden voor uitlenen en terugbrengen.

  1. Noteer wat elke instantie weet: de titel, auteur en lener van een boek; de naam en geleende boeken van een lid; de boeken en leden van een bibliotheek.
  2. Bepaal de regels: een boek mag niet al zijn uitgeleend en een lid mag MAX_LOANS = 3 niet overschrijden.
  3. Zet elke regel in de bewerking die de relatie wijzigt, zoals Library.check_out(book, member).
  4. Schrijf de initialisatie en een bruikbare representatie en voeg daarna steeds één actie toe en test die.

Verschillende titels hebben verschillende instanties van Book nodig, geen afzonderlijke klassen die naar elke titel zijn genoemd. Gebruik zelfstandige naamwoorden in het enkelvoud voor afzonderlijke objecten, zoals Book; noem een collectie naar de collectie, zoals Library. Houd de taak van elke klasse duidelijk genoeg om die in één zin te beschrijven.

Test waarneembaar gedrag
acct = BankAccount("Maya", 50)
acct.deposit(25)
assert acct.balance == 75

assert werpt AssertionError op als de voorwaarde onwaar is. Test ook afgewezen acties: vang de verwachte exceptie op en controleer dat de toestand niet is veranderd. Gebruik expliciete validatie met raise voor invoer van aanroepende code; asserties zijn controles tijdens de ontwikkeling en kunnen worden uitgeschakeld wanneer Python met optimalisatie wordt uitgevoerd.

Belangrijkste punten

  • Kies een klasse wanneer samenhangende toestand en terugkerende bewerkingen baat hebben bij één gezamenlijke plek.
  • Houd een eenvoudige berekening als functie wanneer geen blijvende objecttoestand nodig is.
  • Ontwerp attributen op basis van de gegevens en methoden op basis van de acties en regels.
  • Modelleer verschillende gegevenswaarden als instanties van één klasse.
  • Test zowel geslaagde updates als afgewezen wijzigingen.

Klassen en objecten in Python: voorbeelden

5 Walkthroughs

1

Van bekende waarden naar je eerste klasse

11 stappen
Volg methodeaanroepen en gedeelde referenties en maak daarna twee objecten met hun eigen attributen.
  1. 1
    IntroductieBegin met objecten die je kent

    Een lijst, een string en een getal zijn allemaal objecten. Hun typen bepalen welke bewerkingen ze ondersteunen en elke waarde heeft haar eigen identiteit.

    Begin met het volgen van een stringmethode en een lijstmethode. Gebruik daarna dezelfde ideeën om een eenvoudige klasse te maken waarvan de instanties verschillende gegevens opslaan. Blijf twee vragen stellen: welk object bereikt deze naam en wat geeft deze aanroep terug?

  2. 2
    VoorbeeldVraag het type van een waarde op

    Python kan je vertellen wat voor soort object een waarde is.

    text = "river"
    values = [4, 2]
    print(type(text))              # <class 'str'>
    print(isinstance(values, list))  # True
    

    De string en de lijst bieden verschillende methoden omdat ze verschillende typen hebben. Je kunt dir(values) gebruiken om de beschikbare namen op de lijst te bekijken, waaronder gewone en speciale methoden.

  3. 3
    VoorbeeldVolg een teruggegeven string

    Een stringmethode kan een nieuwe waarde opleveren zonder de oorspronkelijke waarde te vervangen.

    name = "robin"
    result = name.title()
    print(result)  # Robin
    print(name)    # robin
    

    title() geeft een nieuwe string terug. De toekenning slaat dat resultaat op onder result, terwijl name nog steeds naar "robin" verwijst. Als je name = name.title() zou schrijven, zou name naar de teruggegeven string verwijzen.

  4. 4
    VoorbeeldVolg een wijziging van een lijst ter plaatse

    Vergelijk de stringaanroep met het sorteren van een lijst.

    values = [4, 2]
    result = values.sort()
    print(values)  # [2, 4]
    print(result)  # None
    

    De lijst zelf verandert en de retourwaarde is None. Als je het resultaat van de aanroep opnieuw aan values zou toekennen, zou je de lijstreferentie van die naam vervangen door None. Gebruik alleen values.sort() wanneer je de bestaande lijst wilt wijzigen.

  5. 5
    UitdagingWaar verschijnt de toevoeging?

    Voorspel beide afgedrukte lijsten.

    a = [7]
    b = a
    c = [7]
    b.append(2)
    print(a, c)
    

    ---reveal---

    De uitvoer is [7, 2] [7]. a en b verwijzen naar één lijst, dus toevoegen via b wijzigt de lijst die via a zichtbaar is. c bevat een afzonderlijke lijst. De lijsten waren aanvankelijk gelijk, maar a is c was onwaar.

  6. 6
    TipTeken referenties voordat je wijzigingen volgt

    Teken één vak voor elke afzonderlijk gemaakte lijst. Laat zowel a als b naar het eerste vak wijzen en laat c naar het tweede wijzen. Toevoegen wijzigt het vak; een toekenning verandert waar een naam naar wijst.

    Maak ook onderscheid tussen een methode en haar aanroep: name.title geeft een methodeobject, terwijl name.title() het uitvoert. Ronde haakjes kunnen het verschil maken tussen gedrag vasthouden en het resultaat ervan verkrijgen.

  7. 7
    AnalogieEén formulier, meerdere ingevulde exemplaren

    Zie een klasse als een leeg formulier dat beschrijft welke informatie een bepaald soort object bevat. Een instantie is een ingevuld exemplaar met eigen gegevens.

    Een klasse Badge kan elke badge in een programma voorstellen. De ene instantie bevat de naam van een bezoeker; een andere bevat een andere naam. De klasse beschrijft het gemeenschappelijke soort object. Je hebt geen nieuwe klasse nodig voor elke waarde die op het formulier staat.

  8. 8
    VoorbeeldDefinieer het type en maak twee instanties

    Gebruik een minimale klasse terwijl je leert hoe instanties werken.

    class Badge:
        pass
    
    first = Badge()
    second = Badge()
    first.name = "Rae"
    second.name = "Ivo"
    

    pass levert een lege inhoud. Elke klasseaanroep maakt een instantie en de toekenningen met een punt slaan gegevens op het gekozen object op. first is second is onwaar. Met first = Badge zou je de klasse een andere naam geven zonder een instantie te maken.

  9. 9
    UitdagingZoek een verkeerd gespeld attribuut

    Ga verder met de twee badges:

    first.nmae = "Tess"
    print(first.name, second.name)
    

    Wat verschijnt er?

    ---reveal---

    De uitvoer is Rae Ivo. De toekenning maakt een afzonderlijk attribuut met de naam nmae; ze wijzigt name niet. Het lezen van een attribuut dat niet bestaat, werpt AttributeError op, maar een waarde toekennen aan een nieuwe naam is toegestaan. Controleer bij een onverwachte waarde de spelling bij het toekennen en het lezen.

  10. 10
    UitdagingCombineer instanties en aliassen

    Ga verder met first en second uit het badgevoorbeeld:

    copy_name = first
    copy_name.name = "Noor"
    print(first.name, second.name)
    

    ---reveal---

    De uitvoer is Noor Ivo. copy_name is een alias voor de eerste badge, dus de toekenning wijzigt dat object. De tweede badge blijft afzonderlijk. Door instanties te maken bepaal je hoeveel objecten er zijn; door namen toe te kennen bepaal je welke objecten die namen bereiken.

  11. 11
    SamenvattingVolg nog een programma op papier

    Probeer een kort programma met twee klasseaanroepen en een derde naam die aan de eerste instantie wordt toegekend. Geef de objecten verschillende attributen en wijzig er daarna één via de alias.

    Teken voordat je het uitvoert de objectvakken en voorspel elke leesactie. Als een voorspelling afwijkt van de uitvoer, bekijk dan de spelling van de attributen en de pijlen van namen naar objecten. Zo maak je onderscheid tussen een fout bij de inrichting en een referentiefout.

2

Maak objecten met betrouwbare begingegevens

14 stappen
Initialiseer een kleine takenverzameling, maak onderscheid tussen gedeelde instellingen en persoonlijke gegevens en wijs ongeldige inrichting af.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieRicht een takenverzameling in
  2. 2
    UitlegGeef Python een initialisatiemethode
  3. 3
    VoorbeeldKoppel een aanroep aan zijn parameters
  4. 4
    UitdagingHerken het ontbrekende attribuut
  5. 5
    VoorbeeldAccepteer een optionele beginlijst
  6. 6
    TipControleer hoever de kopie gaat
  7. 7
    UitlegVoeg gegevens over de klasse toe
  8. 8
    VoorbeeldVolg een toekenning die een waarde verhult
  9. 9
    UitdagingHerstel de gedeelde teller
  10. 10
    UitlegWijs een onbruikbaar maximum af
  11. 11
    VoorbeeldKies de fout en de herstelroute
  12. 12
    UitdagingWijst afdrukken de inrichting af?
  13. 13
    UitdagingBehoud het eerdere object bij een fout
  14. 14
    SamenvattingControleer de inrichting als aanroepende code
3

Beheer toestand via methoden en properties

16 stappen
Maak een voorraadobject met controles, volg een alias en bied gevalideerde toegang tot attributen.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieMaak een voorraadobject bruikbaar
  2. 2
    VoorbeeldBegin met een opgeslagen hoeveelheid
  3. 3
    UitlegLaat het ontvangende object self leveren
  4. 4
    UitdagingMaak een resultaat herbruikbaar
  5. 5
    VoorbeeldVoeg voorraad toe na controle van de hoeveelheid
  6. 6
    VoorbeeldWijs een verwijdering af vóór de aftrekking
  7. 7
    UitdagingVolg een wijziging via een alias
  8. 8
    VerbandKopieer de toestand op het juiste niveau
  9. 9
    UitlegMarkeer interne opslag
  10. 10
    VoorbeeldLees via een property
  11. 11
    VoorbeeldSta gecontroleerde openbare toekenning toe
  12. 12
    UitdagingVoorkom een recursieve setter
  13. 13
    KernpuntBereken een waarde wanneer die wordt gelezen
  14. 14
    UitdagingCombineer een setter met een alias
  15. 15
    TipLees de definitie en de aanroep samen
  16. 16
    SamenvattingTest steeds één bewerking
4

Laat objecten in Pythonexpressies passen

17 stappen
Geef een coördinatenpaar bruikbare weergaven, vergelijkingen, rekenbewerkingen en duidelijk ingebouwd gedrag.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieBepaal wat een object moet betekenen
  2. 2
    VoorbeeldBegin met een punt
  3. 3
    VoorbeeldVoeg tekst voor onderzoek toe
  4. 4
    UitdagingVoorspel de weergave van een lijst
  5. 5
    TipGeef in beide weergavemethoden tekst terug
  6. 6
    VoorbeeldVergelijk coördinaatwaarden
  7. 7
    KernpuntLaat niet-ondersteunde vergelijkingen aan Python over
  8. 8
    UitdagingKunnen gelijke paren in een verzameling?
  9. 9
    VoorbeeldKies een coördinatenordening
  10. 10
    VerbandEen volgorde kan bij één taak horen
  11. 11
    VoorbeeldTel op zonder de operanden te wijzigen
  12. 12
    VoorbeeldOndersteun beide volgordes van vermenigvuldiging
  13. 13
    UitdagingHoud een nieuw resultaat en een alias uit elkaar
  14. 14
    UitlegGebruik lengte voor een collectie
  15. 15
    UitdagingVoorspel de tak voor een lege wachtrij
  16. 16
    TipHoud de betekenis zichtbaar
  17. 17
    SamenvattingControleer elke expressie afzonderlijk
5

Verbind objecten met duidelijke taken

15 stappen
Bouw een kleine bestelling uit regelobjecten, volg gedeelde referenties en test een afgewezen bewerking.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieBouw een bestelling uit kleinere onderdelen
  2. 2
    VoorbeeldGeef één regel zijn eigen berekening
  3. 3
    VoorbeeldSla regels op in een bestelling
  4. 4
    VoorbeeldDraag elke kostenberekening over
  5. 5
    UitdagingVolg een regel die twee bestellingen delen
  6. 6
    TipControleer op een ontbrekend zoekresultaat
  7. 7
    UitlegGeef een object door aan een andere methode
  8. 8
    VoorbeeldVolg het ontvangende object en het resultaat
  9. 9
    UitdagingWaar stopt een mislukte combinatie?
  10. 10
    VerbandVolg aanroepen die twee objecten wijzigen
  11. 11
    UitlegBepaal welk gedrag bij elkaar hoort
  12. 12
    UitdagingVoorkom een klasse voor elk product
  13. 13
    VoorbeeldTest de gecontroleerde openbare methode
  14. 14
    UitdagingKies een test voor het gecombineerde ontwerp
  15. 15
    SamenvattingOntwerp zelf een kleine samenwerking

Klassen en objecten in Python: oefenvragen

50 Oefenvragen in 5 sets

Set 1: Samenwerkende objecten en duidelijke ontwerpen10 Oefenvragen

Vraag 1 van 10

Een Workshop slaat Tool-objecten op in self.tools. Wat leest workshop.tools[0].label?
  1. Het eigen label van de werkplaats.
  2. De labels van alle opgeslagen gereedschappen.
  3. Het label van het eerst opgeslagen gereedschap.
  4. Het aantal opgeslagen labels.
Toon antwoordVerberg antwoord
Antwoord: C
De expressie volgt de lijst tools van de werkplaats, selecteert het eerste element met index 0 en leest de label van dat gereedschap. Ze geeft dus het label van één gereedschap terug. Ze verzamelt niet elk label; de index selecteert één object vóór de laatste attribuutleesactie.

Vraag 2 van 10

Een winkelmand berekent zijn totaal door line.cost() aan te roepen op elke opgeslagen regel. Een kwantumkorting verandert hoe de kosten van elke regel worden berekend. Waar hoort die regel?
  1. In de initialisatie van de lijst van de winkelmand.
  2. In de methode cost van de regelklasse.
  3. In alle aanroepende code die een winkelmand afdrukt.
  4. In de lus van de winkelmand na elke aanroep.
Toon antwoordVerberg antwoord
Antwoord: B
De regel is al verantwoordelijk voor de berekening van zijn kosten, dus de kortingsregel hoort in cost. De winkelmand kan blijven delegeren en de teruggegeven waarden optellen. Kortingslogica toevoegen aan de lus van de winkelmand zou de verantwoordelijkheid verdubbelen en andere aanroepen van cost andere regels laten gebruiken.

Vraag 3 van 10

Welk totaal drukt de code af?

class Line:
    def __init__(self, rate, count):
        self.rate = rate
        self.count = count
    def cost(self):
        return self.rate * self.count
x = Line(4, 3)
a = [x]
b = [x, Line(2, 5)]
a[0].count = 6
print(sum(line.cost() for line in b))
  1. 22
  2. 34
  3. 24
  4. 28
Toon antwoordVerberg antwoord
Antwoord: B
Beide lijsten bevatten een referentie naar x, dus als je het aantal via a[0] wijzigt, worden de kosten 4 * 6, ofwel 24. De afzonderlijke regel in b kost 2 * 5, ofwel 10, samen 34. Het totaal 22 houdt het oude aantal aan en ziet de gedeelde referentie naar het element over het hoofd.

Vraag 4 van 10

De methode find(name) van een collectie geeft bij succes een object terug en bij een mislukte zoekactie None. Welke aanroepende code handelt beide gevallen af voordat result.name wordt gelezen?
  1. Lees result.name en controleer daarna result is None.
  2. Gebruik if result.name: voordat je de naam afdrukt.
  3. Gebruik if type(result) is None: voordat je leest.
  4. Gebruik if result is not None: voordat je leest.
Toon antwoordVerberg antwoord
Antwoord: D
Controleer het teruggegeven object zelf op None voordat je de attributen ervan volgt. Als je eerst result.name leest, mislukt dat al wanneer er geen overeenkomst is gevonden. De waarheidswaarde van de naam controleren lost dat probleem niet op, omdat je nog steeds een werkelijk resultaatobject nodig hebt om de naam te bereiken.

Vraag 5 van 10

Een methode Position.midpoint(other) geeft een nieuwe positie terug waarvan de coördinaten de gemiddelden zijn. Als a op (2, 8) ligt en b op (10, 4), wat is de situatie na c = a.midpoint(b)?
  1. c op (6, 6); a en b ongewijzigd.
  2. a op (6, 6); c verwijst naar a.
  3. b op (6, 6); c verwijst naar b.
  4. c op (12, 12); a en b ongewijzigd.
Toon antwoordVerberg antwoord
Antwoord: A
Middelen geeft de coördinaten (2 + 10) / 2 en (8 + 4) / 2, dus de nieuwe positie is (6, 6). De methode geeft een nieuw object terug en laat de oorspronkelijke objecten ongewijzigd. Coördinaten optellen zonder te delen zou (12, 12) opleveren, en dat is niet het midden.

Vraag 6 van 10

send_to(other, n) roept self.remove(n) aan en daarna other.add(n). remove wijst een hoeveelheid boven de voorraad van de verzender af voordat iets wordt gewijzigd; add accepteert positieve hoeveelheden. De voorraad van de verzender begint op 9 en die van de ontvanger op 4. Een overdracht van 3 slaagt, daarna wordt een overdracht van 8 geprobeerd en de exceptie opgevangen. Welke voorraden blijven over?
  1. Verzender 9, ontvanger 4.
  2. Verzender 6, ontvanger 15.
  3. Verzender 6, ontvanger 7.
  4. Verzender -2, ontvanger 15.
Toon antwoordVerberg antwoord
Antwoord: C
De eerste overdracht haalt 3 van 9 af en telt dat bij 4 op, zodat 6 en 7 overblijven. De tweede verwijdering wijst 8 af voordat de toestand verandert, dus de daaropvolgende toevoeging wordt niet uitgevoerd. Een voorraad van 15 bij de ontvanger gaat er ten onrechte van uit dat de uitvoering doorgaat naar add nadat de verwijdering een exceptie opwerpt.

Vraag 7 van 10

Een overdracht trekt voorraad af van de verzender en roept daarna de methode add van de ontvanger aan. De ontvanger wijst de hoeveelheid af voordat zijn eigen voorraad verandert. Er is geen code om wijzigingen terug te draaien en de aanroepende code vangt de exceptie op. Welke toestand blijft over?
  1. Verzender ongewijzigd; ontvanger ongewijzigd.
  2. Verzender verminderd; ontvanger ongewijzigd.
  3. Verzender verminderd; ontvanger vermeerderd.
  4. Verzender ongewijzigd; ontvanger vermeerderd.
Toon antwoordVerberg antwoord
Antwoord: B
De aftrekking bij de verzender slaagde voordat de ontvangende methode de hoeveelheid afwees, dus de voorraad van de verzender blijft verminderd. De ontvanger wees de hoeveelheid af voordat zijn eigen voorraad veranderde, dus die blijft ongewijzigd. Het opvangen van de exceptie maakt de eerdere aftrekking niet ongedaan.

Vraag 8 van 10

Een script zet één ingevoerde temperatuur om en drukt het resultaat één keer af. Het heeft geen opgeslagen toestand of terugkerend objectgedrag nodig. Welke structuur is het duidelijkst?
  1. Een klasse voor elke mogelijke temperatuur.
  2. Een klasse die elke rekenstap bevat.
  3. Meerdere objecten met een gedeeld resultaat.
  4. Een functie die de omgerekende waarde teruggeeft.
Toon antwoordVerberg antwoord
Antwoord: D
Een functie past bij één berekening zonder blijvende objecttoestand. Ze kan de temperatuur ontvangen en de omgerekende waarde rechtstreeks teruggeven. Als je de berekening in een klasse onderbrengt, voeg je inrichting en objectbeheer toe zonder dat dit script een bruikbare combinatie van toestand en terugkerend gedrag krijgt.

Vraag 9 van 10

Een verhuursysteem heeft veel fietsen. Elke fiets heeft een label en een beschikbaarheidstoestand, en dezelfde gecontroleerde acties voor verhuren en terugbrengen. Wat is een bruikbaar klassenontwerp?
  1. Eén klasse Bike met toestand en gecontroleerde methoden.
  2. Een klasse voor elk label met gekopieerde actiecode.
  3. Eén fietsobject met alle labels als aliassen.
  4. Een klasse die alleen print-instructies bevat.
Toon antwoordVerberg antwoord
Antwoord: A
De fietsen delen gedrag maar hebben een afzonderlijke toestand nodig, dus één klasse Bike kan attributen en gecontroleerde methoden voor verhuren en terugbrengen definiëren. Maak één instantie per fiets. Een klasse per label zou dezelfde actieregels herhalen, terwijl aliassen van één object één beschikbaarheidstoestand zouden delen.

Vraag 10 van 10

De plank moet een derde boek afwijzen en de twee bestaande boeken behouden. Welke assertie brengt na de hieronder opgevangen fout de onjuiste implementatie aan het licht?

class Shelf:
    def __init__(self):
        self.limit = 2
        self.books = []
    def add(self, title):
        self.books.append(title)
        if len(self.books) > self.limit:
            raise ValueError("shelf full")
shelf = Shelf()
shelf.add("Atlas")
shelf.add("Birch")
try:
    shelf.add("Cove")
except ValueError:
    pass
  1. assert len(shelf.books) == 3
  2. assert shelf.limit == 2
  3. assert len(shelf.books) == 2
  4. assert shelf.books[-1] == "Cove"
Toon antwoordVerberg antwoord
Antwoord: C
De methode voegt het derde boek toe voordat ze de capaciteit controleert, dus na de fout zijn drie boeken opgeslagen. Een assertie voor het vereiste aantal van twee mislukt en brengt de ongewenste wijziging aan het licht. Als je alleen de ongewijzigde grens controleert of het onjuiste resultaat met drie boeken bevestigt, slaagt de controle zonder betrouwbaar na te gaan of de toevoeging is afgewezen.
Set 2: Pas de ideeën toe in nieuwe situaties10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Wat geeft isinstance(items, list) terug voor een ingebouwde lijst items?
  1. Het aantal elementen in de lijst.
  2. De namen van de lijstmethoden.
  3. Het klasseobject met de naam list.
  4. De booleaanse waarde True.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Wat drukt deze code af?

class Tray:
    labels = []
a = Tray()
b = Tray()
a.labels.append("red")
b.labels = ["blue"]
Tray.labels.append("green")
print(a.labels, b.labels)
  1. ['red', 'green'] ['blue']
  2. ['red', 'green'] ['blue', 'green']
  3. ['red'] ['blue', 'green']
  4. ['blue', 'green'] ['blue', 'green']
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Wat drukt deze code af?

class Kit:
    def __init__(self, parts=None):
        self.parts = [] if parts is None else list(parts)
source = [[1]]
k = Kit(source)
source.append([2])
source[0].append(3)
print(k.parts)
  1. [[1]]
  2. [[1, 3], [2]]
  3. [[1, 3]]
  4. [[1], [2]]
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

De setter van een meter wijst negatieve waarden af voordat _reading wordt opgeslagen. De initialisatiemethode kent rechtstreeks toe aan self._reading, dus Meter(-2) slaagt. Door welke wijziging gebruikt het maken dezelfde controle als latere openbare toekenningen?
  1. Voeg een return-instructie toe aan de getter.
  2. Ken self.reading = reading toe in __init__.
  3. Ken self.reading = reading toe binnen de setter.
  4. Verwijder de property en houd _reading openbaar.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Een Key vergelijkt gelijkheid alleen op basis van name, en zijn hash gebruikt ook name. Twee verschillende instanties beginnen met de naam "north"; één wordt een dictionarysleutel. Waarom moet de naam van die sleutel stabiel blijven?
  1. Een naam wijzigen verandert de identiteit van beide objecten.
  2. Alle instantieattributen moeten in Python onwijzigbaar zijn.
  3. Dictionarysleutels worden bij invoeging automatisch gekopieerd.
  4. Een gewijzigde hash kan het opzoeken van de opgeslagen sleutel verhinderen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Twee clubs hebben elk een afzonderlijke lijst members, maar beide lijsten bevatten dezelfde instantie van Member. Eén club wijzigt de naam van dat lid. De clubs hebben nu onafhankelijke lidnamen nodig. Welke wijziging is nodig?
  1. Maak voor elke club een afzonderlijk lidobject.
  2. Kopieer alleen een van de buitenste lijsten members.
  3. Ken een andere variabele toe aan het gedeelde lid.
  4. Verplaats members naar de klasse-inhoud van de club.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Een berichtklasse heeft een bruikbare __str__, maar een afgedrukte lijst met berichten toont nog steeds standaardobjectbeschrijvingen. Welke toevoeging verbetert die lijstelementen?
  1. Een __len__ die de tekstlengte teruggeeft.
  2. Een __init__ die de tekstwaarde teruggeeft.
  3. Een __repr__ die bruikbare berichttekst teruggeeft.
  4. Een extra aanroep van print binnen __str__.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

a.combine(b) hoort beide invoerobjecten ongewijzigd te laten. De inhoud roept self.parts.extend(other.parts) aan en geeft daarna self terug. Welk gedrag heeft die implementatie daadwerkelijk?
  1. Ze maakt een nieuwe container met gekopieerde onderdelen.
  2. Ze wijzigt a en geeft datzelfde object terug.
  3. Ze wijzigt b en geeft datzelfde object terug.
  4. Ze laat beide ongewijzigd en geeft None terug.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Binnen class Vault kent de inrichting self.__code = "x" toe. Wat verklaart waarom vault.__code mislukt terwijl vault._Vault__code kan werken?
  1. De code wordt tijdens de initialisatie versleuteld.
  2. De lage streepjes maken de waarde een klasseattribuut.
  3. De getter wordt alleen met ronde haakjes aangeroepen.
  4. Naamvervorming verandert de opgeslagen attribuutnaam.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

De methode take van een klasse gebruikt assert n > 0 als enige controle op invoer van de aanroepende code. De regel moet ook gelden wanneer Python met optimalisatie is ingeschakeld. Welke wijziging is nodig?
  1. Geef het resultaat van de assertie terug aan de aanroepende code.
  2. Verplaats de assertie naar de aanroepende lus.
  3. Gebruik een expliciete voorwaarde die een exceptie opwerpt.
  4. Plaats de assertie na de wijziging van de toestand.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 3: Methoden, toestandswijzigingen en properties10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Welk argument levert Python als self wanneer het programma panel.area() aanroept?
  1. Het klasseobject Panel.
  2. Het object dat panel bevat.
  3. De waarde die area teruggeeft.
  4. Het eerste attribuut in panel.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Door welke wijziging kan de aanroepende code double berekenen?

class Pace:
    def __init__(self, minutes):
        self.minutes = minutes
    def seconds(self):
        print(self.minutes * 60)
p = Pace(3)
double = p.seconds() * 2
  1. Roep p.seconds aan zonder ronde haakjes.
  2. Geef p expliciet door aan p.seconds(p).
  3. Geef self terug uit de initialisatiemethode.
  4. Geef het product terug binnen seconds.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Een constructor vereist een lijst met meetwaarden en wijst elk ander type af voordat het wordt opgeslagen. Welke exceptie beschrijft het best dat aanroepende code de string "12,14" doorgeeft?
  1. TypeError
  2. ValueError
  3. AttributeError
  4. AssertionError
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Wat drukt deze code af?

class Tank:
    def __init__(self):
        self.level = 5
    def add(self, amount):
        self.level += amount
a = Tank()
b = a
result = b.add(4)
print(a.level, result)
  1. 5 None
  2. 9 9
  3. 9 None
  4. 5 9
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Wat drukt deze code af?

import copy
class Log:
    def __init__(self):
        self.entries = []
a = Log()
b = copy.copy(a)
b.entries.append("open")
b.entries = ["closed"]
print(a.entries, b.entries, a is b)
  1. [] ['closed'] False
  2. ['closed'] ['closed'] True
  3. ['open'] ['open'] False
  4. ['open'] ['closed'] False
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Een sessie wijst namen af die leeg zijn nadat spaties aan de randen zijn verwijderd. Welke inhoud van de initialisatiemethode handhaaft die regel voor name?
  1. if not name: raise ValueError("name required")

    self.name = name.strip()

  2. name = name.strip()

    if not name: raise ValueError("name required")

    self.name = name

  3. self.name = name.strip()

    if not name: raise ValueError("name required")

  4. if name == "": raise ValueError("name required")

    self.name = name

Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Waarom roept een toekenning aan reading.value deze setter herhaaldelijk aan?

class Reading:
    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, number):
        self.value = number
  1. De toekenning gebruikt opnieuw de propertynaam.
  2. De getter leest een andere attribuutnaam.
  3. De setter heeft een expliciete retourwaarde nodig.
  4. De decorator moet de klasse noemen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Een teller moet niet-negatief blijven. De methode remove(n) moet niet-positieve hoeveelheden en verwijderingen groter dan de huidige waarde afwijzen. Welke volgorde laat de toestand bij beide afwijzingen ongewijzigd?
  1. Trek n af; controleer het teken; controleer de nieuwe waarde.
  2. Controleer het teken; trek n af; controleer de nieuwe waarde.
  3. Controleer het teken; controleer de beschikbare waarde; trek n af.
  4. Controleer de beschikbare waarde; trek n af; controleer het teken.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Wat drukt deze code af?

class Dial:
    def __init__(self, value):
        self.value = value
    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, number):
        if not 0 <= number <= 9:
            raise ValueError("out of range")
        self._value = number
d = Dial(4)
try:
    d.value = 12
except ValueError:
    pass
print(d.value)
  1. 12
  2. 4
  3. 9
  4. None
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Een klasse berekent area met een alleen-lezenproperty uit width en height. Een object heeft breedte 6 en hoogte 2; daarna wordt aan de breedte 8 toegekend. Wat geeft het lezen van obj.area terug?
  1. 12
  2. 6
  3. 16
  4. 8
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 4: Leesbare weergaven en bruikbare operatoren10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Een klasse definieert zowel __str__ als __repr__. Welke methode levert de tekst van een instantie wanneer die in een afgedrukte lijst verschijnt?
  1. __str__
  2. __init__
  3. __len__
  4. __repr__
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Wat drukt deze code af?

class Tag:
    def __init__(self, text):
        self.text = text
    def __repr__(self):
        return f"Tag({self.text!r})"
t = Tag("ok")
print(t)
  1. Tag('ok')
  2. ok
  3. Tag(ok)
  4. 'ok'
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Waarom werpt str(marker) TypeError op wanneer de methode __str__ alleen print(self.code) aanroept?
  1. De methodenaam heeft te veel lage streepjes.
  2. De afgedrukte code moet enkele aanhalingstekens gebruiken.
  3. De methode geeft None terug in plaats van een string.
  4. De aanroepende code moet marker.__str__() rechtstreeks aanroepen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Een wijzigbare klasse Label definieert gelijkheid op basis van haar tekst en definieert geen __hash__. Twee labels bevatten dezelfde tekst. Wat gebeurt er als ze in een verzameling worden geplaatst?
  1. Ze vormen twee elementen omdat hun identiteit verschilt.
  2. Het maken van de verzameling geeft een fout voor een niet-hashbaar type.
  3. Ze vormen één element omdat hun tekst overeenkomt.
  4. Het maken van de verzameling zet hun tekst om in sleutels.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Een klasse Mark definieert alleen __lt__, die numerieke scores vergelijkt, en geen andere eigen vergelijkingen. Wat gebeurt er voor a met score 2 en b met score 7?
  1. a > b is onwaar; a <= b is waar.
  2. a > b werpt een exceptie op; a <= b is waar.
  3. a > b werpt een exceptie op; a <= b ook.
  4. a > b is onwaar; a <= b werpt een exceptie op.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Een Vector definieert __mul__ voor vector * number, maar geen methode voor gespiegelde vermenigvuldiging. Welke methode moet worden toegevoegd om ook number * vector te ondersteunen?
  1. __rmul__
  2. __add__
  3. __lt__
  4. __len__
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Een klasse definieert __eq__ met code en __hash__ als hash(self.code). Haar objecten worden gebruikt als dictionarysleutels. Welke ontwerpwijziging maakt het sleutelgedrag betrouwbaar?
  1. Wijzig de hash telkens wanneer een opzoeking mislukt.
  2. Gebruik id(self) als hash voor elk object.
  3. Houd code ongewijzigd zolang een object een sleutel is.
  4. Vergelijk identiteit en behoud de hash van de code.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Een klasse Queue definieert __len__ als het aantal wachtende taken en definieert geen __bool__. Wat zijn len(q) en bool(q) als er geen wachtende taken zijn?
  1. 0 en True
  2. 0 en False
  3. None en False
  4. 1 en True
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Wat drukt de laatste regel af?

class Offset:
    def __init__(self, value):
        self.value = value
    def __add__(self, other):
        return Offset(self.value + other.value)
a = Offset(6)
b = a
a = a + Offset(4)
print(a.value, b.value, a is b)
  1. 10 6 False
  2. 10 10 True
  3. 6 10 False
  4. 10 10 False
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Rank.__lt__ ordent records op prioriteit. Eén rapport moet die records in plaats daarvan op aanmaaktijd sorteren zonder hun gebruikelijke volgorde te veranderen. Welke aanpak past daarbij?
  1. Vervang __lt__ door een tijdvergelijking voor elk record.
  2. Geef elk record een nieuwe klasse voor de tijdvolgorde van het rapport.
  3. Verander eerst de prioriteit van elk record in de aanmaaktijd.
  4. Roep sorted aan met een sleutelfunctie die de aanmaaktijd teruggeeft.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 5: Objecten, referenties en betrouwbare inrichting10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Wat drukt deze code af?

a = [6, 2]
b = a
a = sorted(a)
b.append(9)
print(a, b)
  1. [2, 6] [6, 2, 9]
  2. [2, 6, 9] [2, 6, 9]
  3. [6, 2, 9] [2, 6]
  4. [2, 6] [2, 6, 9]
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Wat drukt deze code af?

label = "cedar"
label.upper()
print(label)
  1. Tekst in hoofdletters: CEDAR
  2. De waarde None
  3. Oorspronkelijke tekst: cedar
  4. Tekst met beginhoofdletter: Cedar
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Wat bevat first.name aan het einde?

class Badge:
    pass
first = Badge()
second = Badge()
first.name = "Rae"
second.name = "Ivo"
first.nmae = "Sol"
  1. "Sol"
  2. "Ivo"
  3. Geen waarde; de toekenning mislukt.
  4. "Rae"
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Een programma heeft drie sensoren nodig met verschillende labels, maar dezelfde methoden voor uitlezen en resetten. Hoe moeten de klassen en objecten worden ingericht?
  1. Eén sensorklasse per label, met elk één object.
  2. Eén sensorklasse, met drie afzonderlijke instanties.
  3. Eén sensorinstantie, met drie namen ervoor.
  4. Drie labelklassen, die één sensorinstantie delen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Wat drukt deze code af?

class Counter:
    def __init__(self, start=4):
        self.value = start
c = Counter(9)
print(c.value)
  1. 4
  2. 0
  3. 9
  4. None
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Waarom mislukt de laatste regel?

class Lamp:
    def __init__(self, brightness):
        brightness = brightness
lamp = Lamp(7)
print(lamp.brightness)
  1. De toekenning wijzigt alleen een lokale parameter.
  2. De klasseaanroep laat de parameter oningesteld.
  3. Het attribuut wordt op de klasse opgeslagen.
  4. De initialisatiemethode moet de helderheid teruggeven.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Wat drukt deze code af?

class Folder:
    def __init__(self, tags=[]):
        self.tags = tags
a = Folder()
b = Folder()
a.tags.append("urgent")
a.tags = []
print(b.tags, a.tags)
  1. [] []
  2. ['urgent'] ['urgent']
  3. [] ['urgent']
  4. ['urgent'] []
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Wat drukt deze code af?

class Ticket:
    fee = 3
x = Ticket()
y = Ticket()
x.fee = 8
Ticket.fee = 5
print(x.fee, y.fee)
  1. 5 5
  2. 8 5
  3. 8 3
  4. 3 5
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Wat drukt deze code af?

class Job:
    count = 0
    def __init__(self):
        self.count += 1
a = Job()
Job.count = 10
b = Job()
print(a.count, b.count, Job.count)
  1. 1 11 10
  2. 11 11 10
  3. 1 1 10
  4. 1 11 11
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Wat drukt deze code af?

class Batch:
    def __init__(self, size):
        if size <= 0:
            raise ValueError("size must be positive")
        self.size = size
batch = Batch(6)
try:
    batch = Batch(0)
except ValueError:
    pass
print(batch.size)
  1. 0
  2. None
  3. 6
  4. ValueError
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Kom je niet uit je eigen opgave? Huiswerkhulp

Kernbegrippen

62 Kernbegrippen, elk met een definitie

A

alias
Een alias is een andere naam die naar een bestaand object verwijst, zodat wijzigingen aan een gedeeld wijzigbaar object via beide namen zichtbaar zijn.
Na backup = entries wijzigt toevoegen via backup ook de lijst die via entries wordt bereikt.
assertie
Een assertie is een ontwikkelcontrole die AssertionError opwerpt als haar voorwaarde onwaar is; Python kan die bij uitvoering met optimalisatie weglaten.
Na een storting controleert assert acct.balance == 75 het gedrag; afgewezen invoer van aanroepende code heeft nog steeds expliciete validatie nodig.
attribuut
Een attribuut is een benoemde waarde die je via een object of klasse met puntnotatie bereikt, zoals de opgeslagen titel van een boek.
De toekenning book.title = "Emma" slaat een titel op, die je daarna kunt lezen door book.title te evalueren.
attribuutopzoeking
Attribuutopzoeking is het proces waarbij een benoemd attribuut wordt gevonden; gewone instantiegegevens kunnen vóór een klassewaarde worden gevonden.
Als p geen eigen limit heeft, kan het lezen van p.limit de gedeelde waarde limit vinden die op de klasse is gedefinieerd.

C

compositie
Compositie bouwt een groter object op uit andere objecten die in zijn attributen of collecties zijn opgeslagen en modelleert zo een heeft-een-relatie.
Een bibliotheek kan boekobjecten opslaan, waarbij elk boek zijn titel en informatie over de huidige lener bewaart.
container
Een container is een object dat referenties naar andere objecten bevat, zodat die samen kunnen worden opgeslagen en verwerkt.
De artikelenlijst van een winkelwagen bevat artikelobjecten; via cart.items[0] bereik je het eerste opgeslagen artikel.

D

delegatie
Delegatie draagt een deel van een taak over aan de methode van een ander object, zodat dat object de regels voor zijn eigen gegevens toepast.
Een winkelwagen draagt elk subtotaal over aan het bijbehorende artikel en telt daarna de teruggegeven bedragen op tot het winkelwagentotaal.
diepe kopie
Een diepe kopie kopieert een object en zijn geneste objecten en scheidt zo geneste wijzigbare toestand die bij een ondiepe kopie gedeeld kan blijven.
Als een rekening een transactielijst opslaat, wordt met copy.deepcopy(account) ook die lijst gekopieerd, zodat toevoegen aan de geschiedenis van de kopie het origineel ongemoeid laat.

G

gebonden methode
Een gebonden methode is een methodeobject dat zowel de functie als de instantie onthoudt die bij de aanroep van de methode wordt geleverd.
r.area levert een gebonden methode; als je ronde haakjes toevoegt zoals in r.area(), wordt die uitgevoerd en de berekende oppervlakte teruggegeven.
gedragstest
Een gedragstest maakt objecten, voert een actie uit en controleert een waarneembaar resultaat, inclusief toestand die na afgewezen invoer behouden blijft.
Een opnametest vangt de verwachte fout op en controleert of het saldo en de transactiegeschiedenis nog overeenkomen met hun eerdere waarden.
gespiegelde bewerking
Een gespiegelde bewerking laat de rechteroperand een bewerking afhandelen wanneer de linkeroperand het paar niet kan ondersteunen.
Voor 3 * vector kan Python de __rmul__ van de vector gebruiken wanneer vermenigvuldiging van gehele getallen die vector niet kan verwerken.

H

hashbaarheid
Hashbaarheid maakt het mogelijk dat een object als element van een verzameling of als dictionarysleutel dient, met een stabiele hash die overeenstemt met de gelijkheidsregel.
Een klasse die __eq__ zonder __hash__ definieert, wordt niet-hashbaar, ook als haar instanties in een lijst werken.

I

identiteit
Identiteit onderscheidt één object van elk ander object; de operator is toetst of twee referenties hetzelfde object bereiken.
Twee afzonderlijk gemaakte lijsten kunnen voldoen aan a == b terwijl a is b onwaar is, omdat hun identiteit verschilt.
initialisatie
Initialisatie stelt de begintoestand van een nieuw gemaakt object in, meestal door argumenten en beginwaarden als attributen op te slaan.
Een initialisatiemethode voor een rekening kan de eigenaar opslaan, een beginsaldo accepteren en een lege transactielijst maken.
inkapseling
Inkapseling houdt de gegevens van een object en het gedrag dat die beheert bij elkaar en geeft aanroepende code een duidelijke interface voor geldige wijzigingen.
De stortingsmethode van een rekening controleert het bedrag en werkt de interne opslag bij zonder dat aanroepende code de regel herhaalt.
instantie
Een instantie is één object dat bij een klasse hoort en de specifieke toestand van dat object bevat.
De aanroepen Book() en Book() maken twee afzonderlijke boekinstanties, ook al hebben beide hetzelfde type.
instantieattribuut
Een instantieattribuut wordt op één specifiek object opgeslagen en geeft die instantie eigen gegevens onder de naam van het attribuut.
Twee pizza’s kunnen elk een andere size en een afzonderlijke lijst met beleg opslaan via toekenningen op self.
instantiemethode
Een instantiemethode is een functie die in een klasse is gedefinieerd en het object ontvangt waarop ze is aangeroepen, volgens conventie via haar eerste parameter self.
Bij r.area() levert Python r aan de methode, zodat die de breedte en hoogte van die rechthoek kan vermenigvuldigen.
intern attribuut
Een intern attribuut is bedoeld voor gebruik binnen de implementatie van een klasse, wat meestal wordt aangegeven met één laag streepje aan het begin van de naam.
In een rekeningklasse leest aanroepende code een openbare property balance, terwijl de eigen methoden van de klasse de opgeslagen _balance beheren.
invariant
Een invariant is een regel die waar moet blijven om de toestand van een object geldig te laten zijn, ook na geslaagde wijzigingen.
Een scoreklasse kan vereisen dat elke score tijdens de inrichting en bij latere toekenningen tussen 0 en 100 blijft.

K

klasse
Een klasse definieert een Pythontype en biedt een gemeenschappelijke definitie voor de attributen en het gedrag van haar instanties.
Eén klasse Book kan veel boeken maken, die elk een andere titel opslaan en dezelfde methodedefinities delen.
klasseattribuut
Een klasseattribuut wordt op de klasse opgeslagen en kan worden gevonden door instanties die geen verhullend attribuut met dezelfde naam hebben.
Een instelling MAX_TOPPINGS voor de hele klasse kan de standaardgrens leveren die via veel verschillende pizzaobjecten wordt gelezen.
klassenontwerp
Klassenontwerp kiest de typen, toestand, acties en geldigheidsregels die nodig zijn om een probleem duidelijk met samenwerkende objecten te modelleren.
Het ontwerpen van een bibliotheek begint met boeken en leden en plaatst daarna een uitleengrens in een uitleenbewerking.

M

methode
Een methode is een functie die een klasse biedt en die op een object kan worden aangeroepen om met dat object of zijn gegevens te werken.
De aanroep "cedar".upper() voert een stringmethode uit, terwijl scores.append(7) een methode op een lijst uitvoert.

N

naamverhulling
Naamverhulling treedt op wanneer een eigen gewoon gegevensattribuut van een instantie bij het opzoeken een klasseattribuut met dezelfde naam verbergt.
Na p.limit = 8 vervangt een wijziging van Pizza.limit niet de afzonderlijke grens die al op p is opgeslagen.
naamvervorming
Naamvervorming herschrijft namen in een klasse-inhoud met twee lage streepjes aan het begin en zonder dubbele lage streepjes aan het einde, zodat de klassenaam erin wordt opgenomen.
Binnen Acc wordt self.__balance _Acc__balance, dat toegankelijk blijft onder de vervormde naam.
None
None is de unieke Pythonwaarde voor een ontbrekend of niet-beschikbaar resultaat en is ook bruikbaar voor een relatie waaraan nog geen object is toegekend.
Een boek kan borrower = None opslaan totdat een lid het leent, zodat code controleert voordat ze de naam van een lener leest.
NotImplemented
NotImplemented is een speciale retourwaarde die aangeeft dat een vergelijkings- of numerieke methode de opgegeven operanden niet ondersteunt.
De gelijkheidsmethode van een punt kan NotImplemented teruggeven voor een string, zodat Python het niet-ondersteunde paar afhandelt.

O

object
Een object is een Pythonwaarde met een identiteit, een type en een toestand, samen met de bewerkingen die het type ondersteunt.
De string "hello" en de lijst [2, 5] zijn beide objecten, al bieden hun typen verschillende bewerkingen.
objectargument
Een objectargument geeft een referentie naar een instantie door aan een functie of methode, zodat de aangeroepen code dat object kan gebruiken.
De parameter other in p.midpoint(q) verwijst naar q, waarvan de methode de coördinaten leest om haar resultaat te berekenen.
ondiepe kopie
Een ondiepe kopie maakt een nieuw buitenste object terwijl referenties naar de bestaande geneste objecten behouden blijven, zodat die gedeeld kunnen blijven.
Als een rekening een transactielijst opslaat, kan de rekening die met copy.copy(account) is gemaakt die lijst nog steeds delen met het origineel.
ontvangend object
Het ontvangende object is het object vóór de punt in een instantiemethodeaanroep, dat automatisch als het self-argument van de methode wordt doorgegeven.
In sender.transfer_to(receiver, 5) ontvangt sender de overdrachtsaanroep; het rekeningargument is de bestemming.
operatoroverloading
Operatoroverloading definieert wat een operator voor een klasse betekent door de speciale methode te implementeren die bij die bewerking hoort.
De __add__ van een vector kan a + b een nieuwe vector laten opleveren door de overeenkomstige coördinaten op te tellen.
opslagattribuut
Een opslagattribuut bewaart de waarde die een property beheert onder een afzonderlijke naam en voorkomt zo recursieve toegang tot de property.
Een getter voor score leest _score; als je binnen de eigen setter aan score zou toekennen, zou die setter herhaaldelijk worden aangeroepen.

P

property
Een property biedt door methoden beheerste toegang via attribuutsyntaxis, zodat een leesactie een resultaat kan berekenen of een toekenning controles kan uitvoeren.
Het lezen van student.score kan een getter aanroepen en de toekenning student.score = 90 kan een validerende setter aanroepen.
puntnotatie
Puntnotatie is de syntaxis die een punt plaatst tussen een object of klasse en de naam van een attribuut dat wordt benaderd.
In cart.items geeft de naam vóór de punt het object aan en selecteert de naam erna het attribuut met artikelen.

R

referentie
Een referentie verbindt een naam of opgeslagen waarde met een object, zodat meerdere namen of containers hetzelfde object kunnen bereiken.
Als je één artikel in twee winkelwagenlijsten plaatst, wordt dat artikel gedeeld, zodat een wijziging van de prijs beide berekende totalen kan beïnvloeden.
representatie voor programmeurs
Een representatie voor programmeurs is de ondubbelzinnige tekst die __repr__ teruggeeft en die wordt gebruikt bij onderzoek en in containerweergaven.
De representatie van een boek kan "Book('Emma', 'Jane Austen', 1815)" tonen, inclusief tekstvelden tussen aanhalingstekens.
retourwaarde
Een retourwaarde is het object dat een aanroep aan de omringende expressie levert en dat beschikbaar is voor toekenning, berekening of toetsing.
Door de oppervlakte terug te geven kan r1.area() + r2.area() resultaten optellen, terwijl alleen afdrukken None als elk resultaat overlaat.

S

self
De parameter self ontvangt volgens conventie de huidige instantie, zodat een methode de attributen van dat object kan lezen of wijzigen.
In self.owner = owner slaat de linkerkant gegevens op de instantie op en leest de rechterkant een lokale parameter.
setter
Een setter is de methode die wordt aangeroepen door een toekenning aan een property en die de voorgestelde waarde vaak valideert voordat ze afzonderlijk wordt opgeslagen.
Een setter van score die 105 afwijst voordat aan _score wordt toegekend, laat een eerdere geldige score ongewijzigd.
sleutelfunctie
Een sleutelfunctie haalt voor elk element de waarde op die een sorteerbewerking moet vergelijken en kiest zo een volgorde voor die specifieke taak.
Een rapport kan sorted(records, key=by_date) aanroepen zonder de gebruikelijke vergelijkingsmethode van de recordklasse te veranderen.
speciale methode
Een speciale methode heeft een naam met twee lage streepjes aan elke kant en levert gedrag voor Pythonsyntaxis of ingebouwde bewerkingen.
Python vraagt __str__ op bij het omzetten van een object naar zijn leesbare stringvorm en __len__ voor zijn lengte.
standaardargument
Een standaardargument is een waarde die wordt gebruikt wanneer aanroepende code een argument voor een parameter weglaat en die wordt geëvalueerd wanneer de functie of methode wordt gedefinieerd.
Met balance=0 in de initialisatiemethode begint Account("Rae") met nul zonder dat een saldoargument wordt doorgegeven.
stringrepresentatie
Een stringrepresentatie is de leesbare tekst die __str__ teruggeeft en die normaal gesproken bedoeld is voor gebruikers van het programma.
Een punt kan bij rechtstreeks afdrukken worden weergegeven als "(3, 4)", terwijl zijn numerieke coördinaatattributen ongewijzigd blijven.

T

terugval op de representatie voor programmeurs
De terugval op de representatie voor programmeurs laat de standaardstringconversie een eigen __repr__ gebruiken wanneer een klasse geen eigen __str__ definieert.
Alleen __repr__ toevoegen kan zowel print(point) als de weergave van het punt binnen een afgedrukte lijst verbeteren.
toestand
De toestand van een object bestaat uit de huidige gegevens in zijn attributen, die methoden tijdens de uitvoering van het programma kunnen bekijken en bijwerken.
Na een geaccepteerde storting op een rekening die een geschiedenis bijhoudt, omvat de toestand van de rekening zowel het nieuwe saldo als de toegevoegde regel in de transactiegeschiedenis.
type
Een type is de klasse van een object, die bepaalt welke bewerkingen het ondersteunt en hoe waarden van die soort zich gedragen.
type([2, 5]) geeft de klasse list terug en isinstance([2, 5], list) bevestigt dat de waarde een lijst is.
TypeError
Een TypeError meldt dat een bewerking een ongeschikt type heeft ontvangen of is aangeroepen met argumenten die haar definitie niet accepteert.
Tekst doorgeven aan een numerieke breedtevergelijking werpt TypeError op, omdat die vergelijking tekst en nul niet kan ordenen.

U

uitleesmethode
Een uitleesmethode is een methode die informatie geeft over de toestand van een object zonder die toestand bewust te wijzigen.
De uitleesmethode area() van een rechthoek leest de breedte en hoogte en geeft een getal terug zonder de afmetingen te wijzigen.

V

validatie
Validatie controleert of binnenkomende gegevens of een gevraagde wijziging voldoen aan de regels die een klasse stelt, voordat ze worden geaccepteerd.
Een rechthoek valideert een numerieke breedte door nul of negatieve waarden af te wijzen voordat de afmeting wordt opgeslagen.
ValueError
Een ValueError meldt dat een argument een aanvaardbaar type heeft, maar dat de waarde buiten wat de bewerking accepteert valt.
Een numerieke breedte van -2 kan ValueError opwerpen met de melding "width must be positive".
verantwoordelijkheid
De verantwoordelijkheid van een klasse is de duidelijke taak die haar gegevens en methoden dienen en die helpt bepalen welk gedrag bij elkaar hoort.
Een artikel berekent zijn eigen subtotaal, terwijl een winkelwagen artikelen organiseert en die subtotalen optelt tot een totaal.
voorwaarde voor directe uitvoering
Een voorwaarde voor directe uitvoering controleert of een module rechtstreeks wordt uitgevoerd en voorkomt dat opstartacties worden uitgevoerd wanneer de module wordt geïmporteerd.
Plaats main() onder if __name__ == "__main__": zodat een ander programma de klassen kan importeren zonder het programma te starten.

W

waardegelijkheid
Waardegelijkheid vergelijkt objecten op basis van betekenisvolle gegevens, meestal gedefinieerd met __eq__, zonder dezelfde objectidentiteit te vereisen.
Twee afzonderlijke punten met dezelfde coördinaten kunnen gelijk zijn bij vergelijking en overeenkomen bij een lidmaatschapscontrole in een lijst.
waarheidsinterpretatie
Waarheidsinterpretatie is de booleaanse interpretatie van een object in een voorwaarde; zonder __bool__ maakt een gedefinieerde lengte nul het object onwaar.
Een lege afspeellijst met __len__ en zonder eigen __bool__ zorgt ervoor dat if playlist: zijn inhoud overslaat.
wijzigbaarheid
Wijzigbaarheid is het vermogen van een object om zijn inhoud te veranderen terwijl het hetzelfde object met dezelfde identiteit blijft.
Als je iets aan een lijst toevoegt, verandert de bestaande lijst; als je upper() op een string toepast, krijg je een nieuwe string terug.
wijzigbare standaardwaarde
Een wijzigbare standaardwaarde is een wijzigbaar standaardobject dat bij meerdere aanroepen kan worden hergebruikt en bij opslaan of wijzigen tot onbedoeld delen kan leiden.
Als items=[] rechtstreeks wordt opgeslagen, kunnen twee objecten die zonder dat argument zijn gemaakt naar dezelfde lijst verwijzen.
wijzigingsmethode
Een wijzigingsmethode is een methode die de toestand van een bestaand object verandert en vaak invoer controleert voordat samenhangende attributen worden bijgewerkt.
Een gecontroleerde wijzigingsmethode voor opnames kan het saldo verlagen en een transactie vastleggen nadat het bedrag de validatie heeft doorstaan.

Z

zoekresultaat
Een zoekresultaat kan het bestaande overeenkomende object zijn of een speciale waarde zoals None, die aangeeft dat geen overeenkomst is gevonden.
De aanroepende code controleert found is not None voordat ze found.name leest uit een zoekactie naar een artikel in een winkelwagen.

#

__init__
De methode __init__ initialiseert een instantie nadat Python die heeft gemaakt en moet None teruggeven wanneer de initialisatie is voltooid.
De aanroep Counter(5) geeft de nieuwe instantie en 5 door aan de initialisatiemethode voordat de ingerichte teller wordt teruggegeven.
__lt__
De methode __lt__ implementeert de vergelijking kleiner dan en levert een ordening die bewerkingen zoals sorted kunnen gebruiken.
Een __lt__ op basis van scores laat een lijst met studentobjecten sorteren van de laagste naar de hoogste score.

Over deze les

Door StudeliFout melden

Maak je eigen Studiemateriaal

Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.

Aan de slag