0

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.

0

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

7 Comments

@abdul_niyas_pm. Your answer wasn't that bad. There was no need to delete it.
I don't understand part globals()[name] = cls(). Is that putting an instance of class inside a variable? Is that mean variable User is already an instance and not a class? Because I want to instantiate class multiple times inside tasker.tasker. Is it okay if I write globals()[name] = cls instead?
@fahadh4ilyas. Yes of course. I misunderstood your requirement
I've tried it and it's working. But, it's kind of slow when I do from tasker.tasker import something. Is it because for loop?
That being said, Python will only run that loop once. The first import from tasker may be slow, but the second and following shouldn't be.
|
0

This might work

from table import user

user.User()

1 Comment

It's working but I have to manually write from table import module. Is there any way to do it dinamically?
0

you can import all modules inside a package at once using asterisks:

from table import *

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.