1
\$\begingroup\$

There's something I completely dislike when importing a module in an interactive Python shell, typing the name of the module, hitting tab and getting the automatic completion cluttered with other modules that the module itself had imported (but are internal implementation details that are not really useful for me).

Example:

a.py

import os
import datetime

def foo():
    now = datetime.datetime.now()
    print os.path.join(map(str, (now.year, now.month, now.day)))

shell

$ ipython 
Python 2.7.15rc1 (default, Nov 12 2018, 14:31:15) 
Type "copyright", "credits" or "license" for more information.

IPython 5.5.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import a

In [2]: a.
           a.datetime a.py       
           a.foo      a.pyc      
           a.os                  

I don't care that module a depends on datetime and os, that is distracting me from what the module provides (foo).

So I have started to make my imports private, like this:

a.py

import os as _os
import datetime as _datetime

def foo():
    now = _datetime.datetime.now()
    print _os.path.join(map(str, (now.year, now.month, now.day)))

shell

$ ipython 
iPython 2.7.15rc1 (default, Nov 12 2018, 14:31:15) 
Type "copyright", "credits" or "license" for more information.

IPython 5.5.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import a

In [2]: a.
           a.foo 
           a.py  
           a.pyc 

Is this considered pythonic at all? I feel like it's a little bit too verbose, but I think simplifying the end user's experience should be above saving some extra tokens per import.

\$\endgroup\$

closed as off-topic by 200_success, ferada, Sᴀᴍ Onᴇᴌᴀ, Toby Speight, Ludisposed Feb 27 at 12:58

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Lacks concrete context: Code Review requires concrete code from a project, with sufficient context for reviewers to understand how that code is used. Pseudocode, stub code, hypothetical code, obfuscated code, and generic best practices are outside the scope of this site." – 200_success, ferada, Sᴀᴍ Onᴇᴌᴀ, Toby Speight, Ludisposed
If this question can be reworded to fit the rules in the help center, please edit the question.

3
\$\begingroup\$

NO

This is not pythonic... and this is ugly... aaah, I can't get that code out of my head...

There is this thing called __all__

1. How does it work

Make a list, put everything you want to make public in it and boom, you're done.

2. What it doesn't do

You will still be able to do my_module.datetime if datetime is imported in my_module

3. What does it do

When you do from my_module import *, it doesn't import datetime. Autocomplete will use __all__ if it exist.

4. What are some great conventions that goes with this

You can put it in the __init__.py if it exists

5. Show me

Numpy uses the warning module but it doesn't pollute your namespace.

>>> import numpy
>>> 'warnings' in dir(numpy)
True
>>> 'warnings' in numpy.__all__
False
>>> from numpy import *
>>> warnings
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'warnings' is not defined

Update:

Every autocomplete in the world* uses __all__ except ipython which uses "some custom logic"(github issue). So I believe the most pythonic solution is go complain on the github issue.

*extrapolation of "the editors I use"

\$\endgroup\$
  • \$\begingroup\$ I already considered using __all__ for this purpose, but I rejected it because: 1. doing wildcard imports is usually discouraged (see PEP-8) 2. the default mechanism for introspection is dir, so if it shows in dir it makes sense that it is public. 3. it needs to be kept in sync manually. p.s. your hubris is also quite ugly and I can't get it out of my head either, so I guess we are even. \$\endgroup\$ – fortran Feb 28 at 15:03
  • \$\begingroup\$ @fortran "if it shows in dir it makes sense that it is public", What ? Everything shows in dir, public or private, beginning with _ or not. Also, that's how python works, if you like it or not. If you do import antigravity, you can access sys by doing antigravity.webbrowser.subprocess.os.sys for example. __all__ is the way to go, and from what I've heard, that bug in IPython will be solved in the future. So no your solution is not pythonic, but who needs a pythonic solution when you have a solution that works. \$\endgroup\$ – Benoît Pilatte Feb 28 at 15:42
  • \$\begingroup\$ You are absolutely correct about dir (I was thinking about something else), but the other two points still hold. I was aware that my solution wasn't Pythonic and that's why I asked for a better one, but yours is more flawed and it came with some attitude that was totally unasked for. \$\endgroup\$ – fortran Feb 28 at 15:56
  • \$\begingroup\$ I'm sorry, I was trying to be helpful, if I was not, I failed. I didn't want to criticise you personally, I wanted to criticise your code. I apologise if I've hurt your feelings. At least we agree your solution is an ugly workaround. But, my point is, use __all__ because otherwise, when IPython is fixed, you will still have ugly code. Writing ugly code to have slightly better autocompletion (until fixed) isn't worth it in my opinion. \$\endgroup\$ – Benoît Pilatte Feb 28 at 16:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.