ProgrammatieSenior Python ontwikkelaar

Hoe werkt de __new__ methode in Python en wat is het verschil met __init__? Wanneer en waarom zou je __new__ moeten overschrijven in plaats van __init__? Geef een gedetailleerd voorbeeld van gebruik.

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

In Python is het aanmaken van een object van een klasse een proces in twee stappen:

  1. Eerst wordt de statische methode __new__ aangeroepen, die verantwoordelijk is voor het toewijzen en retourneren van een nieuw exemplaar van de klasse (instantie).
  2. Vervolgens wordt __init__ aangeroepen, die het reeds aangemaakte object initialiseert.

Verschillen:

  • __new__ — creatie (kan elk nieuw object retourneren; verplichte parameter — de klasse).
  • __init__ — initialisatie (werkt met self, het al toegewezen exemplaar).
  • Gewoonlijk wordt __new__ overschreven voor afgeleiden van onveranderlijke types (tuple, str, int), het maken van singletons en het "factory" patroon.

Voorbeeld van gebruik:

class MyStr(str): def __new__(cls, value): print("__new__ aangeroepen") instance = super().__new__(cls, value.upper()) # waarde veranderen vóór creatie return instance def __init__(self, value): print("__init__ aangeroepen", value) s = MyStr('abc') # __new__ aangeroepen -> __init__ aangeroepen abc print(s) # 'ABC'

Een vraag met een twist.

Kan je een onveranderlijk object initialiseren via __init__, als er in de klasse geen __new__ is geïmplementeerd?

Antwoord met voorbeeld:

Nee! Bijvoorbeeld, voor onveranderlijke types (zoals bij str, int, tuple) moeten alle wijzigingen aan velden/waarde in __new__ gebeuren, anders is het in __init__ niet mogelijk om de waarde te wijzigen.

class MyTuple(tuple): def __init__(self, items): print(f'__init__! {items}') def __new__(cls, items): print(f'__new__! {items}') return super().__new__(cls, map(str, items)) t = MyTuple([1, 2, 3]) print(t) # ('1', '2', '3')

Voorbeelden van echte fouten door gebrek aan kennis over de nuances van het onderwerp


Verhaal

In een groot Django-project werd er erfelijkheid van str geïmplementeerd voor het opslaan van speciale typen strings. Ze probeerden de waarde te wijzigen in __init__ — maar het resultaat veranderde niet, omdat str onveranderlijk is. Dit werd pas opgelost na studie en het overschrijven van __new__.


Verhaal

Bij de implementatie van het Singleton patroon vergaten ze de logica voor het retourneren van het bestaande exemplaar in __new__: meerdere aanroepen van de klasse maakten nog steeds nieuwe objecten aan, wat leidde tot geheugenfragmentatie.


Verhaal

In een bibliotheek voor gegevensserialisatie hebben ze bij het cachen een klasse gebruikt met een overschreven __init__, maar ze verzuimden te beseffen dat voor caching het nodig is om precies hetzelfde object te retourneren via __new__. Hierdoor faalde de cache bij elke nieuwe aanroep, omdat er verschillende objecten werden aangemaakt.