Skip to content

Instantly share code, notes, and snippets.

@i-am-unknown-81514525
Last active May 30, 2025 15:26
Show Gist options
  • Select an option

  • Save i-am-unknown-81514525/d3e2a8e57e4fcbd487f47922155950a1 to your computer and use it in GitHub Desktop.

Select an option

Save i-am-unknown-81514525/d3e2a8e57e4fcbd487f47922155950a1 to your computer and use it in GitHub Desktop.
Python Class Mutex via MRO
from typing import Callable
from random import choices
from itertools import permutations
registry: dict[type, tuple[type, Callable, Callable]] = {} # old: (new, ori_init, ori_init_subclass)
rev_registry: dict[type, type] = {}
__lock: bool = False
__inner: bool = False
def get_latest_from_reg(cls: type):
while cls in registry:
cls = registry[cls][0]
return cls
def new_init(v: type, *args, **kwargs): # old
r = registry[v][1](*args, **kwargs)
args[0].__class__ = get_latest_from_reg(v) # registry[v][0]
return r
def is_subcls_unmod(cls: type):
class __internal: ...
return type(cls.__init_subclass__) == type(__internal.__init_subclass__)
def new_init_subclass(v: type, cls: type, *args, **kwargs): # old, unmod_subclass?
global __lock, __inner
try:
__set_inner = False
if not __inner:
ori_cls = cls
cls = get_latest_from_reg(cls)
v = get_latest_from_reg(v)
__inner = True
__set_inner = True
try:
__lock = True
mro = tuple(map(get_latest_from_reg, cls.mro()))
new_cls = type(cls.__name__, mro, {})
finally:
__lock = False
ori_init = ori_cls.__init__
ori_init_subclass = ori_cls.__init_subclass__
cls.__init__ = init_closure(cls)
cls.__init_subclass__ = init_subclass_closure(cls)
registry[cls] = (new_cls, ori_init, ori_init_subclass)
rev_registry[new_cls] = cls
if is_subcls_unmod(ori_cls):
return ori_init_subclass(*args, **kwargs)
else:
return ori_init_subclass.__func__(cls, *args, **kwargs)
finally:
if __set_inner:
__inner = False
def init_closure(v: type):
def inner(*args, **kwargs):
return new_init(v, *args, **kwargs)
inner.__name__ = "__init__"
inner.__qualname__ = v.__qualname__
return inner
def init_subclass_closure(v: type):
def inner(cls, *args, **kwargs):
return new_init_subclass(v, cls, *args, **kwargs)
inner.__name__ = "__init_subclass__"
inner.__qualname__ = v.__qualname__
return classmethod(inner)
def factorial(x):
t = 1
for v in range(1, x+1): t *= v
return t
def as_mutex(*t):
global __inner
size = 1
while factorial(size) < len(t): size += 1
rnd = "".join(choices("0123456789abcdef", k=16))
prefix = "__Mutex_" + "_".join(map(lambda x: x.__name__, t)) + "_" + rnd + "_"
mutex = [type(f"{prefix}_{i}", (), {}) for i in range(size)]
for curr, mutex_comb in zip(t, permutations(mutex, len(mutex))):
ori_curr = curr
curr = get_latest_from_reg(curr)
reso = tuple(curr.mro()[:-1] + list(mutex_comb) + [object])
try:
__inner = True
new_cls = type(curr.__name__, reso, {}) # + "_mutex_" + rnd
finally:
__inner = False
ori_init = ori_curr.__init__
ori_init_subclass = ori_curr.__init_subclass__
curr.__init__ = init_closure(curr)
curr.__init_subclass__ = init_subclass_closure(curr)
registry[curr] = (new_cls, ori_init, ori_init_subclass)
rev_registry[new_cls] = curr
if __name__ == '__main__':
class A:...
class B:...
as_mutex(A, B)
class C(A):...
C()
class D:
def __init__(self, t):
self.t = 1
as_mutex(A, B, D)
class E(D):
def __init__(self, t):
super().__init__(t)
self.t
E(1)
class F:
def __init_subclass__(cls):
print(cls)
as_mutex(A, B, F)
class G(D, F): ...
print(G(1).__class__.mro())
try:
class H(B, F): ...
raise AssertionError
except TypeError:
...
@1Git2Clone
Copy link

What the fuck? 😭😭😭

@i-am-unknown-81514525
Copy link
Author

It basically modify the __init__ and __init_subclass__, so that they would be redirected for handling the modification.
On creating the mutex system, the minimal amount of mutex class is used (calculated by the factorial, which for x mutex, it have x! to arrange the class in different order)
It then gives each class a new inheritance of different ordered mutex, such that if 2 class being inherit at the same time, no valid MRO order can be form for the mutex.
For example

class A:...
class B:...
as_mutex(A, B)
A().__class__.mro() # [A_mod, A_ori, __Mutex_A_B__0, __Mutex_A_B__1, object]
B().__class__.mro() # [B_mod, B_ori, __Mutex_A_B__1, __Mutex_A_B__0, object]

Which therefore when you attempt to inherit A and B at the same time, Python MRO rule would lead to no valid way to resolved an order of method resolution (i.e. should __Mutex_A_B__0 be first or __Mutex_A_B__1 because they claim differently

You can noted that I do A().__class__.mro() instead of A.mro(), and the above MRO result shown A_mod and A_ori, this is because the class inheritance of A is not the one that changed, but the __init__ is injected such that the class of the object (via obj.__class__ = ...) would be replaced to the class with the mutex. The A_mod and A_ori is only for pure demonstration purpose, in which in the code, you would just see 2 A.
Strictly, injecting the __init__ is not necessary as the MRO check is being done before hand, but it would be really difficult to demonstrate the mutex so the __init__ injection is kept.

As the class inheritance of A and B isn't modified, how does it prevent it?
It was done by injecting the classmethod __init_subclass__, where it would check the initial MRO of the class, and then create a new class that contain the mutex, then inject the __init__ and __init_subclass__ so the cycle continues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment