How to make a third party obj thread safe in python? - python

I want to use a third module in python like this :
import some_module
class MyService():
def __init__(self):
self.some_module_obj = some_module.some_obj()
def run(self,some_parameter):
self.some_module_obj.some_attritude(some_parameter)
I know that some_module.some_obj and its method some_attritude is not thread safe , My question is how to make MyService thread safe ?
update 1:
I see Artiom Kozyrev's code , Is the code below right ?
import some_module
import threading
GLOBAL_LOCK = threading.Lock()
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
with GLOBAL_LOCK:
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(
*args, **kwargs
)
return cls._instances[cls]
class MyService(metaclass=Singleton):
def __init__(self):
self.some_module_obj = some_module.some_obj()
self.rlock = threading.RLock()
def run(self,some_parameter):
result = None
with self.rlock:
result = self.some_module_obj.some_attritude(some_parameter)
return result

Related

Python thread safe singleton stuck when used

I tried to implement a thread safe singleton for my python code. I tried these 2 pieces of code but both of them get stuck when the class with the metaclass of the Singleton is being called from my unittests.
1 (check-lock-check):
import functools
import threading
from typing import Callable
def synchronized(thread_lock: threading.Lock):
""" Synchronization decorator """
def wrapper(function: Callable):
#functools.wraps(function)
def inner_wrapper(*args: list, **kw: dict):
with thread_lock:
return function(*args, **kw)
return inner_wrapper
return wrapper
class Singleton(type):
_instances = {}
_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._locked_call(*args, **kwargs)
return cls._instances[cls]
#synchronized(_lock)
def _locked_call(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
2 (simple lock):
from threading import Lock
class Singleton(type):
_instances = {}
_lock: Lock = Lock()
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
with cls._lock:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
Does someone know why my code get stuck on this implementation when I run it locally (for unittests for example)? Because once the app is deployed it's actually uses multithreading everything is fine.
And do you have suggestions for something else that could work with what I need?
Thanks.

How to reset a singleton instance in python in this case?

I am trying to create a Singleton class in Python using this code:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
def clear(cls):
cls._instances = {}
class MyClass(metaclass=Singleton):
def my_attribute(*args):
if len(args) == 1:
MyClass.i_attribute = args[0]
elif len(args) == 0:
try:
return MyClass.i_attribute
except:
MyClass.i_attribute = 0
but the clear() method does not seem to work:
MyClass.my_attribute(42)
MyClass.clear()
MyClass.my_attribute() # still returns 42, but I expect 0
How do I delete the instance of MyClass so that I am back to 0 instances?
The singleton metaclass collects in the _instances attribute all the instantiated children. Therefore, if you want to clear the _instances attributes only for a specific class, you can:
Redefine the Singleton class, to make _instances an attribute of the class instantiated by the metaclass:
class Singleton(type):
"""
Singleton metaclass, which stores a single instance of the children class in the children class itself.
The metaclass exposes also a clearing mechanism, that clear the single instance:
* clear: use as follows 'ClassToClear.clear()
"""
def __init__(cls, name, bases, methods):
cls._instance = None
super().__init__(name, bases, methods)
def __call__(cls, *args, **kwargs):
if cls._instance:
return cls._instance
cls._instance = super().__call__(*args, **kwargs)
return cls._instance
def clear(cls):
cls._instance = None
Using this new definition of the singleton, you can write a clear method that can be called by any of the classes initialized with the Singleton metaclass and it will clear the _instance attribute.
So in your case, MyClass.clear() would reset the _instance attribute to None.
Add a clear method, which removes only the children class from the Singleton._instances dictionary:
class SingletonRegistry(type):
"""
Singleton metaclass, which implements a registry of all classes that are created through this metaclass and
the corresponding instance of that class (added at the first creation).
The metaclass exposes also a clearing mechanism, that clears a specific class from the registry:
* clear: use as follows 'ClassToClear.clear()
* clear_all: use as follows 'SingletonRegistry.clear_all()
"""
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonRegistry, cls).__call__(*args, **kwargs)
return cls._instances[cls]
def clear(cls):
_ = cls._instances.pop(cls, None)
def clear_all(*args, **kwargs):
SingletonRegistry._instances = {}
In this case, if you would like to clear only one specific child class, then you could write MyClass.clear(), which will cause the MyClass key to be removed from Singleton._instances dictionary.
This structure allows also to clear all key in the _instances dictionary by writing SingletonRegistry.clear_all().
user2357112 is right. Here is the correct code:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
def clear(cls):
cls._instances = {}
class MyClass(metaclass=Singleton):
def my_attribute(*args):
my = MyClass()
if len(args) == 1:
my.i_attribute = args[0]
elif len(args) == 0:
try:
return my.i_attribute
except:
my.i_attribute = 0
return my.i_attribute

