Instance attribute attribute_name defined outside __init__
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Defining an instance attribute outside __init__ is legal Python, but static analyzers often warn about it because it makes object state less explicit. The real issue is not syntax. The real issue is whether the class clearly communicates which attributes are guaranteed to exist and which ones appear only after particular methods run.
Why Linters Warn About This Pattern
Consider a class like this:
This code works, but it does not guarantee that token exists right after construction. If some other method expects self.token to exist before authenticate has been called, the class can fail depending on call order.
That is why linters complain. They are pointing out that the object's shape depends on execution history rather than on a clear constructor-defined contract.
Prefer Declaring Expected State in __init__
If an attribute is part of the normal shape of the object, declare it up front, even if the starting value is None.
Now the class communicates its state clearly:
- every
Sessionhas auser_id - every
Sessionhas atokenattribute - the token simply starts unset
That is much easier for readers, tools, and future methods to reason about.
Lazy Initialization Is Still Fine
There are valid cases where a value should only be computed later. The key is that the attribute can still be declared in __init__ and filled lazily.
This keeps the class contract explicit while still avoiding unnecessary work during construction.
Dynamic Attributes Can Be Intentional
Some designs really do create attributes dynamically, especially in framework integration, deserialization, or schema-flexible models.
This is valid, but it should be intentional and documented. You are trading static clarity for runtime flexibility, and that tradeoff should be visible to readers.
Dataclasses Make Explicit State Easier
If the class is mostly structured data, dataclasses make the explicit style concise.
This gives you a clear state contract with very little boilerplate.
Ask the Right Design Question
The question is not "may I ever assign to self outside __init__." Of course you may. Methods update instance state all the time.
The better question is this: is the attribute part of the object's normal expected shape, or is it incidental state created on one narrow execution path. If it is part of the normal shape, declaring it in __init__ usually makes the class more understandable and less error-prone.
Common Pitfalls
- Creating a required attribute only inside an optional method call.
- Suppressing a linter warning without deciding whether the class state contract is actually clear.
- Mixing explicit attributes and dynamic attributes in one class without documenting which ones are guaranteed.
- Treating lazy initialization as an excuse to avoid constructor clarity.
- Forgetting that type checkers and IDEs work better when expected attributes are declared early.
Summary
- Defining instance attributes outside
__init__is valid Python, but often a design smell. - If an attribute is part of the normal object contract, declare it in
__init__. - Lazy initialization can still be explicit by starting with
Noneand filling the value later. - Dynamic attribute creation is acceptable when it is intentional and documented.
- The warning is mainly about clarity, tooling, and method-order safety, not about Python syntax legality.

