[Python-bugs-list] [ python-Bugs-493628 ] import not pythonic in 2.1.1

noreply@sourceforge.net noreply@sourceforge.net
Tue, 18 Dec 2001 09:04:29 -0800


Bugs item #493628, was opened at 2001-12-15 03:37
You can respond by visiting: 
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=493628&group_id=5470

Category: Python Interpreter Core
Group: Not a Bug
Status: Closed
>Resolution: Remind
Priority: 5
Submitted By: Chris Withers (fresh)
Assigned to: Nobody/Anonymous (nobody)
Summary: import not pythonic in 2.1.1

Initial Comment:
Take a package 'aPackage', which contains a sub-package 'aSubPackage' that in turn contains a 
module 'aModule' that defines a class 'aClass'.

If I do:

import aPackage.aSubPackage
print aPackage.aSubPackage.aModule

I get:

Traceback (most recent call last):
  File "x.py", line xx, in ?
    print aPackage.aSubPackage.aModule
AttributeError: 'aPackage.aSubPackage' module has no attribute 'aModule'

A yet, if I do:

import aPackage.aSubPackage.aModule
print aPackage.aSubPackage.aModule

I get:
<module 'aPackage.aSubPackage.aModule' from 'some_path'>

...as expected, which is very confusing and doesn't feel 'right' :-S




----------------------------------------------------------------------

>Comment By: Chris Withers (fresh)
Date: 2001-12-18 09:04

Message:
Logged In: YES 
user_id=24723

Indeed. Damn SF drop downs and M$ mouse wheels ;-)

----------------------------------------------------------------------

Comment By: Guido van Rossum (gvanrossum)
Date: 2001-12-18 08:59

Message:
Logged In: YES 
user_id=6380

> Comment By: Chris Withers (fresh)
> 
> I've added this feature request to PEP 42.

No you haven't. :-)


----------------------------------------------------------------------

Comment By: Chris Withers (fresh)
Date: 2001-12-18 08:56

Message:
Logged In: YES 
user_id=24723

I've added this feature request to PEP 42.

----------------------------------------------------------------------

Comment By: Chris Withers (fresh)
Date: 2001-12-18 08:56

Message:
Logged In: YES 
user_id=24723

Thanks for the pointers :-)

I would use pickling, but I'm not sure MySQL database connections would take too well to being pickled :-S
(an attribute of the object to be stored is a mySQLdb database connection)

And yeah, reading through this, it's __import__ not import that's confusing. Why is the m = 
sys.modules[module] needed?

Also, when using syntax like import item.subitem.subsubitem, why that last subitem be a class or function?

cheers,

Chris

----------------------------------------------------------------------

Comment By: Guido van Rossum (gvanrossum)
Date: 2001-12-17 06:35

Message:
Logged In: YES 
user_id=6380

Yeah, Zope has many __init__.py files that I consider
immoral. We're fixing this in Zope3. :-)

What you're doing is similar to what pickle does, by the
way. Can't you store pickles?

Several tips:

- instead of getting str(object.__class__) and then parsing
the result, use
   module, klass = k.__class__.__name__,
k.__class__.__module__

- __import__ *does* support packages, if you do it right:
   __import__(module)
   m = sys.modules[module]

- Instead of exec("k ="...), use
   k = getattr(m, klass)

So please don't blame this in import. :-)

----------------------------------------------------------------------

Comment By: Chris Withers (fresh)
Date: 2001-12-17 03:41

Message:
Logged In: YES 
user_id=24723

> OK, the motivation is that importing a package shouldn't
> recursively import all its submodules -- else importing a
> top-level package could do an immense amount of work.

Fair enough, I guess I don't use any packages where this is 
true, apart from Zope, but "import Zope" certainly takes 
some time anyway ;-)

To answer Tim's question, I need to store the minimum 
amount of information necessary to re-constitute an object 
in a MySQL database. The attributes that need to persist 
are easy, just shove 'em in columns.

However, to actually create the object, I need to 
instantiate a class. With the above restrictions, I've 
ended doing:

            k = str(object.__class__)
            i = k.rindex('.')
            module = k[:i]
            klass  = k[i+1:]

..and storing module and class in columns.

Then, to reconstitute the object, I do:

                exec("import "+module)
                exec("k = "+module+'.'+klass)
                object=k()

the second exec is needed because import fails if the last 
name isn't a module or package.

the first exec is needed because:

1. __import__ doesn't handle . seperated names to import

2. If I use __import__ to import the top level package, 
none of the modules/packages below it are imported so 
getattr(module,klass) fails with an AttributeError

Thinking about it, if (1) worked, then I probably wouldn't 
have a problem...

That said, if there's a simpler way to do all this, I'd 
happily use that ;-)

cheers,

Chris




----------------------------------------------------------------------

Comment By: Chris Withers (fresh)
Date: 2001-12-16 12:45

Message:
Logged In: YES 
user_id=24723

> I'm not sure what to do with your whine about being one of
> the many who find it counter-intuitive. Can you explain how
> you would like it to behave?

Sorry, that was me being unclear... I meant I am probably one of the few who finds it unintuitive ;-)

----------------------------------------------------------------------

Comment By: Guido van Rossum (gvanrossum)
Date: 2001-12-16 11:38

Message:
Logged In: YES 
user_id=6380

OK, the motivation is that importing a package shouldn't
recursively import all its submodules -- else importing a
top-level package could do an immense amount of work.

The motivation for the thing you quote is less clear -- it
follows from the requirement that in "import <something>",
"<something>" refers to a module (where a package is a
special case of a module).

I'm not sure what to do with your whine about being one of
the many who find it counter-intuitive. Can you explain how
you would like it to behave?

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2001-12-16 10:03

Message:
Logged In: YES 
user_id=31435

Chris, why do you think you need to use an exec stmt?  You 
haven't shown an example of why it's needed, and it sure 
isn't obvious.

Modules must be imported, and importing a module M requires 
an import stmt whose last path component is M -- that's 
about all there is to it.

----------------------------------------------------------------------

Comment By: Chris Withers (fresh)
Date: 2001-12-16 04:58

Message:
Logged In: YES 
user_id=24723

Well, I read it, and it explains the history, but it doesn't give reasons, particularly for:

> Contrarily, when using syntax like import item.subitem.subsubitem, each item except for the last must be 
a package; the last item can be a module
> or a package but can't be a class or function or variable defined in the previous item. 

...or for the above stuff.

But, while I find it counter-intuitive (and means I have to use unpleasant exec statements), I am but one 
voice among many who probably feel differently so I'll just accept it as one of the things i don't like about 
python...

thanks for your time :-)

Chris


----------------------------------------------------------------------

Comment By: Guido van Rossum (gvanrossum)
Date: 2001-12-15 09:46

Message:
Logged In: YES 
user_id=6380

http://www.python.org/doc/essays/packages.html

----------------------------------------------------------------------

Comment By: Chris Withers (fresh)
Date: 2001-12-15 09:15

Message:
Logged In: YES 
user_id=24723

Okay, if it's intended, that means there's a good reason for it...

...where can I look for enlightenment as to what that is?

cheers,

Chris

----------------------------------------------------------------------

Comment By: Guido van Rossum (gvanrossum)
Date: 2001-12-15 07:39

Message:
Logged In: YES 
user_id=6380

Better adjust your intuition. :-)

This is as intended. Attributes of packages that are
*modules* are only loaded when the corresponding module is
explicitly imported (by you, or by some other code, e.g. the
package's __init__.py).

----------------------------------------------------------------------

You can respond by visiting: 
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=493628&group_id=5470