Can I use module name as a 'variable' in Python? - python

Is it possible to use the name of the module as a variable to send to a function and specify/restrict some object with it? Thanks!
module1.py
def foo(a, b):
return (a + b) / 2.0
module2.py
def foo(a, b):
return 2.0 * a*b / (a+b)
file3.py
import module1
import module2
def do(a, b, module_name):
return module_name.foo(a, b)

Following your question, I assumed that you want to be able to invoke the foo method of any locally imported modules, providing args + module_name (as a string, like the variable name suggests).
Using locals() instead of sys.modules narrows the search to the modules imported in this file.
My solution:
import inspect
import module1
import module2
def do(a, b, module_name):
module = locals().get(module_name)
if inspect.ismodule(module):
return module.foo(a, b)
raise NameError('no such module imported with this name')

You can access modules in the form of a dictionary for easy lookup using sys.modules:
import module1
import module2
import sys
def do(a, b, module_name):
return sys.modules[module_name].foo(a, b)
This way they can be called for example:
do(3, 5, 'module1') # returns 4.0
do(3, 5, 'module2') # returns 3.75

Related

Python pass variable to imported module at "compilation" time

I'm trying to create an object from a custom class with a decorator in it.
Then I need to use the decorator of that object to create a bunch of functions in a different file.
I found the solution of using builtins online but it feels a bit hacky and makes my lsp spit out a bunch of errors.
I'm wondering if anyone knows a better solution.
This is my file structure:
main.py
mylib
├── A.py
└── B.py
main.py
import builtins
from mylib.A import A
a = A("This is printing in the decorator")
builtins.FOO = a
import mylib.B as B
B.foo()
B.poo()
A.py
class A:
def __init__(self, _message):
self.message = _message
def our_decorator(self, func):
def function_wrapper():
print(self.message)
func()
return function_wrapper
B.py
import builtins
#builtins.FOO.our_decorator
def foo():
print("foo")
#builtins.FOO.our_decorator
def poo():
print("poo")
I don't want to change the file structure if it can be avoided.
Using builtins to have a magically created decorator is indeed hacky.
An alternative would be to patch the functions in B from main. It is slightly cleaner (and linters should not complain) because the B module has no longer to be aware of the decorator:
main.py:
from mylib.A import A
a = A()
import mylib.B as B
# decorate here the functions of the B module
B.foo = a.our_decorator(B.foo)
B.poo = a.our_decorator(B.poo)
B.foo()
B.poo()
A.py is unchanged...
B.py:
def foo():
print("foo")
def poo():
print("poo")
As only one version of a module exists in a process, you can even use the functions of B from a third module, provided:
either it is imported after the decoration
or it only imports the module name (import mylib.B as B) and not directly the functions (from mylib.B import foo)

Organizing functions into modules based on choice

I have 2 Python modules (e.g. A.py & B.py) that have the same function names (the implementation is different though). A third module (C.py) has a function that requires the functions in A or B, depending on user choice.
A fourth module (D.py) will import either A or B, and then C.
How do I correctly setup the modules and imports?
# module A.py
def write():
print('A')
# module B.py
def write():
print('B')
# module C.py
def foo():
write()
# module D.py (main executed module)
if choiceA:
import A
import C
else:
import B
import C
C.foo()
This is essentially a basic case of a Strategy Pattern. Instead of doing a double-import and implicitly expecting module C to get the right module, you should just explicitly pass the appropriate selection for it to call.
Using modules A and B as before:
# module C.py
def foo(writer):
writer.write()
# module D.py
import A
import B
import C
if choiceA:
my_writer = A
elif choiceB:
my_writer = B
C.foo(my_writer)
This will also continue to work exactly the same way if you choose to define A, B, and C as a class hierarchy instead of modules.
Not much really.
Module A.py:
def write():
print('A')
Module B.py
def write():
print('B')
Module C.py
def foo(choice):
if choice == 'A':
import A
A.write()
elif choice == 'b':
import B
B.write()
else:
#whatever
module D.py
choice = input('Enter choice: ')
import C
C.foo(choice)

