コンテンツにスキップ

singleton-pattern-dependency

Category: Dependency Injection
Severity: Warning
Triggered by: pyscn analyze, pyscn check --select di

What it does

Flags a class that implements the singleton pattern by caching itself on a class-level _instance attribute.

Why is this a problem?

A singleton is global state wearing a class-shaped costume. Every caller that writes PaymentGateway.instance() depends on the one object the class chooses to return, and that object survives across tests unless each test remembers to reset it. One forgetful test and the next one inherits stale state.

Because the singleton decides its own lifetime, callers can't give it different collaborators in different contexts — a second configuration, a fake for tests, a per-tenant instance. Substitution requires reaching into the class and resetting _instance, which is exactly the coupling the singleton was supposed to hide.

The pattern also obscures real dependencies: reading the code of a method that calls X.instance() tells you nothing about what X needs or where it was configured.

Example

class PaymentGateway:
    _instance = None

    @classmethod
    def instance(cls):
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance

    def charge(self, order):
        ...

Use instead

Construct the object once at the edge of the application and pass it to whatever needs it.

class PaymentGateway:
    def charge(self, order):
        ...

# wiring, done once at startup
gateway = PaymentGateway()
order_service = OrderService(gateway)

Options

Option Default Description
di.enabled false Must be true for analyze to run DI rules.
di.min_severity "warning" Raise to "error" to suppress this rule.

References