Python:导入语句符号差异引发的对象标识断言

Python:导入语句符号差异引发的对象标识断言,python,Python,检查对象的标识时,我收到断言错误,因为对象创建代码以一种符号(base.other_stuff.BarCode)导入对象定义模块,而标识检查代码以不同符号(other_stuff.BarCode)导入同一模块。(有关血淋淋的详细信息,请参见下文。) isinstance()调用似乎对对象定义模块的引用有粘性,并希望它以完全相同的符号导入。(我使用的是2.5版。) 我想可以通过更改代码中检查标识的导入符号来解决这个问题,但是我担心我会将同样的问题传播到依赖它的其他代码中。我相信有一些更优雅的解决方

检查对象的标识时,我收到断言错误,因为对象创建代码以一种符号(
base.other_stuff.BarCode
)导入对象定义模块,而标识检查代码以不同符号(
other_stuff.BarCode
)导入同一模块。(有关血淋淋的详细信息,请参见下文。)

isinstance()调用似乎对对象定义模块的引用有粘性,并希望它以完全相同的符号导入。(我使用的是2.5版。)

我想可以通过更改代码中检查标识的导入符号来解决这个问题,但是我担心我会将同样的问题传播到依赖它的其他代码中。我相信有一些更优雅的解决方案,我可能应该首先使用

那么我该如何解决这个问题呢

细节

PythonPath:“/”,“/base/”

档案:

/__init__.py
base/__init__.py
base/other_stuff/__init__.py
base/other_stuff/BarCode.py
base/stuff/__init__.py
camp/__init__.py
base/stuff/FooCode.py的文本:

import other_stuff.BarCode as bc

class Foo:
    def __init__(self, barThing):
        assert isinstance(barThing, bc.Bar)
camp/new_code.py的文本:

import base.stuff.FooCode as fc
import base.other_stuff.BarCode as bc

thisBar = bc.Bar()
assert isinstance(thisBar, bc.Bar)
thisFoo = fc.Foo(barThing=thisBar)
这是失败的。它通过了断言测试,但在初始代码中的断言中崩溃了

但是,当我修改新的_代码以导入BarCode.py时,它会起作用:

import other_stuff.BarCode as bc

。因为base/和base/其他东西都在PythonPath上。

您的代码布局被严重破坏。在
sys.path
中不应该有包目录

在您的情况下,Python将使用两种不同的搜索路径来查找
BarCode.py
,因此将其作为单独的模块加载两次,
bar.other_stuff.BarCode
other_stuff.BarCode
。这意味着此模块中的每个对象都存在两次,这会浪费内存,并且对象标识自然会失败:

>>> from base.other_stuff import BarCode as bc1
>>> from other_stuff import BarCode as bc2
>>> bc1
<module 'base.other_stuff.BarCode' from '.../base/other_stuff/BarCode.pyc'>
>>> bc2
<module 'other_stuff.BarCode' from '.../other_stuff/BarCode.pyc'>
>>> bc1 == b2
False
>>> bc1 is bc2
False
>>来自base.other\u stuff将条形码作为bc1导入
>>>从其他物料导入条形码作为bc2
>>>bc1
>>>bc2
>>>bc1==b2
假的
>>>bc1就是bc2
假的
虽然它们来自同一个源文件,但Python将
bc1
bc2
视为不同的模块


确保您使用的每个模块都可以通过其完整的限定名称进行唯一标识,在您的情况下:
base.other_stuff.BarCode
如果模块是软件包的一部分,切勿将软件包目录添加到
sys.path

您的代码布局严重损坏。在
sys.path
中不应该有包目录

在您的情况下,Python将使用两种不同的搜索路径来查找
BarCode.py
,因此将其作为单独的模块加载两次,
bar.other_stuff.BarCode
other_stuff.BarCode
。这意味着此模块中的每个对象都存在两次,这会浪费内存,并且对象标识自然会失败:

>>> from base.other_stuff import BarCode as bc1
>>> from other_stuff import BarCode as bc2
>>> bc1
<module 'base.other_stuff.BarCode' from '.../base/other_stuff/BarCode.pyc'>
>>> bc2
<module 'other_stuff.BarCode' from '.../other_stuff/BarCode.pyc'>
>>> bc1 == b2
False
>>> bc1 is bc2
False
>>来自base.other\u stuff将条形码作为bc1导入
>>>从其他物料导入条形码作为bc2
>>>bc1
>>>bc2
>>>bc1==b2
假的
>>>bc1就是bc2
假的
虽然它们来自同一个源文件,但Python将
bc1
bc2
视为不同的模块


确保您使用的每个模块都可以通过其完整的限定名称进行唯一标识,在您的情况下:
base.other_stuff.BarCode
如果模块是包的一部分,请不要将包目录添加到
sys.path

您的
sys.path
中似乎有
/
/base
,这总是不好的。当您从base/stuff/FooCode.py以bc的形式导入其他内容时,它会将
其他内容作为根包导入,但不会将
base的子包导入。因此,在执行
import base.other_stuff.BarCode as bc
之后,您将得到
BarCode
模块导入两次:使用
other_stuff.BarCode
base.other_stuff.BarCode

最好的解决办法是:

  • sys.path
    (或$PYTHONPATH)中删除
    /base
  • 在base/stuff/FooCode.py中使用相对导入:
    from..other_stuff将条形码导入为bc

  • 看起来您的
    系统路径中有
    /
    /base
    ,这总是不好的。当您从base/stuff/FooCode.py以bc的形式导入其他内容时,它会将
    其他内容作为根包导入,但不会将
    base的子包导入。因此,在执行
    import base.other_stuff.BarCode as bc
    之后,您将得到
    BarCode
    模块导入两次:使用
    other_stuff.BarCode
    base.other_stuff.BarCode

    最好的解决办法是:

  • sys.path
    (或$PYTHONPATH)中删除
    /base
  • 在base/stuff/FooCode.py中使用相对导入:
    from..other_stuff将条形码导入为bc
  • “表示法”是最简单的问题——定义为在语义上引用同一模块的不同表示法保证生成相同的对象。例如:

    >>> import sys as foobar
    >>> import sys as zapzip
    >>> foobar is zapzip
    True
    
    问题是,确实有可能多次导入相同的文件,但导入机制无法完全了解您在做什么,因此最终会得到不同的模块对象。例如,像您正在使用的重叠路径很容易产生这种情况

    一种方法(如果您坚持编写代码和/或布局文件系统,可能会造成混淆/误导;-)是将
    \uuuuuu内置\uuuuuu.\uuuuuuuu导入
    设置到您自己的函数中,在调用以前的/正常版本后,使用os.path.normpath检查新导入模块的
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(或者通过标准库模块
    os
    中的功能检测单个文件同义词的更强大的方法,例如符号链接和硬链接)

    用这个钩子,你可以确保