Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate the classes defined in a module imported dynamically

I have a module from a child package that is imported dynamically; how can I iterate over the classes that it contains?

I have been importing the module and listing the names like this:

package = current_module.__name__
package = package[:package.rindex(".")] # get the package
package = "%s.sub.%s"%(package,name) # make the name of the child
print "(loading package %s)"%package
module = __import__(package) # this succeeds
for name,obj in inspect.getmembers(module):
    print name,type(obj)

This only prints module attributes and not the class types that the module defines:

__builtins__ <type 'dict'>
__doc__ <type 'NoneType'>
__file__ <type 'str'>
__name__ <type 'str'>
__package__ <type 'NoneType'>
__path__ <type 'list'>
imported_package <type 'module'>

It seems that my classes are not in the __dict__ unless the fromlist is non-empty! The values in the from-list don't seem to be validated though; [""] seems to work just fine, and suddenly the classes show up!

Can anyone explain why this is?

(Standard ubuntu python 2.7.1+ (r271:86832)

like image 230
Will Avatar asked Sep 28 '11 13:09

Will


People also ask

How do you dynamically import a module using a function?

To load dynamically a module call import(path) as a function with an argument indicating the specifier (aka path) to a module. const module = await import(path) returns a promise that resolves to an object containing the components of the imported module. } = await import(path);

What is __ import __ in Python?

__import__() . This means all semantics of the function are derived from importlib. __import__() . The most important difference between these two functions is that import_module() returns the specified package or module (e.g. pkg. mod ), while __import__() returns the top-level package or module (e.g. pkg ).

What is lazy import python?

Lazy import is a very useful feature of the Pyforest library as this feature automatically imports the library for us, if we don't use the library it won't be added. This feature is very useful to those who don't want to write the import statements again and again in their code.


3 Answers

Example: to create a dict that maps the names to the classes:

dict([(name, cls) for name, cls in mod.__dict__.items() if isinstance(cls, type)])

where mod is the loaded module

like image 69
pvoosten Avatar answered Nov 17 '22 06:11

pvoosten


If you define __all__ in the module you are importing, which defines which symbols will be exported, you can iterate by selecting these items specifically.

map(module.__dict__.get, module.__all__)
like image 32
huntie Avatar answered Nov 17 '22 06:11

huntie


Method 1:

import inspect
import mymodule

for name, obj in inspect.getmembers(mymodule):
    if inspect.isclass(obj):
        do stuff...

Method 2:

desired_classes = [obj for name, obj in somemodule.__dict__.items() if isinstance(obj, DesiredType)]

Method 3:

Inside the module you want to iterate on:

File: mymodule.py

class Dog:
    VOICE = 'haou'


class Cat:
    VOICE = 'meew'


class ImNotIncluded:
    VOICE = 'what a shame'


__all__ = ['Dog', 'Cat']

>>> from mymodule import *
>>> Dog.VOICE
'haou'
>>> Cat.VOICE
'meew'
>>> ImNotIncluded.VOICE
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
NameError: name 'ImNotIncluded' is not defined

Now to iterate you do:

>>> for cls in map(mymodule.__dict__.get, mymodule.__all__): cls
...
<class 'mymodule.Dog'>
<class 'mymodule.Cat'>
 
like image 30
ניר Avatar answered Nov 17 '22 08:11

ניר