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
中的功能检测单个文件同义词的更强大的方法,例如符号链接和硬链接)
用这个钩子,你可以确保