Courseiva
Question 8 of 169
Object-Oriented ProgrammingeasyMultiple ChoiceObjective-mapped

PCAP Object-Oriented Programming Practice Question

A junior developer writes a class 'Logger' that should only ever have one instance (singleton). They attempt to implement it by overriding __new__ to always return the same instance. However, when multiple threads attempt to create a Logger, they sometimes get different instances. Which modification will make the singleton thread-safe?

⚠ Common exam trap

Python Institute often tests the misconception that simply overriding `__new__` or using a class method is sufficient for thread safety, when in fact the race condition in the check-then-create pattern requires explicit synchronization like a lock.

Answer choices

Why each option matters

Answer the question above first, then reveal the full breakdown to understand why each option is right or wrong.

Correct answer & explanation

Use a lock (threading.Lock) in __new__ to serialize access

The race condition occurs when multiple threads simultaneously check `cls._instance` and find it `None`, then both proceed to create a new instance. Wrapping the creation logic inside a `threading.Lock` in `__new__` ensures that only one thread can execute the critical section at a time, guaranteeing that only one instance is ever created.

Answer analysis

Option-by-option breakdown

For each option: why learners choose it and why it is or isn't the right answer here.

  • Use a lock (threading.Lock) in __new__ to serialize access

    Why this is correct

    Acquiring a threading.Lock inside __new__ before checking and assigning the class-level singleton reference serializes the critical section, so concurrent threads cannot both observe a None value and proceed to construct separate instances. Without this lock, even with CPython's GIL, a thread can be suspended between the check and the assignment, allowing another thread to create a second instance. This approach directly addresses the race condition at the point where the object is actually allocated and published.

  • Use a class method get_instance() that checks a class variable and creates the instance if needed, and call that from __init__

    Why it's wrong here

    This approach conflates two creation paths: __init__ always runs on an object already returned by __new__, so calling get_instance() from inside __init__ cannot replace that newly allocated object with the singleton reference. The class-method pattern only works when get_instance() is the exclusive factory, but this option still lacks a lock, so two threads can both see the class variable as None and both create instances before either assignment completes. Because __init__ has no return value and cannot veto the existing instance, the design fails to enforce the singleton invariant.

  • Use a metaclass that overrides __call__ to return the singleton

    Why it's wrong here

    A metaclass overriding __call__ is a valid way to intercept construction and return a cached instance, but doing so without a lock reproduces the same race condition: two threads can both pass the `if instance is None` check and each invoke __new__ and __init__ to create distinct objects. The metaclass hook runs before __new__, making it a potentially correct synchronization point, but merely overriding __call__ provides no mutual exclusion. The absence of synchronization still permits multiple instances when threads are preempted between the check and the assignment.

  • Override __init__ to check if the instance was already initialized and if so, skip initialization

    Why it's wrong here

    This change addresses only the initialization state of a single object, not the multiplicity of objects created by __new__. Every call to the class still allocates a fresh instance in memory, and the __init__ guard merely skips resetting attributes on subsequent initialization calls; it never returns the original instance to the caller. As a result, callers receive new, uninitialized (or partially initialized) objects that violate the singleton guarantee, and this becomes especially dangerous if the skipped initialization leaves required state missing.

About these practice questions

Courseiva creates original exam-style practice questions with explanations and wrong-answer analysis. It does not publish real exam questions, exam dumps, or protected exam content. Learn why practice questions differ from exam dumps →

How Courseiva writes practice questions · Editorial policy

Last reviewed: Jun 30, 2026

Question Discussion

Share a tip, memory trick, or ask about the reasoning behind this question. Do not post real exam questions, leaked content, braindumps, or copyrighted exam material. Comments are moderated and may be removed without notice.

Loading comments…

Sign in to join the discussion.

This PCAP practice question is part of Courseiva's free Python Institute certification practice question bank. Courseiva provides original exam-style practice questions with explanations, topic-based practice, mock exams, readiness tracking, and study analytics to help learners prepare for the PCAP exam.