Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #80850 > unrolled thread
| Started by | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| First post | 2014-11-15 21:01 -0800 |
| Last post | 2014-11-22 19:33 -0600 |
| Articles | 20 on this page of 54 — 16 participants |
Back to article view | Back to comp.lang.python
PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-15 21:01 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-16 16:16 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" alex23 <wuwei23@gmail.com> - 2014-11-21 10:14 +1000
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-21 11:31 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-20 19:53 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Tim Chase <python.list@tim.thechases.com> - 2014-11-21 04:26 -0600
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-21 07:52 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Tim Chase <python.list@tim.thechases.com> - 2014-11-21 10:12 -0600
Re: PyWart: "Python's import statement and the history of external dependencies" Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-21 10:42 -0700
Re: PyWart: "Python's import statement and the history of external dependencies" Ned Batchelder <ned@nedbatchelder.com> - 2014-11-21 06:32 -0500
Re: PyWart: "Python's import statement and the history of external dependencies" Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-21 08:33 -0700
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-21 10:24 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-22 05:34 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Michael Torrie <torriem@gmail.com> - 2014-11-21 12:05 -0700
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-21 12:29 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Michael Torrie <torriem@gmail.com> - 2014-11-21 15:54 -0700
Re: PyWart: "Python's import statement and the history of external dependencies" Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-21 12:23 -0700
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-21 14:25 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-21 15:21 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-22 10:52 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-21 17:07 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-22 13:36 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-22 02:27 -0700
Re: PyWart: "Python's import statement and the history of external dependencies" sohcahtoa82@gmail.com - 2014-11-21 16:33 -0800
Import a module from a specific file path (was: PyWart: "Python's import statement and the history of external dependencies") Ben Finney <ben+python@benfinney.id.au> - 2014-11-22 11:37 +1100
Re: Import a module from a specific file path Marko Rauhamaa <marko@pacujo.net> - 2014-11-22 08:28 +0200
Re: Import a module from a specific file path (was: PyWart: "Python's import statement and the history of external dependencies") Chris Angelico <rosuav@gmail.com> - 2014-11-22 13:32 +1100
Re: Import a module from a specific file path Ben Finney <ben+python@benfinney.id.au> - 2014-11-22 17:46 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-21 17:32 -0700
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-21 17:48 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2014-11-21 15:38 -0500
Re: PyWart: "Python's import statement and the history of external dependencies" Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-11-22 23:25 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-23 00:00 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-11-23 17:30 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Rustom Mody <rustompmody@gmail.com> - 2014-11-22 22:44 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-23 17:56 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-23 17:59 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2014-11-24 11:37 +1300
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-23 22:25 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-24 17:34 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Mark Lawrence <breamoreboy@yahoo.co.uk> - 2014-11-24 10:34 +0000
Re: PyWart: "Python's import statement and the history of external dependencies" Rick Johnson <rantingrickjohnson@gmail.com> - 2014-11-24 08:51 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Ned Batchelder <ned@nedbatchelder.com> - 2014-11-24 12:06 -0500
Re: PyWart: "Python's import statement and the history of external dependencies" Robin Becker <robin@reportlab.com> - 2014-11-24 17:07 +0000
Re: PyWart: "Python's import statement and the history of external dependencies" Marko Rauhamaa <marko@pacujo.net> - 2014-11-24 19:08 +0200
Re: PyWart: "Python's import statement and the history of external dependencies" Rustom Mody <rustompmody@gmail.com> - 2014-11-24 09:38 -0800
Re: PyWart: "Python's import statement and the history of external dependencies" Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-24 15:34 -0700
Re: PyWart: "Python's import statement and the history of external dependencies" Ben Finney <ben+python@benfinney.id.au> - 2014-11-23 18:43 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-23 18:51 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2014-11-23 11:23 -0500
Re: PyWart: "Python's import statement and the history of external dependencies" Chris Angelico <rosuav@gmail.com> - 2014-11-24 03:36 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Tim Chase <python.list@tim.thechases.com> - 2014-11-22 15:27 -0600
Re: PyWart: "Python's import statement and the history of external dependencies" Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-11-23 12:00 +1100
Re: PyWart: "Python's import statement and the history of external dependencies" Tim Chase <python.list@tim.thechases.com> - 2014-11-22 19:33 -0600
Page 1 of 3 [1] 2 3 Next page →
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2014-11-15 21:01 -0800 |
| Subject | PyWart: "Python's import statement and the history of external dependencies" |
| Message-ID | <066c46c8-a04d-4489-b15a-b603c1b1818b@googlegroups.com> |
Python's attempt to solve the "external dependencies problem"
has yet to produce the results that many people, including
myself, would like.
Actually, Python is not alone in this deficiency, no, Python
is just *ANOTHER* language in a *STRING* of languages over
the years who has *YET AGAIN* implemented the same old
crusty design patterns, packaged them in a shiny metallic
wrapping paper with a big red bow on top, and hoped that no
one would notice the stench...
WELL I NOTICED M.F.!
Before we can formulate a solution to this mess, we must
first obtain an "inside perspective" of the "world" in which a
Python script lives during run-time.
============================================================
Welcome to "Python Gardens": a master planned community
============================================================
Well... urm, sort of. @_@
I like to analyze problems, when possible, in relation to
real world "tangible" examples. So for me, i like to think
of the main script (aka: __main__) as an apartment building,
and each module that runs under the main script as a single
apartment, and finally, the inhabitants of the apartments as
objects.
Furthermore, we can define the apartment building as being
"global space", and each individual apartment as being
"local space". The first law we encounter is that "global
space" is reserved for all tenants/guest, but "local space"
is by *invitation* only!
You can think of "import" as similar to sending out an
invitation, and requesting that a friend join you inside
your apartment (we'll get back to "import" later).
And of course, with this being the 21st century and all, every
apartment has *local* access to *global* resources like
water and electrical.
In Python, these "global resources" are available
"locally" in every module via the implicit namespace of
"__builtins__". You can think of built-ins as a "house
keeper" robot that lives in every apartment (I call mine
"Rosie"). It was there when you moved in --a "house
warming" gift of sorts-- and it helps you with chores
and makes your life a little easier. Sometimes i abuse
my robot but i always apologize afterwards.
Now that we know how the global and local spaces are defined
(in the context of modules), and what implicit/explicit
"gifts" (are supplied), and "rules" (are demanded) in our
little Python world, we have a good basis to start
understanding why Python's import mechanism is at best a
"helpful failure" that only *naively* attempts to
streamline the management of such an important language
feature as external dependencies!
Up until this point, our apartment example has not mapped
the actual *mechanics* of "import" to a real world example,
but now that we have the correct "perspective", we can tread
into the dark and damp underworld that is "import".
Remember when i said: "import is like sending out an
invitation"? Well, in actuality, import is only
*superficially* similar to "sending out an invitation".
You see, when you send an invitation in real life, the most
important two things you'll need are a *name* and an
*address* --a name so you'll know *who* to send the
invitation to, and an address so you'll know *where* to send
the invitation-- but Python's import mechanism does not work
that way. When you import an external dependency into a
Python module all you need is the name of a module --
addresses are neither required *OR* allowed!
Like almost all modern languages, Python has adopted the
ubiquitous practice of internalizing a mapping of known
directories from which to search for modules (called a
search path), so when we "import somemodule" the following
happens
(Note: I'm not going into too many details for the sake of topic):
1. Python checks if the external resource has already been loaded
if not 1, then
2. Python looks in a few "special places"
if not 2, then
3. Python searches one-by-one the directories in sys.path
RESULT: Python finds the resource or barfs an exception.
I have no problem with step 1, however, step 2 and step 3
can be redundant, excessive, and even unreliable. I can
explain better why i levee such harsh words for "import" by
going back to our apartment building example.
Let's imagine that Python is the "lobby boy" of our apartment
building. And in our little example, one of the duties of
the "lobby boy" is to manage invitations between tenants
and guests. Each time a tenant wants to invite someone into
their apartment, they must pick up the phone, press the
import button (which connects them to the lobby boy via a
voice connection) and they say the name of the person they
want to invite.
But *EVEN IF* they know the address of the recipient, they
are not allowed to say the address to the lobby boy, no,
because *THIS* building is owned by a evil tyrant,
who has declared that any mention of an address when
calling import is punishable by the fatal exception!
So, being a good tenant who does not want to *DIE*, they
simply mention the recipients name, roll their eyes, hang up
the phone, and hope that lobby boy can locate the correct
recipient
It is at this point that the lobby boy (aka: Python) springs
into action. The lobby boy has a gargantuan task ahead of
him, he must locate a tenant based solely on the name with
no idea of which apartment the tenant resides. And,
realizing that he has a terrible memory, and that some of
the building's pranksters have sent him on "wild goose chases"
for recipients that do not exist, his first action is to
check his daily log and ensure he did not *already* deliver
the invitation...
DAMN! Not in the log!
So then the lobby boy checks for a few special places...
DAMN! not in my "special places" either!
Sadly, the lobby knows that now he must check the ENTIRE
building, of which contains thousands of tenants. So he
starts on floor one (sys.path[0]), knocks on all the doors,
then proceeds to floor two (sys.path[1]), knocks on all
those doors..., and so on and so forth until he locates the
recipient or dies of exhaustion -- whichever comes first.
It is this point that i find the import machinery to be
lacking. It's not only the *needless* exhaustive searching
via such an unintelligent algorithm, but also the great
possibility of importing the wrong resource.
"Yeah Rick, but who wants to include a file-path for
importing modules, the whole reason for import was to
abstract away the file-system and file-paths, etc... Are
you proposing we go back and re-adopt the historical
conventions?"
Absolutely not. In most day to day usage Python's import
statement works just fine, it's a cycle burner, but who
cares about a lobby boy anyway right?
I have thousands of modules on my hdrive, and many many
directories holding them, even if i could overlook the
"cycle bonfire" of import's underlying machinery, the list of
intuit-able names for modules are finite, and i'm not about
to start tagging file-names because then i'm back to the
file-system again -- but instead of slashes i'm using
underscores.
NO THANKS!.
What the creators of "import" fail to understand is that a
trade-off has been made, and the Python programmer has been
given the short end of a very long stick, and now we're
being beaten with the very long stick and he nothing to
defend himself with but a tooth-pick!
Creating an "implicit name resolution system" (aka: import)
to abstract away an "explicit name resolution system"
(file-paths) has resulted in more problems that it can solve:
1. Name clashes!
2. Smaller name pool!
3. Machinery is too implicit!
4. Circular imports are inevitable!
5. Much too difficult to use and/or explain!
6. Too many "gotchas"!
Of course, if "import" is not problematic enough for you,
one you use one of the many modules like importlib, imp,
importil, ihooks, or __import__ function, and then become
more confused!! -- Python's external dependency is not only
broken, it's discombobulated and downright confusing!
In closing, there is only one thing you need to know about
Python's import statement: it is deceptively easy to
underestimate it's ability to *EFF UP* your expectations!
[toc] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-11-16 16:16 +1100 |
| Message-ID | <mailman.15866.1416115003.18130.python-list@python.org> |
| In reply to | #80850 |
On Sun, Nov 16, 2014 at 4:01 PM, Rick Johnson <rantingrickjohnson@gmail.com> wrote: > Creating an "implicit name resolution system" (aka: import) > to abstract away an "explicit name resolution system" > (file-paths) has resulted in more problems that it can solve: > > 1. Name clashes! > 2. Smaller name pool! > 3. Machinery is too implicit! > 4. Circular imports are inevitable! > 5. Much too difficult to use and/or explain! > 6. Too many "gotchas"! And the ability to write cross-platform code! ChrisA
[toc] | [prev] | [next] | [standalone]
| From | alex23 <wuwei23@gmail.com> |
|---|---|
| Date | 2014-11-21 10:14 +1000 |
| Message-ID | <m4m04r$aeg$1@dont-email.me> |
| In reply to | #80850 |
On 16/11/2014 3:01 PM, Rick Johnson wrote:
> Python's attempt to solve the "external dependencies problem"
> has yet to produce the results that many people, including
> myself, would like.
I'd say this was an argumentum ad populum, only you didn't cite anything
that shows the "many" you claim you speak for.
> Actually, Python is not alone in this deficiency, no, Python
> is just *ANOTHER* language in a *STRING* of languages over
> the years who has *YET AGAIN* implemented the same old
> crusty design patterns, packaged them in a shiny metallic
> wrapping paper with a big red bow on top, and hoped that no
> one would notice the stench...
Are you sure that's not just you?
> 1. Name clashes!
> 2. Smaller name pool!
Just off the top of my head, we have several solutions for this:
1) Rebinding imports
import foo as foo2
2) Namespace packages
import mypackage.foo
3) Filepath imports (deprecated in 3.4 but under discussion for
reprecation or replacement)
import importlib.machinery
loader = importlib.machinery.SourceFileLoader("module.name",
"/path /to/file.py")
foo = loader.load_module()
foo.MyClass()
4) Virtual environments
In before "but WHY so MANY different WAYS OMG PYTHON you M.F.P.O.S.":
because they offer flexibility.
> 3. Machinery is too implicit!
See: importlib
> 4. Circular imports are inevitable!
They're also clear indication of bad design. That's not something Python
should explicitly set out to support.
> 5. Much too difficult to use and/or explain!
Well sure, if your reaction to things you don't understand is to rant
against them instead of asking questions, then I can see how that would
be true.
Also: citation needed.
> 6. Too many "gotchas"!
Is this the sequel to "Too Many Cooks"? Awesome.
> In closing, there is only one thing you need to know about
> Python's import statement: it is deceptively easy to
> underestimate it's ability to *EFF UP* your expectations!
There's your problem right there: a language conforms to its
specification, not your random expectation.
I'm eager to see how you resolve your concerns in RickPython3000.
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-11-21 11:31 +1100 |
| Message-ID | <mailman.16070.1416529897.18130.python-list@python.org> |
| In reply to | #81149 |
On Fri, Nov 21, 2014 at 11:14 AM, alex23 <wuwei23@gmail.com> wrote: >> 1. Name clashes! >> 2. Smaller name pool! > > Just off the top of my head, we have several solutions for this: > > 1) Rebinding imports > > import foo as foo2 To be fair to Rick, this doesn't actually solve anything. If you have two modules called "foo", you can't import one of them this way. But part of the problem is actually before you even get as far as importing: it's the nature of open source, forking, and the internet. There's a module called "remix", which one Peter Sobot forked and tweaked for his own use, and then distributed a slightly changed version of. (I believe the original intention was for the patches to be incorporated into trunk, but that hasn't happened as yet.) If you want to use his app, you need to use his tweaked remix module; if you want to use someone else's, you might need to use the original from upstream. What do you do about that? They're both called "remix". How do you import one or the other? How do you install one or the other? There is fundamentally no solution to this. As soon as there are two incompatible (even just slightly incompatible) versions of a project in the wild, people need to cope with it. It's the same with avconv vs ffmpeg, it's the same with wodim vs cdrecord, it's the same with all of them - until one of them undergoes a name change, everyone's stuck. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2014-11-20 19:53 -0800 |
| Message-ID | <8661e407-4472-4208-97c2-f666f6502c67@googlegroups.com> |
| In reply to | #81149 |
On Thursday, November 20, 2014 6:15:03 PM UTC-6, alex23 wrote:
> On 16/11/2014 3:01 PM, Rick Johnson wrote:
> [...]
> > Actually, Python is not alone in this deficiency, no, Python
> > is just *ANOTHER* language in a *STRING* of languages over
> > the years who has *YET AGAIN* implemented the same old
> > crusty design patterns, packaged them in a shiny metallic
> > wrapping paper with a big red bow on top, and hoped that no
> > one would notice the stench...
>
> Are you sure that's not just you?
>
> > 1. Name clashes!
> > 2. Smaller name pool!
>
>
> Just off the top of my head, we have several solutions for
> this:
>
> 1) Rebinding imports
>
> import foo as foo2
>
> 2) Namespace packages
>
> import mypackage.foo
I was not talking about name clashes within the script
(which are the problem of the programmer, because he and
only he has *DIRECT* control over the contents of any
scripts he writes!) no, i was talking about two or more
modules who share the same name who then, in effect,
*SHADOW* each other (this is problem for which the
programmer *CANNOT* solve *INTUITIVELY* because he cannot
*EASILY* control the manner in which the underlying import
mechanism finds modules). If you had taken the time to read
my example utilizing a "lobby boy", then you might have
understood what i was talking about.
FOR INSTANCE: Let's say i write a module that presents a
reusable GUI calendar widget, and then i name the module
"calender.py".
Then Later, when i try to import *MY* GUI widget named
"calendar", i will not get *MY* calendar widget, no, i will
get the Python calendar module.
The reason Python finds the library module instead of my
module is because the Python library is higher in search
path than my module.
OKAY, FAIR ENOUGH...
Now, i could *TRY* to be "cleaver" and inject the directory
that holds *MY* "calendar module" as the *FIRST* directory
of sys.path, and this will work, but it's a TOTAL FREAKING
HACK, and unbeknownst to most first-time "import hackers",
the changes to sys.path does not only affect the "contents" of
sys.path within the "current module", but *ALL* modules
further down the "import chain" will suffer the changes!
############################################################
# BE WARNED: #
############################################################
# Contrary to popular belief, sys.path is *NOT* a module, #
# no, it's a global! #
############################################################
This is another confusing fundamental of Python, it seems *MORE*
intuitive that changes to the "import search path" would only
affect the *CURRENT* module's "import search path", but that's
is not the case!
############################################################
# Lesson Of The Day #
############################################################
# Try to be intuitive, and python will *break* you! #
############################################################
And you know why, it's because our "dear leaders" have this
irrational phobia of global variables. But the joke is on
them, because they fail to realize that importing a module
into more than one namespace is creating globals!
YOU CAN PUT LIPSTICK ON A PIG, BUT IT'S STILL A PIG!
This is what happens when your emperor stops wearing
clothes, and more proof that Python's import mechanism sucks
dingo balls!
Now some people will say: "Don't name your modules the same
as a Python library modules and problem solved!"
Sorry, but that's not good enough for me! I believe that the
current import mechanism is only *HALF* of what it should
be. Currently, import uses an "implicit" name resolution via
predefined paths in sys.path, and for 75% of the time, this
"implicit" import mechanism will work just fine -- it's a
slow algorithm, but fast enough for humans not to notice.
HOWEVER,
in the 25% of cases where *NAME SHADOWING* or where the
author knows the location and can specify the location to
save "lobby boy" from knocking on doors until his knuckles
bleed, the author should have an option defining the search
path *LOCALLY* (in a manner that will *NOT* affect the
"import search path" further down the import chain), WITHOUT
needing to import one of the many discombobulated and
confusing import tools that Python has tortured this
community with.
>
> 3) Filepath imports (deprecated in 3.4 but under discussion for
> reprecation or replacement)
>
> import importlib.machinery
>
> loader = importlib.machinery.SourceFileLoader("module.name",
> "/path /to/file.py")
> foo = loader.load_module()
> foo.MyClass()
That's ridiculously noisy. I have an idea, if you *REALLY*
want to introduce boilerplate hell then Python should adopt
"import header files", NOT!
> 4) Virtual environments
>
> In before "but WHY so MANY different WAYS OMG PYTHON you
> M.F.P.O.S.": because they offer flexibility.
>
> > 3. Machinery is too implicit!
>
> See: importlib
>
> > 4. Circular imports are inevitable!
>
> They're also clear indication of bad design. That's not
> something Python should explicitly set out to support.
I think your confusing "circular references" with "circular
imports", and while the two have much in common, and both
should be avoid when possible, there are times when both are
unavoidable (if you want to write sane code!). But this a
discussion better suited to a thread of it's own.
> > 5. Much too difficult to use and/or explain!
>
> Well sure, if your reaction to things you don't understand
> is to rant against them instead of asking questions, then
> I can see how that would be true.
I've asked questions on this list, and you know what kind of
help i get, NONE! I can distinctly remember asking D'Aprano
to help explain the new format method and he flat out
refused, even though he time for "Devils Advocating", he had
no time to help me -- go figure!
The only time i get *real* help from people on this list is
when i ask them privately. I won't mention any names but it
would be nice to feel like a welcomed member who could
participate fully.
You may not believe me, but i have seen some major
improvements in the community since i've been here. Whilst
my complaints to the caretakers of Python.org about the
lackluster and discombobulated nature of the site were
initially taken as offensive, i was pleased to see my
recommendations fully implemented within a year or so. Heck,
i can remember a time when you had to navigate four or five
pages (from the home page) just to see the damn docs, now,
both 2.x and 3.x docs are just a single click away!
THANKS RICK!
About three years ago i started contacting every owner of a
major Python tutorial and pleaded with them to upgrade
their tuts to Python 3.x, again, some took the advice as
offensive, but most of them finally admitted the importance
of sticking to the latest Python version.
THANKS RICK!
Probably my proudest achievement is to see all the
neophytes who have gained the courage to interact with this
community. Before i came along, most of them hide in the
shadows and only watched, unwilling to participate for fear
of ridicule by our rabid attack dogs. But, after witnessing
the hell that i went through, and my public lynching, but
then my triumphant rise as like a "Phoenix From The Ashes",
they realized that the fearless can *NEVER* be defeated, and
that those who carry *ABSOLUTE* resolve to succeed, *WILL*
succeed -- even if they don't get *ANY* credit for their
contributions!
THANKS RICK!
PS: You have to pat *yourself* on the back 'round here.
[toc] | [prev] | [next] | [standalone]
| From | Tim Chase <python.list@tim.thechases.com> |
|---|---|
| Date | 2014-11-21 04:26 -0600 |
| Message-ID | <mailman.16093.1416565776.18130.python-list@python.org> |
| In reply to | #81165 |
On 2014-11-20 19:53, Rick Johnson wrote:
> FOR INSTANCE: Let's say i write a module that presents a
> reusable GUI calendar widget, and then i name the module
> "calender.py".
>
> Then Later, when i try to import *MY* GUI widget named
> "calendar", i will not get *MY* calendar widget, no, i will
> get the Python calendar module.
>
> The reason Python finds the library module instead of my
> module is because the Python library is higher in search
> path than my module.
What messed-up version of Python are you running? Or did you fail to
test your conjecture?
$ cat > calendar.py
print("This is my local calendar.py")
x=1
$ cat > importtest.py
import calendar
print(dir(calendar))
$ python2 importtest.py
This is my local calendar.py
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'x']
$ python3 importtest.py
This is my local calendar.py
['__builtins__', '__cached__', '__doc__', '__file__', '__name__', '__package__', 'x']
It finds my local module, not the system "calendar" module.
-tkc
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2014-11-21 07:52 -0800 |
| Message-ID | <2886a22f-54f6-4d54-b064-911fc0f03ed2@googlegroups.com> |
| In reply to | #81191 |
On Friday, November 21, 2014 4:29:48 AM UTC-6, Tim Chase wrote:
> What messed-up version of Python are you running?
> Or did you fail to test your conjecture?
>
> $ cat > calendar.py
> print("This is my local calendar.py")
> x=1
> $ cat > importtest.py
> import calendar
> print(dir(calendar))
> $ python2 importtest.py
> This is my local calendar.py
> ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'x']
> $ python3 importtest.py
> This is my local calendar.py
> ['__builtins__', '__cached__', '__doc__', '__file__', '__name__', '__package__', 'x']
>
> It finds my local module, not the system "calendar" module.
You failed to provide the needed information!
1. We need to see the values in sys.path. So print them
directly before making the call to import.
2. Where did you store your custom "calendar.py" script?
Remember, "import" is an implicit mechanism, it works by
searching the values of 'sys.path' one-by-one (if the module
was not already loaded!) until the *FIRST* module matching
the name you requested is found. If the folder that holds
*your* custom "calendar.py" script is listed *before* the
folder containing the "python calendar" modules then of
course your module will be correctly loaded.
[toc] | [prev] | [next] | [standalone]
| From | Tim Chase <python.list@tim.thechases.com> |
|---|---|
| Date | 2014-11-21 10:12 -0600 |
| Message-ID | <mailman.16111.1416587630.18130.python-list@python.org> |
| In reply to | #81217 |
On 2014-11-21 07:52, Rick Johnson wrote:
> On Friday, November 21, 2014 4:29:48 AM UTC-6, Tim Chase wrote:
>
> > What messed-up version of Python are you running?
> > Or did you fail to test your conjecture?
> >
> > $ cat > calendar.py
> > print("This is my local calendar.py")
> > x=1
> > $ cat > importtest.py
> > import calendar
> > print(dir(calendar))
> > $ python2 importtest.py
> > This is my local calendar.py
> > ['__builtins__', '__doc__', '__file__', '__name__',
> > '__package__', 'x'] $ python3 importtest.py
> > This is my local calendar.py
> > ['__builtins__', '__cached__', '__doc__', '__file__', '__name__',
> > '__package__', 'x']
> >
> > It finds my local module, not the system "calendar" module.
>
> You failed to provide the needed information!
>
> 1. We need to see the values in sys.path. So print them
> directly before making the call to import.
>
> 2. Where did you store your custom "calendar.py" script?
Had you paid attention, having watched the creation of the two files
and the invocation of stock python, you would know that they were in
the same folder, and there's no modification of sys.path in the
process. So if you're seeing different behaviors due to a modified
sys.path, then you should be aware that *you* modified sys.path and
thus broke things.
The above was tested on Python2 and Python3, both on Linux (Debian
in this case) and Win32 (using "copy con" instead of "cat >") with the
out-of-box install.
The only time I've been stung by name overloading is in the indirect
case of creating a local email.py file and then importing smtplib
only to have things break in unforeseen ways. If smtplib used
relative imports for $STDLIB/email.py I suspect it would ameliorate
that particular issue for me.
-tkc
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2014-11-21 10:42 -0700 |
| Message-ID | <mailman.16115.1416591808.18130.python-list@python.org> |
| In reply to | #81217 |
On Fri, Nov 21, 2014 at 9:12 AM, Tim Chase
<python.list@tim.thechases.com> wrote:
> The only time I've been stung by name overloading is in the indirect
> case of creating a local email.py file and then importing smtplib
> only to have things break in unforeseen ways. If smtplib used
> relative imports for $STDLIB/email.py I suspect it would ameliorate
> that particular issue for me.
Relative imports are based on package namespaces and can only be done
within a package. There's no way to do a relative import from a
separate top-level package, whether they happen to be found in the
same directory or not.
$ mkdir p1
$ touch p1/__init__.py
$ echo 'from ..p2 import m2' > p1/m1.py
$ mkdir p2
$ touch p2/__init__.py
$ touch p2/m2.py
$ python3 -c 'import p1.m1'
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/ikelly/p1/m1.py", line 1, in <module>
from ..p2 import m2
ValueError: attempted relative import beyond top-level package
[toc] | [prev] | [next] | [standalone]
| From | Ned Batchelder <ned@nedbatchelder.com> |
|---|---|
| Date | 2014-11-21 06:32 -0500 |
| Message-ID | <mailman.16097.1416569564.18130.python-list@python.org> |
| In reply to | #81165 |
On 11/20/14 10:53 PM, Rick Johnson wrote: > If you had taken the time to read > my example utilizing a "lobby boy", then you might have > understood what i was talking about. Rick, if you are frustrated that people don't know what you are talking about, you should try writing shorter messages, with less bombast. I don't know if you are aiming for humor with your messages, but to my ears, you are verging on self-parody. I'm surprised that people are taking you seriously. -- Ned Batchelder, http://nedbatchelder.com
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2014-11-21 08:33 -0700 |
| Message-ID | <mailman.16104.1416584077.18130.python-list@python.org> |
| In reply to | #81165 |
On Thu, Nov 20, 2014 at 8:53 PM, Rick Johnson
<rantingrickjohnson@gmail.com> wrote:
> FOR INSTANCE: Let's say i write a module that presents a
> reusable GUI calendar widget, and then i name the module
> "calender.py".
>
> Then Later, when i try to import *MY* GUI widget named
> "calendar", i will not get *MY* calendar widget, no, i will
> get the Python calendar module.
Because like a fool you created a local module with a totally generic
name like "calendar" and dumped it into the top-level namespace. The
Python import system gives you the ability to create packages, so use
them -- create a package to contain all the widgets you create. If
they're only for your own use, then you can just call it ricklib or
anything else you want. Then your import becomes:
import ricklib.calendar # or from ricklib import calendar
Now you can drop as much stuff in there as you like, and none of it
will ever conflict with the standard library (unless a standard
"ricklib" module is added, which is unlikely).
> The reason Python finds the library module instead of my
> module is because the Python library is higher in search
> path than my module.
Your PYTHONPATH is added to the sys.path before the Python library,
not after, so to the extent that there is an issue, it's actually the
other way around. You would get your local calendar module when trying
to import the system calendar module.
> # Contrary to popular belief, sys.path is *NOT* a module, #
> # no, it's a global! #
I really doubt that this is a popular belief.
> This is another confusing fundamental of Python, it seems *MORE*
> intuitive that changes to the "import search path" would only
> affect the *CURRENT* module's "import search path", but that's
> is not the case!
This just seems like it would create a maintenance nightmare. Before
you could import anything, you'd have to figure out what the search
path is for the particular module you're working and whether it
happens to include the particular package you want. You find it
doesn't, so you make a local change to the search path. Later, you
make the same change to other modules that need to import it. Later
still, the package moves to a different location in the file system,
and now you get to go through and update every one of those modules
with the new directory. Lucky you.
And after all that, it would still fail if you happened to want to
import both "calendar" modules into the same module.
> in the 25% of cases where *NAME SHADOWING* or where the
> author knows the location and can specify the location to
> save "lobby boy" from knocking on doors until his knuckles
> bleed, the author should have an option defining the search
> path *LOCALLY* (in a manner that will *NOT* affect the
> "import search path" further down the import chain), WITHOUT
> needing to import one of the many discombobulated and
> confusing import tools that Python has tortured this
> community with.
By doing so, the author would also make the module non-portable. This
is a major problem if they intend to distribute it, but still a
problem even if they don't. Any time the code is moved to a new system
and placed in a new location (or worse: moved to a new operating
system) the code will have to be updated. And you can pretty much
forget about hosting it on a network share.
>> 3) Filepath imports (deprecated in 3.4 but under discussion for
>> reprecation or replacement)
>>
>> import importlib.machinery
>>
>> loader = importlib.machinery.SourceFileLoader("module.name",
>> "/path /to/file.py")
>> foo = loader.load_module()
>> foo.MyClass()
>
> That's ridiculously noisy. I have an idea, if you *REALLY*
> want to introduce boilerplate hell then Python should adopt
> "import header files", NOT!
It's three lines of code to replace one. Two if you exclude the
importlib.machinery import that doesn't need to be repeated. Is this
really any worse than something like:
local_search_path.insert(0, "/path/to/local/module")
import my_local_module
that you are proposing?
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2014-11-21 10:24 -0800 |
| Message-ID | <0bbe1c60-2b29-40f6-96e1-ac777f0c276f@googlegroups.com> |
| In reply to | #81213 |
On Friday, November 21, 2014 9:34:55 AM UTC-6, Ian wrote:
> On Thu, Nov 20, 2014 at 8:53 PM, Rick Johnson
> > FOR INSTANCE: Let's say i write a module that presents a
> > reusable GUI calendar widget, and then i name the module
> > "calender.py".
> >
> > Then Later, when i try to import *MY* GUI widget named
> > "calendar", i will not get *MY* calendar widget, no, i will
> > get the Python calendar module.
>
> Because like a fool you created a local module with a
> totally generic name like "calendar" and dumped it into
> the top-level namespace.
Are you also going to call drivers "fools" because they bought
a "certain brand" of car only to have the airbag explode in
their face? What's next, are you going to blame them for not
wearing a mask? Why am *i* the fool when it's obvious that
the creators of Python were either shortsighted and/or
careless with the designs? The only people who suffer are
those who put their trust in the designer, and not the
designer himself -- something is wrong with this picture!
> The Python import system gives you the ability to create
> packages, so use them -- create a package to contain all
> the widgets you create. If they're only for your own use,
> then you can just call it ricklib or anything else you
> want.
Of course, I did that a long time ago! But like everything
in Python, when your try to be cleaver and create a
workaround for the design flaws of this language (and there
are many!) you end up with shards of jagged metal stuck in
your face!
GvR MUST BE A HUGE FAN OF THE JIGSAW MOVIES!
> Now you can drop as much stuff in there as you like, and
> none of it will ever conflict with the standard library
> (unless a standard "ricklib" module is added, which is
> unlikely).
Yes, and now we've solved one problem by replacing it with
it's inverse -- try importing the *python lib* calendar
module and all you will get is your local "intra-package"
version. Now, the only way to get to the lib module is by
mutilating sys.path, or using an import utility module to
"import by filepath".
THANKS PYTHON!
You are correct though, Python's packaging system CAN BE
used to isolate "intra-package" scripts from clashing with
outside scripts, HOWEVER, there are many caveats that one
must know (which are NOT intuitive!) to use Python's
packaging system without requiring a plastic surgeon on
retainer!
Lets say i take your advice, and i want to use python
packages to protect a set of modules from the "global import
scope".
############################################################
# Explosive Trap 1 #
############################################################
# Any attempt to import a stdlib module, who's name #
# matches one of the modules within the current package, #
# will result in importing the local "package module", #
# forcing you to: (1) inject search paths into sys.path #
# manually (2) import a module to correctly import the #
# dependency #
############################################################
YUCK!
############################################################
# Explosive Trap 2 #
############################################################
# Any code in the __init__ file will be executed NOT ONLY #
# when the package is imported DIRECTLY, but even when the #
# package name is referenced as part of a larger "absolute #
# import path" #
############################################################
OUCH!
Anyone would expect that when *DIRECTLY* importing a
package, if the __init__ file has code, then THAT code
should be executed, HOWEVER, not many would expect that
merely "referencing" the package name (in order to import a
more deeply nested package) would cause ALL the
intermediate __init__ files to execute -- this is madness,
and it prevents using an __init__ file as an "import hub"
(without side-effects)!
"Yeah rick, but why would you want to use an __init__ file
as an "import hub"
Because the alternative is messy. If i have a collection of
modules under a package, sometimes i would like to import
all the "exportable objects" into the __init__ file and use
the package as an "import hub". Imagine a package layout
like this:
+ ricklib
__init__.py
+ subpkg1 (ricklib.subpkg1)
__init__.py
module1.py
module2.py
module3.py
+ subpkg1a (ricklib.subpkg1.subpkg1a)
And the contents of "ricklib.subpkg1.__init__.py" are as
follows:
from module1 import Class1
from module2 import Class2
from module3 import Class3
Now, when i want to import a number of modules from subpkg1
i can do:
from ricklib.subpkg1 import Class1, Class2, ...
Instead of this:
from ricklib.subpkg1.module1 import Class1
from ricklib.subpkg1.module2 import Class2
And everything will work fine, UNTIL, i try to access
"subpkg1a"
from ricklib.subpkg1.subpkg1a import something
By simply MENTIONING the name "subpkga" (within the
"absolute path" of "ricklib.subpkg1.subpkg1a"), Python will
execute the "ricklib.subpkg1.__init__.py" file, thereby
burning cycles importing things that don't even need at the
time! And god forbid you have some "print statements" in
there!
BETTER GO MAKE A SANDWICH WHILE THIS ONE LOADS!
> > This is another confusing fundamental of Python, it seems *MORE*
> > intuitive that changes to the "import search path" would only
> > affect the *CURRENT* module's "import search path", but that's
> > is not the case!
>
> This just seems like it would create a maintenance
> nightmare. Before you could import anything, you'd have to
> figure out what the search path is for the particular
> module you're working and whether it happens to include
> the particular package you want. You find it doesn't, so
> you make a local change to the search path. Later, you
> make the same change to other modules that need to import
> it. Later still, the package moves to a different location
> in the file system, and now you get to go through and
> update every one of those modules with the new directory.
But the current "global import search path" injections are
just the inverse. You make changes to sys.path in one
module, and if you fail to reset the changes before
execution moves to the next module in the "import chain",
then that module's import search path will be affected in
implicit ways that could result in importing the wrong
module.
At least with my proposed "local import search mutations",
the modifications to sys.path would NOT propagate outwards,
because each module would recieve a fresh copy of sys.path
from which to use "as-is" or to modify "as needed", but
those changes would only be relevant within the current
iteration of the import chain.
I think you fail to appreciate my proposal because you are
forgetting the importance of maintaining a "linear
structure" for external dependencies. This "idea" that a
script who is "higher" in the import chain, should be
affecting the "import search paths" defined in the all the
"lower scripts", is doomed to failure, and it will fail
hard.
> > That's ridiculously noisy. I have an idea, if you *REALLY*
> > want to introduce boilerplate hell then Python should adopt
> > "import header files", NOT!
>
> It's three lines of code to replace one. Two if you exclude the
> importlib.machinery import that doesn't need to be repeated. Is this
> really any worse than something like:
>
> local_search_path.insert(0, "/path/to/local/module")
> import my_local_module
>
> that you are proposing?
If the changes were LOCAL, then i would have no problem to
this type of mutation, But they are not.
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-11-22 05:34 +1100 |
| Message-ID | <mailman.16118.1416594902.18130.python-list@python.org> |
| In reply to | #81234 |
On Sat, Nov 22, 2014 at 5:24 AM, Rick Johnson <rantingrickjohnson@gmail.com> wrote: > Of course, I did that a long time ago! But like everything > in Python, when your try to be cleaver... Just so you know, I never try to be one of these. http://img1.wikia.nocookie.net/__cb20110615074214/americanmcgeesalice/images/1/1a/Vorpal_Cleaver.png Along with misuse of "your" when you mean "you", plus a few of the all-too-common misplaced (or omitted) apostrophes, this kind of errant English leaves me wondering if you take as much care over your Python code as you do when writing c.l.py posts, and then blame Python for the results. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Michael Torrie <torriem@gmail.com> |
|---|---|
| Date | 2014-11-21 12:05 -0700 |
| Message-ID | <mailman.16120.1416596746.18130.python-list@python.org> |
| In reply to | #81234 |
On 11/21/2014 11:24 AM, Rick Johnson wrote: > Why am *i* the fool when it's obvious that > the creators of Python were either shortsighted and/or > careless with the designs? The only people who suffer are > those who put their trust in the designer, and not the > designer himself -- something is wrong with this picture! So if you know how to create the perfect language that has a solution to these very difficult problems, please come forward with it. Until such time, it's okay to identify problems with the language as you see them, but to cast aspersion on the developers is out of line. Do you know Guido personally to know that he's short-sighted or careless? I certainly don't, but from what I can see he is neither. Not perfect, but pretty darn smart. Much smarter than I am (despite the fact I can also recognize several of Python's flaws). The same goes for many other core developers. They tend to be smart, articulate, and know how to communicate with people. Everything is about trade-offs and the ones Python makes work very well for most people. Perhaps the problem with the picture is that you are unable to see it clearly. I assure you that Python developers not only create Python, they use it too, for their own purposes. Why would think they are some sort of cabal getting kicks from leading the poor masses of Python programmers at their whim?
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2014-11-21 12:29 -0800 |
| Message-ID | <e24671d9-7e7f-4fb7-b8f0-117d3e5d18fb@googlegroups.com> |
| In reply to | #81237 |
On Friday, November 21, 2014 1:06:18 PM UTC-6, Michael Torrie wrote:
> On 11/21/2014 11:24 AM, Rick Johnson wrote:
> > Why am *i* the fool when it's obvious that
> > the creators of Python were either shortsighted and/or
> > careless with the designs? The only people who suffer are
> > those who put their trust in the designer, and not the
> > designer himself -- something is wrong with this picture!
>
> So if you know how to create the perfect language that has a solution to
> these very difficult problems, please come forward with it. Until such
> time, it's okay to identify problems with the language as you see them,
> but to cast aspersion on the developers is out of line. Do you know
> Guido personally to know that he's short-sighted or careless?
Not personally. But how will we *ever* know if he refuses to
participate in these discussions?
YE SHALL *KNOW* THEM BY THEIR FRUITS!
Although GvR has created one of the best scripting languages
known to man, he has utterly failed to foster a sense of
community between the members, and no matter how great
Python might be, the fact that our community is nothing more
than a "*privileged* white-boys club" is nothing less than
self-destructive.
But even ignoring the atrocious sexual and racial diversity
of this community, outside of Python-dev and Python-ideas,
GvR has refuses to engage with the "mainstream alter boys".
And even WITHIN those "moderated groups", he's very
*selective* about who he will respond to.
THIS COMMUNITY IS *ONLY* SUPERFICIALLY FREE!
I know we just *LOVE* to advertise our "commitment to
diversity"[1] but the truth is, our "commitment" is only a
friendly mask covering the evil truth. The truth is, there
exists a STRONG undercurrent of hostility towards ANY
dissent or outside influence within the "upper echelons" of
this community.
This is NOT a free and open society that prides itself on
building heterogeneous relationships to solve complex
problems, no, this is a *Theocracy*, where one man is raised
above all as though his phallus has been plated with gold!
And although he has not taken hammer and chisel to stone
tablets and carved "malevolent laws" by his own hand, by
virtue of his silence, he HAS implicitly defined a
"religious creed" which forbids all free thought and
expression -- and those who *dare* to dissent will be
excommunicated. That's just what they did over at Python-
ideas not to long ago!
WHY WOULD THEY DO THAT?
GvR has effectively walled himself off from the community with
the exception of a few "advisers" which he allows to enter
his "inner circle". This is NOT how you treat people who are
part of *YOUR* community, that is, IF you want to call
yourself "benevolent"!
SO DROP THE "BENEVOLENT ACT" ALREADY, IT'S PATRONIZING!
If he *REALLY* wants to earn that "benevolent" badge of his,
then he needs to demand that all these forums become free
and open to all opinions and ideas. But more importantly, he
needs to start participating with the community at all
levels, not just hiding behind the coat tails of his attack
dogs and brown-nosers.
START BEARING SOME PALATABLE FRUITS!
[1]: https://www.python.org/community/diversity/
[toc] | [prev] | [next] | [standalone]
| From | Michael Torrie <torriem@gmail.com> |
|---|---|
| Date | 2014-11-21 15:54 -0700 |
| Message-ID | <mailman.16126.1416610475.18130.python-list@python.org> |
| In reply to | #81247 |
On 11/21/2014 01:29 PM, Rick Johnson wrote: > Not personally. But how will we *ever* know if he refuses to > participate in these discussions? Why should he participate in these discussions? Why should you be in charge of said discussions? By the way, Python has more than certainly borne fruit, and the vast majority of it is very good indeed.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2014-11-21 12:23 -0700 |
| Message-ID | <mailman.16121.1416597880.18130.python-list@python.org> |
| In reply to | #81234 |
On Fri, Nov 21, 2014 at 11:24 AM, Rick Johnson <rantingrickjohnson@gmail.com> wrote: > Are you also going to call drivers "fools" because they bought > a "certain brand" of car only to have the airbag explode in > their face? No, but I'll call them fools if they buy a car and the engine catches fire because they never bothered to change the oil. If you don't want to have module name collisions, then don't create modules with names that are likely to collide when Python gives you an excellent tool for avoiding collisions (namespaces). Don't go blaming Python for "bad design" when you couldn't even be bothered to use the tools made available to you. >> Now you can drop as much stuff in there as you like, and >> none of it will ever conflict with the standard library >> (unless a standard "ricklib" module is added, which is >> unlikely). > > Yes, and now we've solved one problem by replacing it with > it's inverse -- try importing the *python lib* calendar > module and all you will get is your local "intra-package" > version. Now, the only way to get to the lib module is by > mutilating sys.path, or using an import utility module to > "import by filepath". Um, no. If your calendar module is named ricklib.calendar, then importing just calendar will import the standard library calendar. The only exception is if you're doing "import calendar" from inside the ricklib package, and you're using Python 2, and you don't have "from __future__ import absolute_import" at the top of your module. The solution to this is easy: just add that __future__ import to the top of your module, and poof, implicit relative imports don't happen. This is also fixed entirely in Python 3. This is the second rather blatant error you've made about Python's import mechanism, which makes me suspect that you don't really know very much about it. > Anyone would expect that when *DIRECTLY* importing a > package, if the __init__ file has code, then THAT code > should be executed, HOWEVER, not many would expect that > merely "referencing" the package name (in order to import a > more deeply nested package) would cause ALL the > intermediate __init__ files to execute -- this is madness, > and it prevents using an __init__ file as an "import hub" > (without side-effects)! The whole point of the __init__.py file, in case you didn't intuit it from the name, is to host any initialization code for the package. Why on earth would you expect to import a module from a package without initializing the package? > Because the alternative is messy. If i have a collection of > modules under a package, sometimes i would like to import > all the "exportable objects" into the __init__ file and use > the package as an "import hub". What is the point of putting things into a hierarchical namespace in the first place if you're just going to turn around and subvert it like this? > But the current "global import search path" injections are > just the inverse. You make changes to sys.path in one > module, and if you fail to reset the changes before > execution moves to the next module in the "import chain", > then that module's import search path will be affected in > implicit ways that could result in importing the wrong > module. No, because the trick you describe doesn't even work. If you edit sys.path in one file in order to import the coconut module: sys.path.insert(0, '/path/to/island') import coconut And then in another module change the sys.path file and try to import a different coconut module: sys.path[0] = '/path/to/other/island') import coconut You think the second import will produce the second coconut module? It won't, because the sys.modules cache will already contain an entry for 'coconut' that points to the first module imported. In order to make this work, you would have to not only modify sys.path but also clear the sys.modules cache. Hopefully by the time you've done that you will have realized that you're abusing the import system by having multiple modules with the same name, and that as a general rule modules shouldn't be manipulating the value of sys.path *at all*. Instead, set your sys.path correctly from the PYTHONPATH environment variable, and if you really must modify sys.path, try to do it only from the main script. >> It's three lines of code to replace one. Two if you exclude the >> importlib.machinery import that doesn't need to be repeated. Is this >> really any worse than something like: >> >> local_search_path.insert(0, "/path/to/local/module") >> import my_local_module >> >> that you are proposing? > > If the changes were LOCAL, then i would have no problem to > this type of mutation, But they are not. The example of a direct loader call that described as "boilerplate hell", to which I was responding, doesn't change anything, locally or globally. All it does is import a module from an arbitrary location.
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2014-11-21 14:25 -0800 |
| Message-ID | <08867178-abb6-4703-9ac5-2a53acb5d227@googlegroups.com> |
| In reply to | #81238 |
On Friday, November 21, 2014 1:24:53 PM UTC-6, Ian wrote:
> On Fri, Nov 21, 2014 at 11:24 AM, Rick Johnson
> > Are you also going to call drivers "fools" because they bought
> > a "certain brand" of car only to have the airbag explode in
> > their face?
>
> No, but I'll call them fools if they buy a car and the engine catches
> fire because they never bothered to change the oil.
As Dennis pointed out that's highly unlikely.
> If you don't want to have module name collisions, then don't create
> modules with names that are likely to collide when Python gives you an
> excellent tool for avoiding collisions (namespaces). Don't go blaming
> Python for "bad design" when you couldn't even be bothered to use the
> tools made available to you.
And by "namespaces" you must be talking about packages here?
Okay, hold that thought...
> >> Now you can drop as much stuff in there as you like, and
> >> none of it will ever conflict with the standard library
> >> (unless a standard "ricklib" module is added, which is
> >> unlikely).
> >
> > Yes, and now we've solved one problem by replacing it with
> > it's inverse -- try importing the *python lib* calendar
> > module and all you will get is your local "intra-package"
> > version. Now, the only way to get to the lib module is by
> > mutilating sys.path, or using an import utility module to
> > "import by filepath".
>
> Um, no. If your calendar module is named ricklib.calendar, then
> importing just calendar will import the standard library calendar.
>
> The only exception is if you're doing "import calendar" from inside
> the ricklib package, and you're using Python 2, and you don't have
> "from __future__ import absolute_import" at the top of your module.
> The solution to this is easy: just add that __future__ import to the
> top of your module, and poof, implicit relative imports don't happen.
> This is also fixed entirely in Python 3.
I wish the irony of needing to know an "implicit rule" to
solve an "implicit problem" could be funny, but it's really
just sad. I can't help but be reminded of the Python zen.
"If it's difficult to explain it's probably a bad idea".
What's more difficult to explain than an implicit rule you
have no knowledge of?
NOW THERE'S SOME IRONY FOR YOU!
> > Anyone would expect that when *DIRECTLY* importing a
> > package, if the __init__ file has code, then THAT code
> > should be executed, HOWEVER, not many would expect that
> > merely "referencing" the package name (in order to import a
> > more deeply nested package) would cause ALL the
> > intermediate __init__ files to execute -- this is madness,
> > and it prevents using an __init__ file as an "import hub"
> > (without side-effects)!
>
> The whole point of the __init__.py file, in case you didn't intuit it
> from the name, is to host any initialization code for the package. Why
> on earth would you expect to import a module from a package without
> initializing the package?
Because you failed to notice that i was NOT importing the
"package" which contained the __init__file, no, i was
importing a *SUB PACKAGE* of the package that contained the
__init__ file.
Why does the code in the main package need to run when i
*explicitly* and *directly* fetched a "nested resource"
within the package? Nothing within the __init__ file is
affecting the code within the subpackage i wanted, and
inversely, the package i wanted does not depend on anything
within the __init__ file. There exists no symbiotic
relationship between these two machinery, yet, by
referencing one of them, the other starts doing unnecessary
things!
There is a workaround, but it's even more of a mess. In
order to maintain a unique "import hub" without the chance
of side effects from __init__ files, i can move all the code
in "ricklib.subpkg1.__init__.py" (the code that does all the
imports) into a normal file named
ricklib.subpkg1._subpkg1.py".
+ ricklib
__init__.py
+ subpkg1 (ricklib.subpkg1)
__init__.py
_subpkg1.py
module1.py
module2.py
module3.py
+ subpkg1a (ricklib.subpkg1.subpkg1a)
Now, since the __init__ file has no global code, i can
import "ricklib.subpkg1.subpkg1s" without side effect -- but
of course, at a cost!
Advanced Python packages are a zero sum game. You cannot
remove the problems, all you can do is move them to new
locations.
so instead of the former (with side effects):
from ricklib.subpkg1.subpkg1a import something
I can do this (without side effect):
from ricklib.subpkg1.subpkg1a._subpkg1a import something
But at the cost of my sanity.
> > Because the alternative is messy. If i have a collection of
> > modules under a package, sometimes i would like to import
> > all the "exportable objects" into the __init__ file and use
> > the package as an "import hub".
>
> What is the point of putting things into a hierarchical namespace in
> the first place if you're just going to turn around and subvert it
> like this?
I'm not "subverting it", i'm merely trying to organize my
*VAST* code libraries utilizing the ONLY tools that have been
made available to me -- and to be quite honest, these tools are
lacking!
If Python expects me to use packages to protect my module
names from clashing, but it gives me no method by which to
import packages without causing side effects, then what is a
boy to do (besides creating workarounds for workarounds)?
> > But the current "global import search path" injections are
> > just the inverse. You make changes to sys.path in one
> > module, and if you fail to reset the changes before
> > execution moves to the next module in the "import chain",
> > then that module's import search path will be affected in
> > implicit ways that could result in importing the wrong
> > module.
>
> No, because the trick you describe doesn't even work. If you edit
> sys.path in one file in order to import the coconut module:
>
> sys.path.insert(0, '/path/to/island')
> import coconut
>
> And then in another module change the sys.path file and try to import
> a different coconut module:
>
> sys.path[0] = '/path/to/other/island')
> import coconut
>
> You think the second import will produce the second coconut module? It
> won't, because the sys.modules cache will already contain an entry for
> 'coconut' that points to the first module imported. In order to make
> this work, you would have to not only modify sys.path but also clear
> the sys.modules cache.
DAMMIT!
We have levels upon levels of esoteric, un-intuit-able, and
implicit procedures happining here. It seems that sys.path
modification is fruitless. Which is good, because i never
liked the idea of it anyway. It's a dirty hack!
Thanks for pointing this out in such a simplistic manner! I
now understand why the import mechinism is so unintuitable!
I'm gushing with exuberance because i feel as though a
"coconut of enlightenment" has been dropped on my head!
I NOW KNOW HOW TO FIX THE PYTHON IMPORT PROBLEM!
I was aware that sys.path was global, but for some reason, i
failed to realize that sys.modules was (i don't know why, it
seems to make perfect sense now!) I was thinking that
sys.modules was specific to each script, and as such, even
though modules were being cached by name, the changes to
sys.path would circumvent the "short circuit behavior" of
"module name resolution"; implemented by a "peek" into
system modules.
Not only is Python going to stop searching the "file system"
for module named "coconut" when it first encounters a file
named coconut, it won't even check sys.path to see if the
programmer has injected a new directory that might contain a
*DIFFERENT* coconut file!
'/path/to/other/island'
And that's good for performance, but bad for intuition!
Now, i'm not suggestion that Python burn up our hard-drives
with listdir() requests, however, there must be some sort of
method we can implement that will solve the "coconut import
problem".
============================================================
THE SOLUTION TO PYTHON'S IMPLICIT IMPORT NIGHTMARE
============================================================
The only way to wrangle this beast in a manner that offer
both the ease of implicit machinery, and the power of explicit
machinery, and do both in a backwards compatible manner, is
to introduce the following:
############################################################
# STEP 1: #
############################################################
# Make sys.path *read-only* #
############################################################
Actually "step 1" is optional. We could leave it as is but
making it read-only would be more consistent. We need to
drive home the point that "injecting sys.path is fruitless"
############################################################
# STEP 2: #
############################################################
# Add a new listing called "sys.path_extra" (or whatever #
# makes sense; that's a dumb name but the best i can think #
# of for now), OR (even better), allow a new variable into #
# each module namespace called "__search_path__" (or #
# something. Again, the name is negotiable), for which #
# will be a list of paths. #
############################################################
############################################################
# STEP 3 #
############################################################
# Make the following changes to the import machinery: #
# Before Python reads a module file, Python will clear the #
# values in "sys.path_extra", OR, query the #
# "__search_paths__" variable, if any paths exists in this #
# list, THEN THESE PATHS MUST BE SEARCHED, AND THEY MUST #
# BE SEARCHED BEFORE ANY PATHS IN "sys.path", AND NO #
# PEEKING IN "sys.modules" IS ALLOWED! #
############################################################
By this method, we can retain the existing implementation of
import, whist offering a more powerful tool to control the
machinery when needed.
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2014-11-21 15:21 -0800 |
| Message-ID | <a2184638-9fd0-4988-8528-cace9786041f@googlegroups.com> |
| In reply to | #81252 |
On Friday, November 21, 2014 4:25:49 PM UTC-6, Rick Johnson wrote:
> ############################################################
> # STEP 3 #
> ############################################################
> # Make the following changes to the import machinery: #
> # Before Python reads a module file, Python will clear the #
> # values in "sys.path_extra", OR, query the #
> # "__search_paths__" variable, if any paths exists in this #
> # list, THEN THESE PATHS MUST BE SEARCHED, AND THEY MUST #
> # BE SEARCHED BEFORE ANY PATHS IN "sys.path", AND NO #
> # PEEKING IN "sys.modules" IS ALLOWED! #
> ############################################################
Actually, to be more specific, not only should the
__search_path__ variable be unique to each file, Python
should query the value of "__search_path__" variable each
time it encounters an import statement.
So, if we wanted to import multiple modules who share the
same name, but who exist in different namespaces, we would
could do so by changing the values of __search_path__ before
calling the import:
#
# import the first coconut module Python can find using
# the default search path, if not raise an error
#
import coconut
#
# import the first coconut module python can find using
# *ONLY* the explicit paths provided, or raise an error.
#
__search_path__ = [
'path/to/a/specific/coconut/tree',
'might/be/here/also'
]
import coconut
At first i was thinking that *IF* any "explicit paths" were
defined via __search_path__, then Python should look in all
those paths first, then if nothing is found look in
sys.modules, then if nothing is found, exhaust sys.modules,
BUT NOW I AM THINKING THAT IS A BAD IDEA!
When __search_path__ *IS* defined, Python should look *ONLY*
in the provided paths, and if not module is found, raise an
"ExplictImportError".
Because if we're going to be explicit then we need to also be
consistent. If the programmer is requesting that Python
search in a predefined directories, then obviously he
doing so to avoid name clashes, so if Python went on and
returned a module OUTSIDE of those predefined paths, Python
would be circumventing (IMPLICITLY AGAIN!) the wishes of the
programmer.
============================================================
Succinct Summary Of My New Proposal:
============================================================
1. Use the historical "implicit import" mechanism for most day
to day imports, and let Python do all the heavy lifting.
2. Use the new "explicit import" mechanism for advanced name
resolutions, but realize that since you are now taking
control of import, so you must do more work, and you must be
"exhaustively explicit" about *where* Python searches.
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-11-22 10:52 +1100 |
| Message-ID | <mailman.16127.1416614372.18130.python-list@python.org> |
| In reply to | #81254 |
On Sat, Nov 22, 2014 at 10:21 AM, Rick Johnson <rantingrickjohnson@gmail.com> wrote: > 1. Use the historical "implicit import" mechanism for most day > to day imports, and let Python do all the heavy lifting. > > 2. Use the new "explicit import" mechanism for advanced name > resolutions, but realize that since you are now taking > control of import, so you must do more work, and you must be > "exhaustively explicit" about *where* Python searches. In other words, what you want is: # today's method, import based on search path import sys # new explicit path method import '/usr/local/lib/python3.5/lib-dynload/math.cpython-35m.so' Can you tell me, please, how this is going to work for *any* system other than the one it was built on? One of the reasons I write Python code is because I expect it to work unchanged on Windows, Linux, Mac OS, BSD, OS/2, uPy, and any other platform I care to throw it onto. If I want to hard-code all the details, I might as well write C code and at least take advantage of ./configure to work out the right paths for me. There are a VERY VERY few cases where you really do want to import a module from a specific file path. For those situations, there are already techniques you can use. Why change the behaviour of import itself? ChrisA
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | comp.lang.python
csiph-web