I'm considering using the following design pattern:
from threading import Lock
class FieldsLocker:
def __init__(self):
self.lock = Lock()
def __setattr__(self, name, value):
if name == 'lock':
return super().__setattr__(name, value)
with self.lock:
print('locked set', name, '=', value)
return super().__setattr__(name, value)
def __getattribute__(self, name):
if name == 'lock':
return super().__getattribute__(name)
with self.lock:
print('locked get', name)
return super().__getattribute__(name)
class MyClass(FieldsLocker):
def __init__(self):
super().__init__()
self.a = 1
self.b = 2
o = MyClass()
o.a = o.b
It seems to lock class members whenever they're set and get, it produces the following output:
locked set a = 1
locked set b = 2
locked get b
locked set a = 2
I have 2 questions:
1. Is there any risk of using __setattr__
and __getattribute__
methods for ensuring thread safety of class members in general?
Aside of the fact that a single lock is used for all fields (which is possibly less efficient than using few individual locks for specific members where strictly necessary).
2. Is there any risk of using reusable FieldsLocker
parent class from example above?
Aside of the fact that:
- MyClass may break it by declaring its own
self.lock = None
- the user may forget to put
super().__init_()
and may want to override__setattr__
and__getattribute__
themselves (and may forget or intentionally not call super() equivalents of these methods).