[Python-Dev] Package ambiguities

Ka-Ping Yee Ka-Ping Yee <pingster@ilm.com>
Wed, 7 Jun 2000 15:39:28 -0700 (PDT)


On Wed, 7 Jun 2000, Gordon McMillan wrote:
> I disagree with the moral.
> 
> If test.py uses "import A.parent" and changes references 
> accordingly, it works.

Correct.

Well, maybe there are two things going on here.

I agree that import * isn't usually a very good idea.

However, notice that the problem occurs even if the first line
of test.py is "import parent" (no star).  When you talk about
changing references accordingly, the real issue is referencing
"A.parent" rather than "parent".

In fact, if you change the first line to "from A.parent import *"
(not that i am advocating this!) -- it works.  In short:

    from parent import *    ...  Parent             doesn't work
    import parent           ...  parent.Parent      doesn't work
    
    from A.parent import *  ...  Parent             works
    import A.parent         ...  A.parent.Parent    works

The first two cases -- attempting to import "parent" -- are
only made possible by the fact that we're executing test.py
from within the A/ directory, and hence the confusion.


This problem is an "advanced" version of a simpler issue
which a friend of mine discovered and complained about
recently to me: the __main__ vs. module-name conflict.
Allow me to paraphrase his example.

Exhibit A:

    ---- spam.py ----
    import eggs

    def go():
        print "was", eggs.a
        eggs.a = 3
        print "now", eggs.a

    ---- eggs.py ----
    import spam

    a = 1

    def go():
        spam.go()
        print "finally", a

    if __name__ == "__main__": go()

    --- watch what happens ----
    % python eggs.py
    was 1
    now 3
    finally 1

    % python
    >>> import eggs
    >>> eggs.go()
    was 1
    now 3
    finally 3


Exhibit B:

    ---- one.py ----
    import two
    def go(): pass

    ---- two.py ----
    import one
    one.go()

    ---- watch what happens ----
    % python one.py

    % python two.py
    Traceback (innermost last):
      File "two.py", line 1, in ?
        import one
      File "./one.py", line 1, in ?
        import two
      File "./two.py", line 2, in ?
        one.go()
    AttributeError: go
    Exit 1

    % python
    >>> import one
    Traceback (innermost last):
      File "<stdin>", line 1, in ?
      File "./one.py", line 1, in ?
        import two
      File "./two.py", line 2, in ?
        one.go()
    AttributeError: go
    >>> import two
    >>> 


The facts that eggs.a appears to behave differently in Exhibit A,
and that one.py can be run but two.py cannot, yet "two" can be
imported and "one" cannot, in Exhibit B, both result from the
duplication namespaces in __main__ and in a module.

Normally, this only affects the main file that you are running,
the one with the __main__ namespace.  However, attempting to run
scripts in package directories allows this problem to propagate
further into the duplication of other modules:

    __main__ imports parent which imports child
    A.test imports A.parent which imports A.child

...and that can cause duplicate classes all over the place,
which is what happened to Andy.


My friend was quite irked by the existence of __main__, citing
it as the culprit for this duplication.  But naturally Python
can't always know the name of the script being run -- in the
case of a file ending in .py, perhaps, it's easy, but the script
might come from a pipe, for example.  So eliminating __main__
doesn't seem like a feasible response.

Depending how "real" you consider this problem, leaving things
as they are and instructing people in the discipline of keeping
modules and scripts separated may be the best response.

I bet this crops up all the time in those "testing" sections
of modules that use the 'if __name__ == "__main__"' convention,
though...


-- ?!ng

"Computers are useless.  They can only give you answers."
    -- Pablo Picasso