开发者

Unexpected relative import behavior in Python

开发者 https://www.devze.com 2023-03-02 11:37 出处:网络
I ran into a very surprising relative import behavior today (unfortantely after nearly 4 hours of pulling my hair out).

I ran into a very surprising relative import behavior today (unfortantely after nearly 4 hours of pulling my hair out).

I have always been under the impression that if you have "Class A" inside of a module name "module_a.py" within a package named "package" that you could equivalently use either:

from package.module_a import ClassA

or

from module_a import ClassA

as long as you were importing from a module within "package". I understood this to be a relative import.

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

Consider the following:

package/module_a.py

class ClassA(object):
    pass

def check_from_module_a(o开发者_StackOverflow中文版bj):
    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 executing 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 have followed the logic and now see why this occurs - it was not real obvious as I assumed that the binding for ClassA was the same regardless of an absolute or relative import. This caused a very nasty bug for me that was very hard to isolate.

My questions:

  1. Is this the behavior that would be expected?

  2. If this is the logical way that it should work - it is then not clear to me why I would use relative imports if they are not compatible (in the above sense) with absolute imports. Is there a good explanation here that I am missing?

  3. I always assume that relative imports provided additional ease in large refactors when sub package structure might be moved around. Is this the main benefit of a relative import?


Since implicit relative imports have caused problems they have been removed in Python 3. You often don't get 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 a base (stock) module.


(1) Yes, this is expected behaviour.

(2) An explicit relative import is

from .module_a import ClassA

, and not

from module_a import ClassA

which can be relative as well as absolute, and which can give conflicts between top-level packages and modules.

(3) Yes, that is one of the advantages of relative import. The main benefit is probably having to type less :)

0

精彩评论

暂无评论...
验证码 换一张
取 消