Reputation: 480
I have a project which has this hierarchy
tasker/
table/
__init__.py
user.py
task.py
...
__init__.py
tasker.py
every file inside table
folder (except __init__.py
) contains a class that has a same name as the file name except the first letter is capitalized. I want to call and instantiate every class inside table
folder in tasker.py
. I can do it by writing
import table
inside tasker.py
. But, it turns out that I have to write for example
table.user.User()
to instantiate class inside user.py
and it looks very ugly. Is there any way so that I only type at least
user.User()
or even better,
User()
to instantiate those classes?
Note: Every files inside table
folder is dinamically changed. I might add or remove file in table
folder.
Upvotes: 0
Views: 432
Reputation: 114478
I would suggest doing most of the work automatically. You can register your modules of interest in tasker.table.__init__
:
table_registry = ['user', 'task', ...]
You don't need to import anything at this point and I wouldn't recommend using __all__
as it serves a different purpose altogether. The advantage of using a manually created list is that your package can contain other modules without any interference.
Now tasker.tasker
can do all the work dynamically:
from .table import table_registry
from importlib import import_module
pkg = 'tasker.table'
for name in table_registry:
mod = import_module('.' + name, package=pkg)
name = name.titlecase()
# Check if module contains uppercased class name
if hasattr(mod, name):
cls = getattr(mod, name)
# Check if it's a class
if isinstance(cls, type):
# Assign to current module
globals()[name] = cls
del name, mod, cls
If you don't want to bother with manually registering your modules of interest, you can dynamically discover them using the utilities in pkgutil
. In This version, tasker.table.__init__
can remain empty. tasker.tasker
will get the module list like this:
from pkgutil import walk_packages
from importlib import import_module
for info in walk_packages(tasker.table.__path__, prefix='tasker.table.'):
if info.ispkg: continue
mod = import_module(info.name)
name = info.name.split('.')[-1].titlecase()
if hasattr(mod, name):
...
The remainder of the code is the same as for the manual version. This version will recurse into any sub-packages it finds. It will work fine as long as you don't do anything crazy with your __path__
attributes.
Upvotes: 2
Reputation: 4018
you can import all modules inside a package at once using asterisks:
from table import *
Upvotes: 0