Adding hooks to functions in subclassed methods

Given the following simplified code:
from abc import ABC, abstractmethod
class Parent(ABC):
def __init__(self,*args,**kwargs):
self.parent_name = 'SuperClass'
# global hook to run before each subclass run()
def global_pre_run_hook(self):
pass
#abstractmethod
def run(self, *args, **kwargs):
raise NotImplementedError()
class Child(Parent):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.name = 'ChildClass'
def run(self):
print(f'my parent name is {self.parent_name}')
print(f'my name is {self.name}')
return 22
obj = Child()
result = obj.run()
Is there a way to add functionality so that when the child class run() method is called directly, it first triggers a hook function from the parent class? Assume there is a parent class and a lot of classes that subclass it - would I need to manually add a call global hook() at the beginning of each run() definition for each class that subclasses Parent()? Is there a pythonic way to accomplish this?
There might be a way to do this with a proper decorator, but for the time being I think the cleanest solution you might come up with would be to create your own 'decorator' and manually apply it in the course of Parent.__init__(), which would make sure it takes effect so long as the child class invokes the parent __init__():
from abc import ABC, abstractmethod
def create_hook(func, hook):
def wrapper(*args, **kwargs):
hook()
return func(*args, **kwargs)
return wrapper
class Parent(ABC):
def __init__(self, *args, **kwargs):
self.parent_name = 'SuperClass'
self.run = create_hook(self.run, self.global_pre_run_hook)
# global hook to run before each subclass run()
def global_pre_run_hook(self):
print("Hooked")
#abstractmethod
def run(self, *args, **kwargs):
raise NotImplementedError()
class Child(Parent):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.name = 'ChildClass'
def run(self):
print(f'my parent name is {self.parent_name}')
print(f'my name is {self.name}')
return 22
obj = Child()
result = obj.run()
# this prints:
# Hooked
# my parent name is SuperClass
# my name is ChildClass
The answer by Green Cloak Guy works, but cannot be pickled! To fix this, we need to move the hook creation into __new__. Also, it's a good idea to make use of functools.wraps in the hook creator.
import pickle
from abc import ABC, abstractmethod
from functools import wraps
def create_hook(func, hook):
#wraps(func)
def wrapper(*args, **kwargs):
hook(*args, **kwargs)
return func(*args, **kwargs)
return wrapper
class Parent(ABC):
def __new__(cls, *args, **kwargs):
cls.run = create_hook(cls.run, cls.global_pre_run_hook)
return super().__new__(cls, *args, **kwargs)
# global hook to run before each subclass run()
def global_pre_run_hook(self, *args, **kwargs):
print("Hooked")
#abstractmethod
def run(self, *args, **kwargs):
raise NotImplementedError()
class Child(Parent):
def run(self):
print(f"my parents are {self.__class__.__mro__}")
print(f"my name is {self.__class__.__name__}")
return 22
obj = Child()
result = obj.run()
pickle.dumps(obj)

How dynamically add base class to dynamic class in python

