Class-level private property isolation

The question is: the author said that “You should inherit this class”. Using composition may break it.

I don’t think that the suggestion should be “you shouldn’t listen to the author”

Then your only option to use manual name mangling.

Now there are serval problems:

  • Before you read the source codes of the module, you don’t know which name it used.
  • When this TypeError occurred or running into strange state, what you will do first is check whether there are some hidden bugs in your codes instead of consider the name conflict.
  • Author may change these private names in the next update without any information, so it is fragile.

These issues disappear when you are properly name mangling your subclasses, that is doing it by hand instead of relying on the primitive built-in mechanism.

However, the special manual name mangling may also make the name less readable, normal name mangling may still cause the conflict.

Do you have an actual use-case here or is this entirely theoretical? When the author says “you should inherit this class”, there is usually a VERY strong backward compatibiltiy guarantee, and things are properly documented; and if not, the docs will generally be clear about what you should and shouldn’t be overriding (see eg threading.Thread).

You say this, but you also say that the author is explicitly inviting subclassing. Maybe that should just be considered a bug?

Where is the unittest.TestCase declared which private names shouldn’t be override?

Moreover, I didn’t saw any documents that you cannot cover these private attributes in threading.Thread:

        # threading.Thread in 3.14.7
        assert group is None, "group argument must be None for now"
        if kwargs is None:
            kwargs = {}
        if name:
            name = str(name)
        else:
            name = _newname("Thread-%d")
            if target is not None:
                try:
                    target_name = target.__name__
                    name += f" ({target_name})"
                except AttributeError:
                    pass

        self._target = target
        self._name = name
        self._args = args
        self._kwargs = kwargs
        if daemon is not None:
            if daemon and not _daemon_threads_allowed():
                raise RuntimeError('daemon threads are disabled in this (sub)interpreter')
            self._daemonic = daemon
        else:
            self._daemonic = current_thread().daemon
        self._context = context
        self._ident = None
        if _HAVE_THREAD_NATIVE_ID:
            self._native_id = None
        self._os_thread_handle = _ThreadHandle()
        self._started = Event()
        self._initialized = True
        # Copy of sys.stderr used by self._invoke_excepthook()
        self._stderr = _sys.stderr
        self._invoke_excepthook = _make_invoke_excepthook()
        # For debugging and _after_fork()
        _dangling.add(self)

The original text is:

The Thread class represents an activity that is run in a separate thread of control. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the run() method in a subclass. No other methods (except for the constructor) should be overridden in a subclass. In other words, only override the __init__() and run() methods of this class.

It is not “the private attributes above”.

backwards compatibility.

as the behavior of name-mangling is well known, over teh decades lots of code evolved that, when needing to reach tese variables, would re-create the mangled name.

1 Like