Override function in a module with complex file tree

I have a module module containing 2 functions a and b splited into 2 different files m1.py and m2.py.
The module's file tree:
module/
__init__.py
m1.py
m2.py
__init__.py contains:
from .m1 import a
from .m2 import b
m1.py contains:
def a():
print('a')
m2.py contains:
from . import a
def b():
a()
Now, I want to override the function a in a main.py file, such that the function b uses the new function a. I tried the following:
import module
module.a = lambda: print('c')
module.b()
But it doesn't work, module.b() still print a.
I found a solution, that consists in not importing with from . import a but with import module.
m2.py becomes:
import module
def b():
module.a()

Inheriting a class with the same name in Python

I am new in Python and I am trying to create two classes with the same name in two different source files. Let’s call them "Main.py" and "Extension.py". The class is "MyClass". MyClass in Extesntion.py is derived from MyClass in file Main.py. If it works then when I create an object myclass and I import Extension in my code, then I would have more functions in comparison with file Main.py.
File Main.py
class MyClass:
def __init__(self):
Initialize something
def foo1(self, a, b):
Do something
Then extension would be like this:
File Extensions.py
import Main
class MyClass(MyClass):
def __init__(self):
Initialize something
def foo2(self, a, b):
Do something
def foo3(self, a, b):
Do something
And then if I have code like this. I expect that I can't use foo2 and foo3.
import Main
myclass = MyClass()
myclass.foo1(a, b)
And finally if I have code like this. I expect that I use all the functions.
import Extension
myclass = MyClass()
myclass.foo1(a, b)
myclass.foo2(a, b)
myclass.foo3(a, b)
If you do
import main
you'll need to use main.MyClass to create an object from main.py.
Instead you can do
from main import MyClass
to have it available directly.
If you need two different classes with the same name, you can instead do
from main import MyClass as MainClass
and you'll have the class available under the name MainClass
Unless you do from Extension import *, you'll need to specify the module in order to access the class.
import Main
import Extension
foo = Main.MyClass()
bar = Extension.MyClass()
If you don't want to have to specify the module, then the only way to avoid a name collision is to import the class under a different name like so:
from Main import MyClass as ClassA
It's quite easy when you explicitly import the given name using the from {module} import {name} syntax.
File main.py
class MyClass:
def __init__(self):
pass
def foo1(self, a, b):
pass
File extensions.py
from main import MyClass
class MyClass(MyClass):
def __init__(self):
pass
def foo2(self, a, b):
pass
def foo3(self, a, b):
pass
File client_main.py
from main import MyClass
myinstance = MyClass()
myinstance.foo1(a, b)
File client_extensions.py
from extensions import MyClass
myinstance = MyClass()
myinstance.foo1(a, b)
myinstance.foo2(a, b)
myinstance.foo3(a, b)
Generally in this case, you would do an import as. This allows you to alias your import as a new name. So in the file where your second class is, import the first class as:
from main import MyClass as MainMyClass
Then when doing your inheritance, refer to MainMyClass:
class MyClass(MainMyClass):

Check if class B is subclass of class A which is located in the same module

With the following setup of the two files a.py
#File a.py
import imp
import inspect
class A(object):
pass
if __name__ == "__main__":
mod = imp.load_source("B", "b.py")
for _, c in inspect.getmembers(mod, inspect.isclass):
print issubclass(c, A)
and
#b.py
from a import A
class B(A):
pass
How do I check in file a.py if a class found in b.py is a subclass of A.
The attempt you see in a.py results in two False being printed. Since B is a subclass of A how do I check it crrectly?
I have found the following solution:
#File a.py
import imp
import inspect
class A(object):
pass
if __name__ == "__main__":
mod = imp.load_source("B", "b.py")
#self import
import a
for _, c in inspect.getmembers(mod, inspect.isclass):
print issubclass(c, a.A)
but still I don't have any idea why it works (while your solution doesn't)

Categories

Resources