In case I would like dynamically add a base class to child class
but I don't know what classes will be
which option should I use?
# first_file.py
# Option 1
def add_base(clazz, new_parent_class):
bases = tuple(list(clazz.__bases__) + [new_parent_class])
clazz.__bases__ = bases
return clazz
# Option 2
def add_base(clazz, new_parent_class):
bases = tuple(list(clazz.__bases__) + [new_parent_class])
clazz = type(clazz.__name__, bases, dict(clazz.__dict__))
return clazz
# second_file.py
class OtherClass(object # or any other class #)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class MyClass(object # or any other class #)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# fourth_file.py
from first_file import add_base
from second_file import OtherClass
from third_file import MyClass
new_class = add_base(OtherClass, MyClass)
ins = new_class()

How to add pre/post methods to class. Python

Lets assume I've a class A which has a bunch of methods, but I want it to run certain lines before and after each method is called.
For example: I want my class Dog here to run before() and after() every time bark() or run() are been called.
class Dog():
def __init__(self, sound, speed):
self.sound = sound
self.speed = speed
def before(self):
check_some_things(self)
def after(self):
do_some_things(self)
def bark(self):
sound(self.sound)
def run(self):
move(self.speed)
You could encapsulate this in a decorator; the following decorator will call before and after if these are available on self:
import inspect
from functools import wraps
def before_and_after(f):
#wraps(f)
def wrapper(self, *args, **kw):
if hasattr(self, 'before') and inspect.ismethod(self.before):
self.before()
result = f(self, *args, **kw)
if hasattr(self, 'after') and inspect.ismethod(self.after):
self.after()
return result
return wrapper
then simply apply to the methods that should be wrapped:
class Dog():
def __init__(self, sound, speed):
self.sound = sound
self.speed = speed
def before(self):
check_some_things(self)
def after(self):
do_some_things(self)
#before_and_after
def bark(self):
sound(self.sound)
#before_and_after
def run(self):
move(self.speed)
The decorator assumes it is used on methods, e.g. the produced wrapper expects self as a first argument.
If this needs to apply to all methods that are not before or after, perhaps a metaclass is in order:
class BeforeAfterMeta(type):
def __new__(mcs, classname, bases, body):
for name, value in body.items():
if not inspect.isfunction(value):
continue
if name in ('before', 'after') or name[:2] + name[-2:] == '_' * 4:
# before or after hook, or a special method name like __init__.
continue
body[name] = before_and_after(value)
return super(BeforeAfterMeta, mcs).__new__(mcs, classname, bases, body)
which you then can apply to your class:
class Dog(metaclass=BeforeAfterMeta):
def __init__(self, sound, speed):
self.sound = sound
self.speed = speed
def before(self):
check_some_things(self)
def after(self):
do_some_things(self)
def bark(self):
sound(self.sound)
def run(self):
move(self.speed)
You could also use a decorator function to inspect your class Dog if the pre and post methods exists and override the run method:
def PrePostMethod(inputClass):
mainRun = inputClass.run
beforeFunc = inputClass.before if "before" in inputClass.__dict__ else None
afterFunc = inputClass.after if "after" in inputClass.__dict__ else None
def new_run(self, *args, **kwargs):
# you could inspect the given arguments if you need
# to parse arguments into before and the after methods
if beforeFunc:
self.before()
mainRun(self)
if afterFunc:
self.after()
inputClass.run = new_run
return inputClass
#PrePostMethod
class Dog(object):
def __init__(self, sound, speed):
self.sound = sound
self.speed = speed
def before(self):
print "Do stuff before"
def after(self):
print "Do stuff after"
def run(self):
print "Do main process"
Dog(1,2).run()
To parse arguments and keywords arguments from run into before and after, use the class inspect and loop through the args and kwargs to parse the right ones.
from inspect import getargspec
def argHandler(method, *args, **kwargs):
method = getargspec(method)
mArgs = method.args
mKwargs = method.keywords
rArgs = args[:len(mArgs)-1]
rKwargs = { k:v for k,v in kwargs.iteritems() if k in mKwargs }
leftArgs = len(mArgs)-len(rArgs)
if len(rKwargs):
rKwargs = [ rKwargs[k] for k in mArgs[:leftArgs-1]]
rArgs += rKwargs
return rArgs
def PrePostMethod(inputClass):
mainRun = inputClass.run
beforeFunc = inputClass.before if "before" in inputClass.__dict__ else None
afterFunc = inputClass.after if "after" in inputClass.__dict__ else None
def new_run(self, *args, **kwargs):
if beforeFunc:
nargs = argHandler(self.before, *args, **kwargs)
if nargs: self.before( *nargs)
else: self.before()
nargs = argHandler(mainRun, *args, **kwargs)
if nargs: mainRun(self, *nargs)
else: mainRun(self)
if afterFunc:
nargs = argHandler(self.after, *args, **kwargs)
if nargs: self.after( *nargs)
else: self.after()
inputClass.run = new_run
return inputClass
You can use many different ways to do this. But I think the best way is, to define a class with the Pre- and Post-Methods and redefine it's object hidden methods: __enter__ and __exit__. To use them, just call the class with the compound statement with.
class pre_post(object):
def __enter__(self):
print "Enter check method.."
def __exit__(self, type, value, tb):
print "Exit check method.."
class dog(object):
def run(self, checkups=True):
if checkups:
with pre_post() as pp:
print "My stuff.."
else:
print "My stuff.."
dog().run(True)
This will give you the following result:
Enter check method..
My stuff..
Exit check method..
I hope that will help you.

Categories

Resources