Nathan Rice wrote: > I just ran into this yesterday, and I am curious if there is a > rational behind it... > > I have a class that uses a dictionary to dispatch from other classes > (k) to functions for those classes (v). I recently ran into a bug > where the dictionary would report that a class which was clearly in > the dictionary's keys was giving a KeyError. id() produced two > distinct values, which I found to be curious, and > issubclass/isinstance tests also failed. When I inspected the two > classes, I found that the only difference between the two was the > __module__ variable, which in one case had a name relative to the > current module (foo), and in another case had the fully qualified name > (bar.foo). When I went ahead and changed the import statement for the > module to import bar.foo rather than import foo, everything worked as > expected. My first thought was that I had another foo module in an > old version of the bar package somewhere on my pythonpath; After a > thorough search this proved not to be the case. > > Has anyone else run into this? Is this intended behavior? If so, why?
Not exactly intended, but a logical side effect of how Python identifies its modules. The problem is that you have an entry in sys.path that reaches into the bar package. When you import foo Python does not check whether [path1]/bar/foo.py points to the same file as [path2]/foo.py, it just verifies that the name "foo" is not in the sys.modules cache before it physically imports the file. Therefore you get two distinct imports of "foo.py" stored in the cache as "foo" and "bar.foo". As Python's classes are not declarations, but objects themselves you get distinct classes just as with the following >>> classes = set() >>> for i in range(3): ... class A: pass ... >>> classes = set() >>> for i in range(3): ... class A: pass ... classes.add(A) ... >>> classes set([<class __main__.A at 0x7f4f5a044b30>, <class __main__.A at 0x7f4f5a044ad0>, <class __main__.A at 0x7f4f5a044a70>]) To avoid the problem just remove the offending [path2] from sys.path and always import the foo subpackage with import bar.foo # everywhere or from . import foo # inside bar PS: You may run into similar problems when you import the main module of a program. It will end up in the module cache as filename_sans_extension and "__main__". -- http://mail.python.org/mailman/listinfo/python-list