How to export classes, methods or constants in a Python module

Question:

Hello, I'm starting to work with Python and I have a good experience with Typescript. In Typescript, I tend to create modules when I need to organize my code, like this:

<rootDir>
    domain
        index.ts
        person.ts
    models
        index.ts
        person.model.ts

Where in the index.ts files I export the content of the file when necessary, as well as in the file itself, like this:

/domain/person.ts

export class Person { ... }

/domain/index.ts

export * from './person'

If I try to access these elements inside the models module, I would just have to do this:

/models/person.model.ts

import { Person } from '../domain'
export class PersonModel extends Person { ... }

In Python, I'm creating the following structure:

<rootDir>
    domain
        __init_.py
        person.py
    models
        __init.py
        person_model.py

where do i have the classes

/domain/person.py

class Person():
    ...

And I try to pull the Person class inside the model module file so that I can define it in the PersonModel class creation like this:

/models/person_model.py

from domain import product

class ProductModel(product.Product):
    ...

My question is the following:

  • If I'm using modules in Python, why can't I directly import the Product class like I do in Typescript?
  • Is there any configuration needed to be able to use it this way?

NOTE: the intention of this question is to open my knowledge and be able to assimilate Python in a simpler way based on what I have of Typescript and thus learn faster…

Answer:

Inside the "models" folder, your Python modules will only see the files and folders that are there, and whatever is in the PYTHONPATH.

So, you use either the full name of the "domain" folder, including the project name:

from meuprojeto.domain.person import Person

Or use relative import by adding a "." in addition to the first in the module prefix, for each folder you want to "up":

from ..domain.person import Person

(It only works if that particular .py file is imported as part of the whole project too, that is, its path will be meuprojeto.models.person_model )

In both cases, Python needs to be viewing its module hierarchy as a package – that is, "myproject" above the "domain" and "models" folders must be on the Pythonpath. In general, when we create a project in Python, this outermost folder will have a "setup.py" file with the installation information – if you have setup.py, run the command "pip install -e ." in that folder (above "myproject") – this will assume that the project you are editing and creating is part of the Python environment you are using. So, being in any folder on your computer, you can call just the specific file with a line like python3 -m meuprojeto.models.person_model . If you don't have setup.py, just call the interpreter from this folder, above "myproject", or include it in the "PYTHONPATH" environment variable.

"exporting"

In Python, all objects in all modules are visible to any code – what defines whether they are public or not is the convention: if the name of the file, variable or object starts with "_", users of that project/module should not mess with it directly. So no need to export –

Now in practice, it is common to have things "more public" than others – let's suppose that inside your "domain/person.py" file there are several helper-functions that make sense for the methods of the Person class, but that are not for someone "outside" to use. Placing all these functions as "private" with names starting with "_" will only mess up their readability. What you usually do is expose the highest level class – the names your project user will actually use – in the __init__.py file in each folder.

So you could inside domain.__init__.py a from .person import Person . Then, other packages that use this model will do: from meuprojeto.domain import Person (instead of from meuprojeto.domain.person import Person ).

In large projects it might be desirable not to have to keep editing __init__ to include all classes from all files in that folder, so it might be ok to have some code using for and filesystem introspection even to do the imports automatically – but this type of code usually stays in the framework, not the project.

And, for the sake of completeness, Python also makes use of the module variable __all__ to indicate which names are going to be imported with "*" in that module.

So, going back to the case that "persons.py" has some classes that you want to make "more public", and various helper-functions and module variables – you can at the end of the persons.py file put:

__all__ = ["Person", "OtherPerson", "VIPerson"]  # (as classes públicas)

and in the corresponding __init__.py use from .person import * , to bring only the objects that have the names in __all__

Scroll to Top