Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I prevent users from importing x from a submodule when it exposed in the parent using __all__

Consider the following scenario:

  • You have a module M defined in m.py containing a function f.

    It can be called like this:

    import M;
    M.f()
    
  • The module grows to a size where it is impractical to have in a single file. You split M up into submodules M.X, M.Y, M.Z and put the following in M/__init__.py:

    from .X import *
    from .Y import *
    from .Z import *
    
    __all__ = ["f"]
    

    The original code still works:

    import M;
    M.f()
    

However, new consumers of the code may mistakenly access the submodule directly:

import M.X;
M.X.f()

I would like to prevent this, such that all code is still consistently addressing M directly, and not any of the submodules.

The submodules are for the benefit of internal code organisation, and referencing M leaves the possibility of easy reorganisation in the future.

One option would be to name the submodules _X, _Y, and _Z to communicate that they are internal. Is that the recommended approach?

like image 966
Daniel Fortunov Avatar asked Mar 20 '13 14:03

Daniel Fortunov


1 Answers

One option would be to name the submodules _X, _Y, and _Z to communicate that they are internal. Is that the recommended approach?

As you don't want people to access M.X, you will need to move the X.py module so it is no longer available as M.X. You could delete it as Kaie suggests, but ugh. Therefore yes, your suggestion is the recommended approach.

  1. Move M/X.py to M/_X.py

  2. In M/__init__.py have the line from ._X import f

As others have suggested, it shouldn't really be a problem that people can access the code and it's habits of programming in a language with stronger encapsulation seeping into your Python designs.

The submodules are for the benefit of internal code organisation, and referencing M leaves the possibility of easy reorganisation in the future.

Yes this is a concern I had when coming from C and C++ and dealing with ABIs all day. But it's often not an issue if the code is small and well tested enough. And this is the kind of thing that you can trivially fix later. If you one day decide to reorganize the code to have X as _X then I'm sure Jenkins can tell you what else needs to be updated. :)

like image 143
Ewan Higgs Avatar answered Oct 05 '22 10:10

Ewan Higgs