Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #103470 > unrolled thread
| Started by | Dan Stromberg <drsalists@gmail.com> |
|---|---|
| First post | 2016-02-24 17:07 -0800 |
| Last post | 2016-02-26 15:37 +1100 |
| Articles | 13 — 9 participants |
Back to article view | Back to comp.lang.python
"from module import data; print(data)" vs "import module; print(module.data)" Dan Stromberg <drsalists@gmail.com> - 2016-02-24 17:07 -0800
Re: "from module import data; print(data)" vs "import module; print(module.data)" Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2016-02-25 14:39 +1100
Re: "from module import data; print(data)" vs "import module; print(module.data)" Dan Stromberg <drsalists@gmail.com> - 2016-02-25 08:15 -0800
Re: "from module import data; print(data)" vs "import module; print(module.data)" Dan Stromberg <drsalists@gmail.com> - 2016-02-25 08:20 -0800
Re: "from module import data; print(data)" vs "import module; print(module.data)" Ethan Furman <ethan@stoneleaf.us> - 2016-02-25 08:35 -0800
Re: "from module import data; print(data)" vs "import module; print(module.data)" Ethan Furman <ethan@stoneleaf.us> - 2016-02-25 08:51 -0800
Re: "from module import data; print(data)" vs "import module; print(module.data)" sohcahtoa82@gmail.com - 2016-02-25 12:00 -0800
Re: "from module import data; print(data)" vs "import module; print(module.data)" Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2016-02-26 11:20 +1300
Re: "from module import data; print(data)" vs "import module; print(module.data)" Ben Finney <ben+python@benfinney.id.au> - 2016-02-26 10:38 +1100
Re: "from module import data; print(data)" vs "import module; print(module.data)" Steven D'Aprano <steve@pearwood.info> - 2016-02-26 11:40 +1100
Re: "from module import data; print(data)" vs "import module; print(module.data)" Ian Kelly <ian.g.kelly@gmail.com> - 2016-02-25 20:56 -0700
Re: "from module import data; print(data)" vs "import module; print(module.data)" Chris Angelico <rosuav@gmail.com> - 2016-02-26 15:11 +1100
Re: "from module import data; print(data)" vs "import module; print(module.data)" Ben Finney <ben+python@benfinney.id.au> - 2016-02-26 15:37 +1100
| From | Dan Stromberg <drsalists@gmail.com> |
|---|---|
| Date | 2016-02-24 17:07 -0800 |
| Subject | "from module import data; print(data)" vs "import module; print(module.data)" |
| Message-ID | <mailman.111.1456362461.20994.python-list@python.org> |
Could people please compare and contrast the two ways of doing imports in the Subject line? I've long favored the latter, but I'm working in a code base that prefers the former. Is it fair to say that the former increases the surface area of your shared (sometimes mutable) state? It's clear that the former saves keystrokes. I find the latter a little more clear, because you don't have to go look for where a symbol came from. Anything else? Thanks! PS: Haskell seems better at the former than Python; Haskell tells you if you import two identical symbols from two different places, when you try to use one of them - not at import time. I believe in Python, whichever symbol you import last, wins. Haskell does not warn you at import time, which is fine. Not sure about OCaml or whatever else.
[toc] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2016-02-25 14:39 +1100 |
| Message-ID | <56ce7762$0$11100$c3e8da3@news.astraweb.com> |
| In reply to | #103470 |
On Thursday 25 February 2016 12:07, Dan Stromberg wrote:
> Could people please compare and contrast the two ways of doing imports
> in the Subject line?
from module import data; print(data)
import module; print(module.data)
> I've long favored the latter, but I'm working in a code base that
> prefers the former.
>
> Is it fair to say that the former increases the surface area of your
> shared (sometimes mutable) state?
No, I can't say that it is. If anything, the opposite is the case: it
decreases the surface area, because `data` now is local to the importing
(not imported) module. Rebinding data will not affect anything else.
There are two scenarios (`from module import...` versus `import ...`), each
with two cases: mutation, and rebinding:
(1) from module import data
(a) Mutation (only applies to mutable data like lists, dicts etc)
In place mutation affects everything relying on module.data regardless of
how or where it is accessed.
(b) Rebinding (e.g. `data = []`)
Because data is now a local name, you only affect the local scope.
(2) import module
(a) Mutation is no different from (1)(a) above. No change.
(b) Rebinding `module.data = []` affects the imported module, and therefore
everything that relies on it.
So the `from module import data` scenario reduces the number of ways that
you can affect other modules. That may be important to you, but usually the
answer to that is "well don't rebind attributes of modules unless you really
mean to". Sometimes doing `module.data = ...` is not a bad thing.
On the other hand, seeing something like:
module.data.append(999)
should stand out to a reasonably experienced developer as possibly effecting
other modules. But:
data.append(999)
may fool them into thinking that the change is only local to the current
module. Dangerous things should look dangerous: this is a point in favour of
using `import module` in preference to `from`.
> It's clear that the former saves keystrokes.
Code is read about 100 times more than it is written. Saving keystokes
should be quite low on the list of priorities.
It also saves line width, which may sometimes impact readability. But then
readability is only weakly correlated to line length. As you say:
> I find the latter a little more clear, because you don't have to go
> look for where a symbol came from.
which is also a very good point.
Personally, I prefer the `import module` over `from module` except when I
don't. Consequently I will sometimes even use both in the same module:
import os
from itertools import zip_longest
depending on what's more convenient and useful for each.
I think that having a hard rule that you MUST use one or the other is silly,
but I guess that since Python makes "brace wars" irrelevant people need to
find something else to argue about.
http://encyclopedia2.thefreedictionary.com/1+true+brace+style
> PS: Haskell seems better at the former than Python; Haskell tells you
> if you import two identical symbols from two different places, when
> you try to use one of them - not at import time. I believe in Python,
> whichever symbol you import last, wins. Haskell does not warn you at
> import time, which is fine. Not sure about OCaml or whatever else.
Haskell assumes that importing the same style from two places is an error
that needs warning about. I don't think it is, any more than:
s = 'foo'
s = 'bar'
is necessarily an error (particular if the two rebindings are separated by
code that does things). Both `import` and `from ... import` are rebinding
operations, like = assignment.
--
Steve
[toc] | [prev] | [next] | [standalone]
| From | Dan Stromberg <drsalists@gmail.com> |
|---|---|
| Date | 2016-02-25 08:15 -0800 |
| Message-ID | <mailman.128.1456416920.20994.python-list@python.org> |
| In reply to | #103477 |
On Wed, Feb 24, 2016 at 7:39 PM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > On Thursday 25 February 2016 12:07, Dan Stromberg wrote: > >> Could people please compare and contrast the two ways of doing imports >> in the Subject line? > > from module import data; print(data) > > import module; print(module.data) >> Is it fair to say that the former increases the surface area of your >> shared (sometimes mutable) state? > > No, I can't say that it is. If anything, the opposite is the case: it > decreases the surface area, because `data` now is local to the importing > (not imported) module. Rebinding data will not affect anything else. > There are two scenarios (`from module import...` versus `import ...`), each > with two cases: mutation, and rebinding: > > (1) from module import data > > (a) Mutation (only applies to mutable data like lists, dicts etc) > > In place mutation affects everything relying on module.data regardless of > how or where it is accessed. We have some scenarios where "data" is an instance of a class, and we need to monkey patch it for unit testing. My intuition is telling me that "module.data; data.mutate()" would be easier to monkey patch in a way that all modules will see. Is that fair to say? Thanks.
[toc] | [prev] | [next] | [standalone]
| From | Dan Stromberg <drsalists@gmail.com> |
|---|---|
| Date | 2016-02-25 08:20 -0800 |
| Message-ID | <mailman.129.1456417740.20994.python-list@python.org> |
| In reply to | #103477 |
On Thu, Feb 25, 2016 at 8:15 AM, Dan Stromberg <drsalists@gmail.com> wrote: > On Wed, Feb 24, 2016 at 7:39 PM, Steven D'Aprano > <steve+comp.lang.python@pearwood.info> wrote: >> On Thursday 25 February 2016 12:07, Dan Stromberg wrote: >> >>> Could people please compare and contrast the two ways of doing imports >>> in the Subject line? >> >> from module import data; print(data) >> >> import module; print(module.data) > >>> Is it fair to say that the former increases the surface area of your >>> shared (sometimes mutable) state? >> >> No, I can't say that it is. If anything, the opposite is the case: it >> decreases the surface area, because `data` now is local to the importing >> (not imported) module. Rebinding data will not affect anything else. > >> There are two scenarios (`from module import...` versus `import ...`), each >> with two cases: mutation, and rebinding: >> >> (1) from module import data >> >> (a) Mutation (only applies to mutable data like lists, dicts etc) >> >> In place mutation affects everything relying on module.data regardless of >> how or where it is accessed. > > We have some scenarios where "data" is an instance of a class, and we > need to monkey patch it for unit testing. > > Please ignore: My intuition is telling me that "module.data; data.mutate()" would be > easier to monkey patch in a way that all modules will see. Is that > fair to say? > > Thanks. Correction! My intuition is telling me that "module.data; module.data.mutate()" would be easier to monkey patch in a way that all modules will see. Is that fair to say?
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2016-02-25 08:35 -0800 |
| Message-ID | <mailman.130.1456418103.20994.python-list@python.org> |
| In reply to | #103477 |
On 02/24/2016 07:39 PM, Steven D'Aprano wrote: > (2) import module > > (a) Mutation is no different from (1)(a) above. No change. > > (b) Rebinding `module.data = []` affects the imported module, and therefore > everything that relies on it. More accurate: and therefore everything that has not already done a `from module import data` as those will be unaffected by the rebinding. -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2016-02-25 08:51 -0800 |
| Message-ID | <mailman.131.1456419044.20994.python-list@python.org> |
| In reply to | #103477 |
On 02/25/2016 08:20 AM, Dan Stromberg wrote: > My intuition is telling me that "module.data; module.data.mutate()" > would be easier to monkey patch in a way that all modules will see. > Is that fair to say? It is fair to say that if you need to monkey-patch a module, you should import the module. :) You should also import it before anything else does to make sure your change is visible to all other code. -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | sohcahtoa82@gmail.com |
|---|---|
| Date | 2016-02-25 12:00 -0800 |
| Message-ID | <535b56b5-f836-4cd6-ae95-33f18004c90b@googlegroups.com> |
| In reply to | #103470 |
On Wednesday, February 24, 2016 at 5:07:57 PM UTC-8, Dan Stromberg wrote: > Could people please compare and contrast the two ways of doing imports > in the Subject line? > > I've long favored the latter, but I'm working in a code base that > prefers the former. > > Is it fair to say that the former increases the surface area of your > shared (sometimes mutable) state? > > It's clear that the former saves keystrokes. > > I find the latter a little more clear, because you don't have to go > look for where a symbol came from. > > Anything else? > > Thanks! If I'm only importing a single class or function from a module AND that class or function has a very meaningful name, I will use "from MyModule import MyUsefulClass". Otherwise, I just use "import MyModule". Now, I've noticed people talking about importing os.path. Is there any reason to use "import os.path" rather than "import os"? Both of them will still put the "os" module into the global namespace.
[toc] | [prev] | [next] | [standalone]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2016-02-26 11:20 +1300 |
| Message-ID | <dj9d10F4gciU1@mid.individual.net> |
| In reply to | #103518 |
sohcahtoa82@gmail.com wrote: > Now, I've noticed people talking about importing os.path. Is there any > reason to use "import os.path" rather than "import os"? Both of them will > still put the "os" module into the global namespace. In the case of os.path it doesn't matter, because the os module imports the appropriate path module automatically. But in general, importing a package won't necessarily import submodules under it, so sometimes you need to import somepackage.somemodule explicitly. -- Greg
[toc] | [prev] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2016-02-26 10:38 +1100 |
| Message-ID | <mailman.138.1456443525.20994.python-list@python.org> |
| In reply to | #103520 |
Gregory Ewing <greg.ewing@canterbury.ac.nz> writes:
> sohcahtoa82@gmail.com wrote:
> > Now, I've noticed people talking about importing os.path. Is there any
> > reason to use "import os.path" rather than "import os"? Both of them will
> > still put the "os" module into the global namespace.
>
> In the case of os.path it doesn't matter, because the
> os module imports the appropriate path module automatically.
My position is that behaviour violates one of the principles of the Zen
of Python: “Special cases aren't special enough to break the rules.”
> But in general, importing a package won't necessarily
> import submodules under it, so sometimes you need to
> import somepackage.somemodule explicitly.
Because that's normally the case, I choose not to rely on that special
behaviour of ‘os’. If I need ‘os.path’, I import it explicitly so no
reader needs to guess::
import os
import os.path
--
\ “Crime is contagious… if the government becomes a lawbreaker, |
`\ it breeds contempt for the law.” —Justice Louis Brandeis |
_o__) |
Ben Finney
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2016-02-26 11:40 +1100 |
| Message-ID | <56cf9f01$0$1620$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #103523 |
On Fri, 26 Feb 2016 10:38 am, Ben Finney wrote:
> Gregory Ewing <greg.ewing@canterbury.ac.nz> writes:
>
>> sohcahtoa82@gmail.com wrote:
>> > Now, I've noticed people talking about importing os.path. Is there any
>> > reason to use "import os.path" rather than "import os"? Both of them
>> > will still put the "os" module into the global namespace.
>>
>> In the case of os.path it doesn't matter, because the
>> os module imports the appropriate path module automatically.
>
> My position is that behaviour violates one of the principles of the Zen
> of Python: “Special cases aren't special enough to break the rules.”
But it's not special. It's the standard behaviour of any module which offers
a public name: `import os` makes all the names in the os name space
available. There's no difference between (say) `os.listdir` and `os.path`
except that listdir happens to be a function and path happens to be a
module.
`path` has been a documented public attribute of the `os` module since at
least Python 1.5:
[steve@ando ~]$ python1.5 -c "import os; print os.path"
<module 'posixpath' from '/usr/local/lib/python1.5/posixpath.pyc'>
and likely older. The documentation from help(os) says:
DESCRIPTION
This exports:
- all functions from posix, nt, os2, mac, or ce, e.g. unlink,
stat, etc.
- os.path is one of the modules posixpath, ntpath, or macpath
(The above is from 2.4, the oldest Python I have that supports docstrings;
in 3.3 it is substantially the same except macpath is removed.)
Since `os` is not a package, the fact that importing `os.path` works at all
is surprising. The os module has to make a special effort to support
importing os.path. From the source code:
sys.modules['os.path'] = path
If you take "Special cases are not special enough" seriously, you will not
use `import os.path` since os is not a package:
py> os.__package__
''
and os.path is not part of os, it's just a publicly exposed attribute which
merely happens to be a module. Being a module doesn't make it special, it's
just another name in the os namespace. I trust that you wouldn't insist on
writing:
import os.listdir
(especially since that doesn't work). Neither should you insist on writing
`import os.path`, since path is documented as a public part of the os
module. It has done so since at least Python 1.5.
>> But in general, importing a package won't necessarily
>> import submodules under it, so sometimes you need to
>> import somepackage.somemodule explicitly.
>
> Because that's normally the case, I choose not to rely on that special
> behaviour of ‘os’. If I need ‘os.path’, I import it explicitly so no
> reader needs to guess::
>
> import os
> import os.path
As I have shown above, the fact that os.path is importable at all is the
special case.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-02-25 20:56 -0700 |
| Message-ID | <mailman.139.1456459021.20994.python-list@python.org> |
| In reply to | #103524 |
On Thu, Feb 25, 2016 at 5:40 PM, Steven D'Aprano <steve@pearwood.info> wrote: > If you take "Special cases are not special enough" seriously, you will not > use `import os.path` since os is not a package: > > py> os.__package__ > '' > > and os.path is not part of os, it's just a publicly exposed attribute which > merely happens to be a module. Being a module doesn't make it special, it's > just another name in the os namespace. I trust that you wouldn't insist on > writing: > > import os.listdir > > (especially since that doesn't work). Neither should you insist on writing > `import os.path`, since path is documented as a public part of the os > module. It has done so since at least Python 1.5. I disagree. The fact that os is not a package is an implementation detail. I for one wasn't even aware of it prior to reading your post. The name of the concurrent.futures module is "concurrent.futures". If you want to use it, you import concurrent.futures, not concurrent. Likewise, the name of the os.path module is "os.path". If you want to use it, you import os.path, not os. The fact that concurrent and os are two different types of things is irrelevant. Besides, packages *are* modules. To take another example, collections is a package (I checked), and collections.abc is a module. But collections also contains things that aren't modules. If you want to use collections.abc, you have to import it, but at the same time you don't import collections.Counter. This demonstrates that the analog you suggest between os.path and os.listdir is flawed.
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-02-26 15:11 +1100 |
| Message-ID | <mailman.140.1456459915.20994.python-list@python.org> |
| In reply to | #103524 |
On Fri, Feb 26, 2016 at 2:56 PM, Ian Kelly <ian.g.kelly@gmail.com> wrote: > On Thu, Feb 25, 2016 at 5:40 PM, Steven D'Aprano <steve@pearwood.info> wrote: >> If you take "Special cases are not special enough" seriously, you will not >> use `import os.path` since os is not a package: >> >> py> os.__package__ >> '' >> >> and os.path is not part of os, it's just a publicly exposed attribute which >> merely happens to be a module. Being a module doesn't make it special, it's >> just another name in the os namespace. I trust that you wouldn't insist on >> writing: >> >> import os.listdir >> >> (especially since that doesn't work). Neither should you insist on writing >> `import os.path`, since path is documented as a public part of the os >> module. It has done so since at least Python 1.5. > > I disagree. The fact that os is not a package is an implementation > detail. I for one wasn't even aware of it prior to reading your post. > > The name of the concurrent.futures module is "concurrent.futures". If > you want to use it, you import concurrent.futures, not concurrent. > > Likewise, the name of the os.path module is "os.path". If you want to > use it, you import os.path, not os. > > The fact that concurrent and os are two different types of things is irrelevant. > > Besides, packages *are* modules. To take another example, collections > is a package (I checked), and collections.abc is a module. But > collections also contains things that aren't modules. If you want to > use collections.abc, you have to import it, but at the same time you > don't import collections.Counter. This demonstrates that the analog > you suggest between os.path and os.listdir is flawed. Steven is right, though. You can "from module import X" and it doesn't matter whether 'module' is a package or a non-package module; but if you say "import module.X", aside from special cases like os.path, you're asserting that 'module' is a package and 'X' is a module within that package. Yes, a package is a module, but the dotted lookup requires a package. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2016-02-26 15:37 +1100 |
| Message-ID | <mailman.141.1456461448.20994.python-list@python.org> |
| In reply to | #103524 |
Steven D'Aprano <steve@pearwood.info> writes:
> On Fri, 26 Feb 2016 10:38 am, Ben Finney wrote:
>
> > Gregory Ewing <greg.ewing@canterbury.ac.nz> writes:
> >
> >> sohcahtoa82@gmail.com wrote:
> >> > Now, I've noticed people talking about importing os.path. Is there any
> >> > reason to use "import os.path" rather than "import os"? Both of them
> >> > will still put the "os" module into the global namespace.
> >>
> >> In the case of os.path it doesn't matter, because the
> >> os module imports the appropriate path module automatically.
> >
> > My position is that behaviour violates one of the principles of the Zen
> > of Python: “Special cases aren't special enough to break the rules.”
>
> But it's not special. It's the standard behaviour of any module which offers
> a public name
That is the special behaviour. ‘os’ is a package that has a sub-module
‘path’. Normally, to get at a module inside a package, you import it
with a qualified name::
import os.path
The special case is that ‘os’ also wants the ‘path’ module itself, and
so the name happens to be available as a module attribute. That's a
special case that can not be depended on for other cases.
> `import os` makes all the names in the os name space available.
Since ‘os.path’ is a sub-module of the ‘os’ package, it should not also
be exported from the ‘os’ module attributes. The special case is confusing.
> There's no difference between (say) `os.listdir` and `os.path` except
> that listdir happens to be a function and path happens to be a module.
There's no difference between ‘logging.info’ and ‘logging.config’ except
that ‘info’ happens to be a function and ‘config’ happens to be a
module.
The difference is salient::
>>> import logging
>>> logging.info
<function info at 0x7fa7935bfa60>
>>> logging.config
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'logging' has no attribute 'config'
That's the case normally, when one name is primarily an attribute and
another name is primarily a sub-module. The ‘os.path’ case is not
special enough to break that rule IMO.
> `path` has been a documented public attribute of the `os` module since at
> least Python 1.5:
Then it's been violating that principle for that long :-)
> If you take "Special cases are not special enough" seriously, you will
> not use `import os.path` since os is not a package
The implementation is special. That doesn't exempt it from the principle
that a special case isn't special enough to break expectations.
> and os.path is not part of os, it's just a publicly exposed attribute
> which merely happens to be a module.
You seem to be making my case for me: ‘os’ is indeed special. It goes to
some legth to hide that specialness; I think it doesn't go far enough.
--
\ “If you don't want your beliefs to be ridiculed, don't have |
`\ such ridiculous beliefs.” —Greta Christina, 2011-10-22 |
_o__) |
Ben Finney
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web