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

Asked

Viewed 799 times

4

Hello, I’m starting to work with Python and have a good experience with Typescript. In Typescript, I have a habit of creating modules when I need to organize my code, so:

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

Where in the archives index.ts i do export the contents of the file when necessary, as well as in the file itself, so:

/Domain/person.ts

export class Person { ... }

/Domain/index.ts

export * from './person'

If I try to access these elements within the module models, I’d just have to do it:

/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 I have the classes

/Domain/person.py

class Person():
    ...

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

/models/person_model.py

from domain import product

class ProductModel(product.Product):
    ...

My question is this::

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

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

  • 1

    Would not be from domain.product import Product what do you want?

  • The intention is exactly not to need access to domain.product so I can get to this class. In Typescript this is called "Barrel", I’m seeing how I could use this feature in Python to be clearer the logic of the solutions

  • 1

    But in TS you didn’t import { Person } from '../domain'? Access the same "Domain", no?

  • For you to access Person, that’s inside domain, it has to be declared as exported inside the index file, otherwise you have to access her file directly using domain/person...

1 answer

6


Inside the folder "models" your Python modules will see only the files and folders inside, and whatever is on PYTHONPATH.

Then, 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 prefix module, for each folder you want to "go up":

from ..domain.person import Person

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

In both cases, it is necessary that Python is viewing its module hierarchy as a package - that is, it is necessary that the "meuprojeto", above the folders "Domain" and "models" is in Pythonpath. In general, when we create a Python project, this most external folder will have a "setup.py" file with the installation information - if you have setup.py, run the "Pip install -e." in this folder (above the "myproject") - this will consider that the project you are editing and creating is part of the Python environment you are using. Then, being in any folder on your computer, you can only call 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 that folder, above the "meuprojeto", or include it in the environment variable "PYTHONPATH".

"exporting"

In Python, all objects of 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 this project/module should not mess with it directly. So there is no need to export -

Now in practice, it is common to have "more public" things than others - let’s assume that within your "Domain/person.py" file there are several helper-functions that make sense for the methods of the Person class, but that there is no reason for someone "from the outside" to use. Harvesting all these functions as "private" with names starting with "_" will only disrupt their readability. What you usually do is expose the highest-level class - the names the user of your project will actually use - in the file __init__.py of each folder.

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

In large projects, it may be desirable not to keep editing the __init__ to include all classes of all files in that folder, so it might be ok to have some code using for and introspection of the file system even to make imports automatically - but this type of code generally stays in the framework, not in the project.

And, for the purpose of making the answer complete, Python also makes use of the module variable __all__ to indicate which names will be imported with "*" in that module.

So, going back to the case that "Persons.py" has some classes that you want to leave as "more public", and several helper-functions and module variables - you can at the end of the file persons.py place:

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

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

  • really I realized that I can do something very similar to what I do in Typescript (export * from './persons') on declaring from .persons import *

Browser other questions tagged

You are not signed in. Login or sign up in order to post.