Reputation: 364
I have the following command:
a = imp.load_source("a", r"some_path\some_source.py")
and so a
is a module object from which I can access and run all functions inside some_source.py
. Is there a way in python to accomplish that additional functionality will run before using any of some_source
's functions but without changing some_source.py
? For instance if some_source.py
has functions foo1
, foo2
... foo100
, then I want the command
a.foo5()
to actually execute:
imp.reload(a)
a.foo(5)
and this should be applied to all 100 foo
functions.
Just to be clear, I want the added functionality to happen simply by running the same command as everybody in my team are used to -
a.foo5()
. I don't want them to have to create some sort of class or call a different method than what they're used to.
Upvotes: 2
Views: 249
Reputation: 814
You could do the following :
Option A :
class example:
def __init__(self):
self.a = 2
self.b = 3
def some_func(self, argument_a):
print(argument_a)
def some_func_2(self, argument_b):
print(argument_b)
def make_method(method_name):
def _method(self, *args):
# Insert what ever extra stuff you want to do here ...
function_to_call = getattr(self.class_reference, method_name)
function_to_call(self, *args)
return _method
class a_class:
def __init__(self, class_reference):
self.class_reference = class_reference
object_method_list = [func for func in dir(object) if callable(getattr(object, func))]
method_list = [func for func in dir(class_reference) if callable(getattr(class_reference, func))]
for method_name in method_list:
if method_name in object_method_list:
continue
_method = make_method(method_name)
setattr(type(self), method_name, _method)
module_class = a_class(example)
module_class.some_func()
This creates a class that creates all function from a dynamically (with an extra something).
Option B :
def do_func_with_extra(function_to_do, *args):
# Do something extra...
function_to_do(*args)
do_func_with_extra(a.some_func, argument0, argument1, ..)
Option B isnt exactly as you asked, but it would work as well.
I am also pretty certain there is a better way. but not one I can think of right now. Let me know if it works for you.
Upvotes: 0
Reputation: 24233
You could try to decorate your module like this:
class ReloadingModule:
def __init__(self, module):
self.module = module
def __getattr__(self, attr):
print("reloading {}...".format(self.module.__name__))
imp.reload(self.module)
return getattr(self.module, attr)
import this
this = ReloadingModule(this)
print('\n\n',this.c, '\n\n')
print('\n\n',this.s, '\n\n')
Output:
reloading this...
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
[...]
97
reloading this...
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
[...]
Gur Mra bs Clguba, ol Gvz Crgref
Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
[...]
With some math:
import math
math = ReloadingModule(math)
print(math.pi)
print(math.sin(math.pi/2))
Output:
reloading math...
3.141592653589793
reloading math...
reloading math...
1.0
Upvotes: 3