Unexpected relative import behavior in Python

Today I have a very surprising relative import behavior (unsatisfactory after almost four hours of hair pulling).

I always got the impression that if you have "class A" inside the module name "module_a.py" in a package called "package" that you could use the same way either:

from package.module_a import ClassA 

or

 from module_a import ClassA 

while you import from the module into a "package". I realized that this is a relative import.

I have never had a problem until today, when I needed to check an instance of an object against class A, and I was surprised to find very unusual behavior.

Consider the following:

package / module _a.py

 class ClassA(object): pass def check_from_module_a(obj): print 'from module_a' print '-------------' print 'class is:', ClassA print 'object is', type(obj) print 'is obj a ClassA:', isinstance(obj, ClassA) 

package / module _b.py

 from package.module_a import ClassA from module_a import check_from_module_a a = ClassA() check_from_module_a(a) print ' ' print 'from module_b' print '-------------' print 'class is:', ClassA print 'object is', type(a) print 'is obj a ClassA:', isinstance(a, ClassA) 

Now when you execute module_b.py you get:

 from module_a ------------- class is: <class 'module_a.ClassA'> object is <class 'package.module_a.ClassA'> is obj a ClassA: False from module_b ------------- class is: <class 'package.module_a.ClassA'> object is <class 'package.module_a.ClassA'> is obj a ClassA: True 

I followed the logic and now understand why this is happening - this was not entirely obvious, since I assumed that the binding for ClassA was the same regardless of absolute or relative imports. This caused a very unpleasant mistake for me, which was very difficult to isolate.

My questions:

  • Is this behavior you would expect?

  • If this is the logical way it should work, then I don’t understand why I would use relative imports if they are incompatible (in the indicated sense) with absolute imports. Is there a good explanation here that I am missing?

  • I always assume that relative imports provided extra simplicity in large refactors when the subpackage structure could move. Is this the main advantage of relative imports?

+7
source share
2 answers

Since implicit relative imports caused problems that were fixed in Python 3. You often don't get the expected behavior with them. See PEP-328 for a discussion. This is especially true if you define a subpackage name with the same name as the base (spare) module.

+4
source

(1) Yes, this is the expected behavior.

(2) Explicit relative imports -

 from .module_a import ClassA 

but not

 from module_a import ClassA 

which can be both relative and absolute, and which can create conflicts between packages and top-level modules.

(3) Yes, this is one of the advantages of relative imports. The main advantage is probably to score less :)

0
source

All Articles