One of my developers recently submitted a pull request incuding a number of lines like import os as _os When I asked him why he suggested a) this would improve encapsulation, and b) the practice was supported in the stdlib. Further investigation reveals that some modules (e.g. argparse, crypt, difflib, random) do use this technique, but it is far from universal. So I thought it would be useful to get input from current devs about the value of this practice, since to me it seems somewhat anti-pythonic. What advantages does it confer? regards Steve Holden
On Jan 09, 2017, at 11:42 AM, Steve Holden wrote:
So I thought it would be useful to get input from current devs about the value of this practice, since to me it seems somewhat anti-pythonic. What advantages does it confer?
It just means you can't accidentally import it with a from-import-* since those ignore underscored names by default. (But then if you use __all__'s it won't happen anyway because you'll never put 'os' in __all__.) (Aside from the fact that from-import-* is usually bad form, and the problem with __all__ <wink> [1].) Cheers, -Barry [1] http://public.readthedocs.io/en/latest/#the-problem
On 9 January 2017 at 11:42, Steve Holden <steve@holdenweb.com> wrote:
One of my developers recently submitted a pull request incuding a number of lines like
import os as _os
When I asked him why he suggested a) this would improve encapsulation, and b) the practice was supported in the stdlib. Further investigation reveals that some modules (e.g. argparse, crypt, difflib, random) do use this technique, but it is far from universal.
So I thought it would be useful to get input from current devs about the value of this practice, since to me it seems somewhat anti-pythonic. What advantages does it confer?
As I understand it, it prevents the imports showing up in "import *" imports, but using __all__ is better. I'd imagine usage in the stdlib is mainly historical. It's not a practice I'd recommend in user code. The needs of the stdlib are somewhat special (and stdlib code can be many years old, reflecting out of date design rules) and "because the stdlib does it" is not necessarily a compelling argument in the absence of an actual justification. Regarding "improves encapsulation", as Barry mentioned, using __all__ (and avoiding import-* anyway) is a better approach. Furthermore, Python does not encourage strict (as in, enforced, encapsulation). This is very much a "consenting adults" situation - by hiding imports like this, you make it harder to monkeypatch (for testing purposes, for example). Users are meant to stick to the published API of a module *because it's the right thing to do*, not because they are forced to. Paul
On 01/09/2017 03:42 AM, Steve Holden wrote:
When I asked him why he suggested a) this would improve encapsulation, and b) the practice was supported in the stdlib. Further investigation reveals that some modules (e.g. argparse, crypt, difflib, random) do use this technique, but it is far from universal.
So I thought it would be useful to get input from current devs about the value of this practice, since to me it seems somewhat anti-pythonic. What advantages does it confer?
Aside from what Barry said it also offers the (very) minor advantage of showing up as an implementation detail when someone does a dir() of the module. Personally, I tend to use the technique for new code, but I wouldn't change old code for it (and new code in an old module should follow the old module's practices, etc.) . -- ~Ethan~
I would focus on changing habits to discourage "import *" rather than uglifying all new code with this "os as _os" pattern. Very occasionally one designs a module to explicitly support "import *", and that usually entails using __all__ (like it or not), making the problem go away without uglifying the code. -- --Guido van Rossum (python.org/~guido)
On 1/9/2017 11:48 AM, Guido van Rossum wrote:
I would focus on changing habits to discourage "import *" rather than
The tkinter doc still has ...to use Tkinter all you need is a simple import statement: import tkinter Or, more often: from tkinter import * Should this be changed?
uglifying all new code with this "os as _os" pattern. Very occasionally one designs a module to explicitly support "import *", and that usually entails using __all__ (like it or not), making the problem go away without uglifying the code.
tkinter does not have have __all__. It would have 160 (in 3.6) minus at least 3 (for enum, re, and sys) entries. -- Terry Jan Reedy
On Mon, Jan 9, 2017 at 12:29 PM, Terry Reedy <tjreedy@udel.edu> wrote:
The tkinter doc still has
...to use Tkinter all you need is a simple import statement: import tkinter Or, more often: from tkinter import *
Should this be changed?
yes, it should. I would suggest suggesting something like: import tkinter as tk following the similar convention of wxPython, numpy, matplotlib, (all large widely used packages that started their lives with import * recommendations...) -CHB -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On 1/9/2017 6:42 AM, Steve Holden wrote:
One of my developers recently submitted a pull request incuding a number of lines like
import os as _os
When I asked him why he suggested a) this would improve encapsulation, and b) the practice was supported in the stdlib. Further investigation reveals that some modules (e.g. argparse, crypt, difflib, random) do use this technique, but it is far from universal.
So I thought it would be useful to get input from current devs about the value of this practice, since to me it seems somewhat anti-pythonic. What advantages does it confer?
If the module does not define __all__, it prevents * imports of the module from also importing the imported modules. For instance:
sys Traceback (most recent call last): File "<pyshell#1>", line 1, in <module> sys NameError: name 'sys' is not defined from tkinter import * sys <module 'sys' (built-in)> enum <module 'enum' from 'C:\\Programs\\Python36\\lib\\enum.py'> itertools Traceback (most recent call last): File "<pyshell#5>", line 1, in <module> itertools NameError: name 'itertools' is not defined
Use of such undocumented and unintended attributes of a module is fragile. 1. The imported module could be changed. Tkinter's 'import enum' in only used in "class EventType(str, enum.Enum):". The import could well be changed to 'from enum import Enum' or even better, 'from enum import Enum as _Enum' and the one use modified. 2. The importing module could be changed. 'from tkinter import *' might be changed to 'from tkinter import tk, ...' or 'import tkinter as tk' or even replaced by another module. -- Terry Jan Reedy
* Steve Holden wrote:
One of my developers recently submitted a pull request incuding a number of lines like
import os as _os
When I asked him why he suggested a) this would improve encapsulation, and b) the practice was supported in the stdlib. Further investigation reveals that some modules (e.g. argparse, crypt, difflib, random) do use this technique, but it is far from universal.
So I thought it would be useful to get input from current devs about the value of this practice, since to me it seems somewhat anti-pythonic. What advantages does it confer?
For me (in favor of underscored imports), the following items apply: - the imports are usually not part of the exported API. (If they are, I specifically do not underscore them) - __all__ was referenced in other answers. However, it only protects from a single use case (import *). It does not help you directly with shells (dir(), ipython tab expansion (?)) and it's easy to ignore if you look at the source code itself (because, let's face it, documentation often sucks). - __all__ again: it's tedious and error-prone to maintain. I often found places in my own code where it was plain wrong. (pylint helps these days against wrongness, but not against incompleteness) - In my code (inside the module): I usually know exactly what variable is a module and what is not (by the underscores) - Also in my code - from time to time the modules steal good names for local variables, underscoring also solved this problem for me. Cheers, nd -- die (eval q-qq:Just Another Perl Hacker :-) # André Malo, <http://pub.perlig.de/> #
On Jan 09, 2017, at 06:23 PM, André Malo wrote:
- __all__ again: it's tedious and error-prone to maintain.
Only if you use the wrong tools <wink> http://public.readthedocs.io/en/latest/ http://bugs.python.org/issue26632 Cheers, -Barry
Interesting to see that others have the same problem. We also had this kind of "over-protective" behavior. As far as I know, our devs stopped doing it as it feels cumbersome. Another argument for this is: when using PyCharm, this IDE will suggest imports from those modules which aren't the original ones. So, you might import from a third-party module. Over time, however, people learn to pick the "right" module to import from. Cheers, Sven On 09.01.2017 12:42, Steve Holden wrote:
One of my developers recently submitted a pull request incuding a number of lines like
import os as _os
When I asked him why he suggested a) this would improve encapsulation, and b) the practice was supported in the stdlib. Further investigation reveals that some modules (e.g. argparse, crypt, difflib, random) do use this technique, but it is far from universal.
So I thought it would be useful to get input from current devs about the value of this practice, since to me it seems somewhat anti-pythonic. What advantages does it confer?
regards Steve Holden
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/srkunze%40mail.de
Easily solved with the totally evil ninja mode pattern of module initialization. It has yet to catch on. def ninja(): global exported import os def exported(): # do something ninja() del ninja On Mon, Jan 9, 2017 at 1:13 PM Sven R. Kunze <srkunze@mail.de> wrote:
Interesting to see that others have the same problem.
We also had this kind of "over-protective" behavior. As far as I know, our devs stopped doing it as it feels cumbersome.
Another argument for this is: when using PyCharm, this IDE will suggest imports from those modules which aren't the original ones. So, you might import from a third-party module. Over time, however, people learn to pick the "right" module to import from.
Cheers, Sven
On 09.01.2017 12:42, Steve Holden wrote:
One of my developers recently submitted a pull request incuding a number of lines like
import os as _os
When I asked him why he suggested a) this would improve encapsulation, and b) the practice was supported in the stdlib. Further investigation reveals that some modules (e.g. argparse, crypt, difflib, random) do use this technique, but it is far from universal.
So I thought it would be useful to get input from current devs about the value of this practice, since to me it seems somewhat anti-pythonic. What advantages does it confer?
regards Steve Holden
_______________________________________________ Python-Dev mailing listPython-Dev@python.orghttps://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/srkunze%40mail.de
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/dholth%40gmail.com
participants (10)
-
André Malo
-
Barry Warsaw
-
Chris Barker
-
Daniel Holth
-
Ethan Furman
-
Guido van Rossum
-
Paul Moore
-
Steve Holden
-
Sven R. Kunze
-
Terry Reedy