发现问题
在pycharm上优化毕业设计demo的时候,发现一句话:
from tensorflow.nn import conv2d
其中nn和conv2d均被警告,查其定义均显示’“Cannot find declaration to go to”。但是相关代码确实能够正常运行,且没有报错。
初探问题
为了找到原因,尝试人工寻找conv2d方法。
先找到tensorflow模块中的__init__.py,其中有这样一行:
from tensorflow._api.v1 import nn
在此进一步寻找到nn模块的__init__.py文件,并发现了这样一行:
from tensorflow.python.ops.gen_nn_ops import conv2d
在gen_nn_ops.py下确实找到了conv2d这一方法。
到此,说明了两件事:
- 确实存在
conv2d这一方法,并且程序运行时执行的应该就是该方法。(验证过程省略) - 既然能够成功找到这一方法,为什么pycharm会报错,不能直接定位该方法?
复现问题
根据以上的分析,现提出一个猜想:在上述情况下,pycharm找不到相关方法或模块,会发出警告,但是程序在运行时会根据from tensorflow._api.v1 import nn和from tensorflow.python.ops.gen_nn_ops import conv2d找到相关方法或模块。为了验证这一猜想,开始复现问题。
首先分析一下tensorflow模块的结构,如下:
- tensorflow
- init.py
- _api
- init.py
- v1
- init.py
- nn
- init.py
现复刻以上结构,加入到自己的项目,如下:
- test
- bp
- init.py
- _api
- init.py
- v1
- init.py
- nn
- init.py
- a.py
- bp
其中
bp的初始化模块仿照tensorflow:from bp._api.v1 import nn_api和v1的初始化模块与代码保持一致,为空。- 在
nn的初始化模块中补上一个函数func_b以替代conv2d:def func_b(text): print(text) a.py负责测试,写上:from bp.nn import func_b func_b('This is a.')
到此,内容和结构复现完成,开始测试。
测试结果如下:
-
pycharm在
nn和func_b上均出现警告信息,符合猜想。 -
运行
a.py,系统报错,不符合猜想:No module named 'bp.nn'
据此可知,系统并不能根据from tensorflow._api.v1 import nn和from tensorflow.python.ops.gen_nn_ops import conv2d找到相关模块和方法,猜想是错的。
由此,目前需要解决两个问题:
- 既然
from tensorflow._api.v1 import nn不能让程序找到nn模块,那么它的意义在哪? - 程序在运行时是如何找到
nn这一模块,进而寻找到conv2d这一方法的?
在尝试修改a.py后,第一个问题得到了解答:
from bp import nn
nn.func_b('This is a.')
运行上述代码,不仅pycharm没有出现警告,程序也正常运行。若注释from bp._api.v1 import nn,上述代码将会报错。
这说明:在bp的初始化模块中加入from bp._api.v1 import nn,可以让其他程序能够直接从bp中导入nn模块。如果不加,那么其他程序需要从bp._api.v1中导入nn模块。
再次复现
如果将程序寻找nn模块和conv2d方法所需要的信息串比作一条“路”,那么我们不难知道:
- 复现失败,说明这条“路”不在当前的程序中;
- 复现成功,说明这条“路”在当前的程序中。
由于第一次复现失败,说明这条“路”不在第一次复现的程序中。为了找到这条“路”,目前所需要做的是:保证能够成功复现问题,使复现程序包含这条“路”。然后进一步简化信息,找出哪一部分代码充当了这条“路”。处理步骤如下:
- 首先保证复现成功:将原
tensorflow整包拷贝到test文件夹下,代替原来的bp包。为了防止冲突,将原tensorflow包名改为_tensorflow。 - 在拷贝之后,pycharm出现警告,运行
a.py,没有报错。复现成功。 - 将注意力集中在
tensorflow的初始化模块上。将它的其它内容全部删除,仅留下:
运行from tensorflow._api.v1 import nna.py,系统报错:No module named 'tensorflow.nn'。说明“路”在删除的信息中。 - 还原
tensorflow的初始化模块,依次注释每一个模块,找到了根源:
其中# Make sure directory containing top level submodules is in # the __path__ so that "from tensorflow.foo import bar" works. _tf_api_dir = _os.path.dirname(_os.path.dirname(app.__file__)) # pylint: disable=undefined-variable if _tf_api_dir not in __path__: __path__.append(_tf_api_dir)_os.path.dirname(_os.path.dirname(app.__file__))就是xxx/tensorflow/api/v1,即nn所在目录。
因此总结如下:
- 一般而言,在
from xx.xxx import xxxx中,xxx需要在xx模块的__path__中。 - 一般情况下,
__path__为当前所在目录,可以往里添加新的目录。
重新复现
为了验证上述结论,在第一次复现的基础上,修改bp的初始化模块:
from bp._api.v1 import nn
print(__path__)
__path__.append(_os.path.dirname(_os.path.dirname(nn.__file__)))
print(__path__)
在a.py中,pycharm对nn和func_b提出警告,程序运行成功。打印结果如下:
['C:\\Users\\zhazha\\Desktop\\test\\bp']
['C:\\Users\\zhazha\\Desktop\\test\\bp', 'C:\\Users\\zhazha\\Desktop\\test\\bp\\_api\\v1']
This is a.
本文探讨了在PyCharm环境下使用TensorFlow时遇到的警告问题,即使代码能正常运行。通过复现问题,分析了Python的模块导入机制,解释了PyCharm警告与实际运行不冲突的原因。
791

被折叠的 条评论
为什么被折叠?



