Skip to content

strictaccess

strictaccess enforces Java/C++-style access modifiers on Python classes. Decorate a class with @strict_access_control() and use @private, @protected, and @public to mark methods. Violations raise typed exceptions; an optional debug mode downgrades them to log warnings.

from strictaccess import strict_access_control, private, protected

@strict_access_control()
class Account:
    def __init__(self, balance: int) -> None:
        self._balance = balance  # protected by convention

    @private
    def _adjust(self, delta: int) -> None:
        self._balance += delta

    def deposit(self, amount: int) -> None:
        self._adjust(amount)     # OK: internal call

Where to next

Why not just rely on the underscore convention?

The underscore prefix is documentation. strictaccess turns it into an enforced contract: violations fail loud at runtime instead of silently breaking encapsulation. It is the same model Java and C++ use; the philosophy is "make wrong code look wrong, and refuse to run it."

Why use this at all?

  • Codebases shared across teams. Convention drifts; enforcement does not.
  • Legacy refactors. Run in debug mode to surface every site that touches private state before you commit to a hardened API.
  • Library boundaries. Mark internals so consumers cannot accidentally build on them and complain when you change them.

Why not?

  • You need a security boundary. object.__getattribute__ bypasses strictaccess in one line. See Limitations.
  • You need C-level performance for attribute access. The override pays roughly 20-30x over native attribute access (still nanoseconds — fine for business logic, not for hot inner loops).