Search code examples
pythongetattr

Trying to understand __init__.py combined with getattr


I am trying to understand a piece of Python code.

First, I have the following file structure:

folder1--
   model
     __init__.py
     file1.py
     file2.py
  __init__.py

The __init__.py in the folder folder1 has nothing. The __init__.py in the folder model has the following:

import os
files = os.listdir(os.path.split(os.path.realpath(__file__))[0])
files.remove('__init__.py')
for file in files:
    if file.endswith('.py'):
        exec('from .{} import *'.format(file[:-3]))

With that said, I have some code in python that uses all the above Now, I am trying to understand the following code

from folder1 import model as mymodel

My first question is what does this do? I mean model is a folder name right? it is not an object. or is it? What is exactly importing as mymodel here?

then later in the same code it says

global args, cfg, is_fov120
args = parser.parse_args()
model = getattr(mymodel, args.arch)(sync_bn=False)

Apparently there is some arguments called arch. What is happening here and what does model have after this?

Edit

When I do print(mymodel)

I get <module 'folder1.model' from 'C:\\path\\to\\folder1\\model\\__init__.py'>

Investigating even more I can see that I have imported all the objects from the files in the folder model.

mymodel.files gives the list of files in the folder, and I can call mymodel.somevariable if some variable was defined in file1.py or file2.py. As for classes I have to create an object first like x=mymodel.aClass() and then I can access the elements of the object x.someElement.

Finally I found out that getattr is getting a class from the files inside model and I can guess that the sync_bn=False is a parameter to the constructor of that class.

So in the end, model is an object of that class.


Solution

  • If you desire to have a folder as a python module, the folder must contain an __init__.py, even if it is empty. Then you can import the rest.

    import os
    files = os.listdir(os.path.split(os.path.realpath(__file__))[0]) #get the folder's content
    files.remove('__init__.py')                                      #remove __init__.py since it is empty
    for file in files:                                               #loop through the files
        if file.endswith('.py'):                                     #if it is a python file
            exec('from .{} import *'.format(file[:-3]))              #import
    

    The above code, imports every other .py files than the __init__, which is empty.


    from folder1 import model as mymodel
    

    Here folder1 is the module, and model is the object you imported from (folder) model in this case, since it is now imported to folder1's __init__.py, and now it is part of folder1 (which is a module as discussed).


    model = getattr(mymodel, args.arch)(sync_bn=False)
    

    This line is equal to: mymodel.attr, where attr is the desired attribute of the object. Can you please post more code around the getattr, since I can't tell what args.arch are refering to.

    As Pyzard suggested, the getattr method gets an attribute, which is a function, since it is getting called, and method is the value that this function returned. In this case sync_bn is irrevelant, but knowing more about args.arch would still help.


    More about the getattr function, how import works. Better explanation of how init.py works.