Import class from module dynamically WITHOUT loading entire module - python-3.x

I am trying to load a class at run time from a configuration file. The module that contains the class will contain many other classes and I don't want to import them all. The pattern given in this question Import class from module dynamically
cls = getattr(import_module('my_module'), 'my_class')
loads in the entire module which is exactly what I am trying to avoid. Is there way to get just 'my_class' without everything else in 'my_module'?

Related

Make import module return a variable

I would like to make an imported module behave like an object, ie. an dictionary.
E.g.
import module
print(module['key'])
and in module.py
return {'key':'access'}
This is very easy for Class by inheriting from dict, but how do I do this on a module level?
In particular I want to dynamically built the dictionary in module and return it when module is imported.
I know that there are other solutions such as defining the dict as a var in the module workspace and accessing it via module.var, but I am interested if something like this is possible.
As you point out, you can do this with a class, but not with a module, as modules are not subscriptable.Now I'm not going to ask why you want to do this with an import, but it can be done.
What you do is create a class that does what you want, and then have the module replace itself with the class when imported. This is of course a 'bit of a hack' (tm). Here I'm using UserDict as it gives easy access to the dict via the class attr data, but you could do anything you like in this class:
# module.py
from collections import UserDict
import sys
import types
class ModuleDict(types.ModuleType, UserDict):
data = {'key': 'access}
sys.modules[__name__] = ModuleDict(__name__)
Then you can import the module and use it as desired:
# code.py
import module
print(module['key']
# access

Open a file after it was created in Python

I created two classes. The first class takes an image from the working directory and then covert the image from pdf to jpg using wand. The second class takes the created jpg image and then do further manipulations with the image.
Now When I try to run the first class and then the second class right after that; python crashes because the second class is trying to look for the image but it wont find it until it is created.
My question is how can you run the second class but just after the first class is executed.
class1 = imagecreation('image.jpg')
class2 = transformimage()
I found the answer to my question. When you reference classes and you import as a module in a different one; the module will get call when is defined if you do not use if __name__=='__main__':. By putting this code at the end of the code will only execute the module once it is intended to be executed but not when you import the module. This way you can use the modules by themselves and also to import from other modules.

does an imported function from a module could access class from this module?

I am a new comer when it comes to package and module to python.
I am trying to cut my script in several separate compartiment. to improve readability and maintenance.
My problem is the following:
I have a module which define a class and a function inside this module which instantiate this class.
module blast.py
class Blast():
blabla
def foo():
blast = Blast()
# do some stuff
this module is inside a package with a _ _init__.py file
__all__ = ["blast"]
I have a main script In which i want to use that function.
I import the module with
from package import blast
But To use that function I have to use the name space of the module ( at least my IDE say me that: pycharm)
blast.foo()
So does it works? does the function will see the class inside it module?
And more generally Could I import some function of my package inside my namespace. I though it was done this way and answer I got from internet doesn't really help me.
Yes, the function blast.foo() would know and find the class Blast.
Whenever you import a module, in part or in its entirety, the entire module is loaded - the way you import it merely decides on what classes and functions are available in the current scope, and in what way.
For example, if you call this:
from package.blast import foo
only the function foo() would be available, but the entire package read and loaded. if you were to try instantiate the class Blast by itself in the same script, this would not work.
By the way, you can make importing functions more convenient, if you customize __init__.py. In your case, if you were to edit it like so:
>>>__init__.py
from blast.py import Blast, foo
you can import both function and class like so:
from package import Blast, foo
The reason why you __all__ parameter does not work, is because it requires another import statement - mainly this:
from package import *
Calling this with your current __init__.py should work as expected.
Perhaps this post by Mike Grouchy is able to clarify things a bit more.

Mutual imports; difference between import's standart, "from" and "as" syntax

Given this simple folder structure
/main.py
/project/a.py
/project/b.py
main.py is executed by the python interpreter and contains a single line, import project.a.
a and b are modules, they need to import each other. A way to achieve this would be
import project.[a|b]
When working with deeper nested folder structures you don't want to write the entire path everytime you use a module e.g.
import project.foo.bar
project.foo.bar.set_flag(project.foo.bar.SUPER)
Both from project import [a|b] and import project.[a|b] as [a|b] result in an import error (when used in both, a and b).
What is different between the standart import syntax and the from or as syntax? Why is only the standart syntax working for mutual imports?
And more importantly, is there a simple and clean way to import modules that allows mutual imports and assigning shorter names to them (ideally the modules basename e.g. bar in the case of project.foo.bar)?
When you do either import project.a or from project import a, the following happens:
The module object for project.a is placed into sys.modules. This is a dictionary that maps each module name to its module object, so you'll have sys.modules = {..., 'p.a': <module 'p.a' from '.../project/a.py'>, ...}.
The code for the module is executed.
The a attribute is added to project.
Now, here is the difference between import project.a and from project import a:
import project.a just looks for sys.modules['project.a']. If it exists, it binds the name project using sys.modules['project'].
from project import a looks for sys.modules['project'] and then checks if the project module has an a attribute.
You can think of from project import a as an equivalent to the following two lines:
import project.a # not problematic
a = project.a # causes an error
That why you are seeing an exception only when doing from project import a: sys.modules['project.a'] exists, but project does not yet have a a attribute.
The quickest solution would be to simply avoid circular imports. But if you can't, then the usual strategies are:
Import as late as possible. Suppose that your a.py looks like this:
from project import b
def something():
return b.something_else()
Rewrite it as follows:
def something():
from project import b
return b.something_else()
Of course, you would have to repeat imports in all your functions.
Use lazy imports. Lazy imports are not standard feature of Python, but you can find many implementations around. They work by using the "import as late as possible" principle, but they add some syntactic sugar to let you write fewer code.
Cheat, and use sys.modules, like this:
import sys
import project.a
a = sys.modules['project.a']
Very un-pythonic, but works.
Obviously, whatever solution you choose, you won't be able to access the attributes from a or b until the modules have been fully loaded.

Python 3, imp.reload does not appear to have any effect

I am modifying a module which contains a class in it.
When I %run another module that uses the mofified class from IPython, the changes do not seem to take effect unless I restart IPython.
I have tried to use imp.reload, but this does not help. For example, I have put the following the code at the top of my module, but it does not appear to be using the updated version of my modified class (BigMySQLDatabaseGetter in the big_mysql_database_getter module)
import imp
import sys
from big_mysql_database_getter import BigMySQLDatabaseGetter
module_big_mysql_database_getter = sys.modules['big_mysql_database_getter']
imp.reload(module_big_mysql_database_getter)
Reloading a module doesn't automatically update all references that were created before, it just redefines everything within the module.
So if you do something like:
from spam import eggs
imp.reload(spam)
print(spam.eggs is eggs)
you'll get False, as eggs still references the old class. Likewise, instances created before the reload are instances of the old class, not of the new class:
import spam
e = spam.eggs()
imp.reload(spam)
print(isinstance(e, spam.eggs)) # False!
In your case, you can either reimport BigMySQLDatabaseGetter after reloading the module, or instead of directly importing the class just import the module and use big_mysql_database_getter.BigMySQLDatabaseGetter instead.

Resources