Make `threading.{Lock,RLock}` factory functions subclassable

Original issue: Subclassing threading Lock/RLock: better Exception messages · Issue #94077 · python/cpython · GitHub

Right now threading.Lock and threading.RLock are defined as functions. Here’s how the exception messages look if we try to subclass them:

from threading import Lock, RLock

class SubclassLock(Lock):
    pass
# TypeError: cannot create 'builtin_function_or_method' instances

class SubclassRLock(RLock):
    pass
# TypeError: function() argument 'code' must be code, not str

Here’s my proposal:

def Lock():
    """Factory function that returns a new lock."""
    return _allocate_lock()

Lock.__mro_entries__ = lambda bases: (_thread.lock,)

# ...

RLock.__mro_entries__ = lambda bases: (
    _PyRLock if _CRLock is None else _CRLock,
)

This makes Lock and RLock functions subclassable:

>>> from threading import RLock
>>> class My(RLock): ...
... 
>>> My.__mro__
(<class '__main__.My'>, <class '_thread.RLock'>, <class 'object'>)
>>> 

Should I make this change? How often people actually subclass Lock and RLock?

Right now, it can be solved via this hack:

_LockType = type(threading.Lock())

class MyLock(_LockType): ...

Any feedback is welcome! :slight_smile:

1 Like

What’s the use case for subclassing them?

1 Like

These are functions specifically to prevent subclassing, to give the implementation more freedom. But you can wrap a Lock in a class of your own that supports the same protocol.

5 Likes