观察Python环境中的模块

问题

虽然我经常会遇到需要写python脚本的情况,但是大多是在某个环境中,比如Houdini或者UE4等,所写的大多是一小段逻辑。因此,对于那些牵扯到多个python文件的较大型的python项目,我还没有经验。这导致目前我对python里“模块”这个概念有很多不了解之处。

目前,我所最关注的问题是——当我在Houdini或者UE4中运行Python时:

  • 我可以使用哪些模块?
  • 模块都来自于何处?
  • 我怎样补充新的模块?

我想这些问题并不复杂,不过我还是准备结合文档和实践尝试搞明白这些问题。

基础概念

我从《5. 导入系统 — Python 3.9.0 文档》中获得了关于“模块”的一些概念:

  • 模块(module):是 Python 代码的一种组织单位。各模块具有独立的命名空间,可包含任意 Python 对象。模块可通过导入操作被加载。
  • import 语句是发起调用导入机制的最常用方式,但不是唯一的方式
  • Python 只有一种模块对象类型,所有模块都属于该类型,无论模块是用 Python、C 还是别的语言实现。 为了帮助组织模块并提供名称层次结构,Python 还引入了的概念。
  • 包(package):一种可包含子模块或递归地包含子包的模块。从技术上说,包是带有__path__属性的模块
  • import语句结合了两个操作:它先搜索指定名称的模块,然后将搜索结果绑定到当前作用域中的名称。
  • 你可以把看成是文件系统中的目录,并把模块看成是目录中的文件,但请不要对这个类似做过于字面的理解,因为模块不是必须来自于文件系统。

模块的搜索路径

官方文档里有对模块的搜索机制进行描述,但感觉描述比较复杂,我没能完全理解。。。

《Python 模块 | 菜鸟教程》中,有一个对搜索路径的描述:
使用sys.path可以看到所有会搜索的路径,并且其中有一定的优先级:

  1. 当前目录
  2. shell 变量 PYTHONPATH 下的每个目录。
  3. 默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。

我尝试在我所感兴趣的三个环境中使用sys.path看结果是什么:

直接启动下载的官方的python:
在这里插入图片描述

Houdini里:
在这里插入图片描述
UE4里:
在这里插入图片描述

how to

1. 如何确定一个模块是否加载了?

以“xml”这个模块为例,尝试将这个模块print

print(xml)

如何没有加载,则会显示错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'xml' is not defined

如果已加载,则会显示它是个模块,并显示来源:

<module 'xml' from 'C:\\Users\\admin\\AppData\\Local\\Programs\\Python\\Python38\\lib\\xml\\__init__.py'>
2. 如何判断一个模块是否能找到

简单来说,只要import命令失败,就说明找不到。

>>> import testtest
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'testtest'

而为何找不到,就需要看看模块文件是否有在上一部分所说的“搜索路径”中了。

3. 如何知道模块的来源

依旧是print模块的做法。

“xml”模块看来是来自于一个

>>> print(xml)
<module 'xml' from 'C:\\Users\\admin\\AppData\\Local\\Programs\\Python\\Python38\\lib\\xml\\__init__.py'>

“inlinecpp”模块看来是来自于一个.pyc文件:

>>> print(inlinecpp)
<module 'inlinecpp' from 'C:/PROGRA~1/SIDEEF~1/HOUDIN~1.348/houdini/python2.7libs\in
linecpp.pyc'>

“math”模块看来并非来自于文件:

>>> print(math)
<module 'math' (built-in)>
4. 如何添加新的模块

较为直白的是直接将模块文件放到“搜索路径”中。
我的yaksue.py

def yaksuefunc():
	print("hello yaksue")

在之前已经知道了在Houdini中运行python时会搜索到的路径,因此我将yaksue.py放入其中一个目录。

便可以成功在Houdini的Python环境中使用了:
在这里插入图片描述


如果想使用自己指定的路径,也可以修改sys.path的值,它是可写的。

例如,将文件放入“D:/Temp”文件夹中,然后将此路径加入sys.path

sys.path.append("D:/Temp")

即可在使用自己路径中的模块了
在这里插入图片描述
(不用担心会污染“sys.path”,经测试这个修改sys.path的操作是一次性的)

UE4的“unreal”模块

如果在UE4中使用print(unreal),将会得到

<module 'unreal' (built-in)>

此模块并非源于某个文件。
查看UE4的Python插件代码会发现,在“unreal”这个模块是由C++代码负责添加的:

PyUnrealModule = FPyObjectPtr::NewReference(PyImport_AddModule("unreal"));

关于UE4如何向其中添加具体的内容,还有待研究,我想一定和UE4自己的反射机制离不开。

Houdini的“hou”模块

如果在Houdini中使用print(hou),将会得到:

<module 'hou' from 'C:/PROGRA~1/SIDEEF~1/HOUDIN~1.348/houdini/python2.7libs\hou.pyc'>

会发现它是由一个编译好的python文件提供。它是编译好的二进制,没法阅读,但是在同级目录可以找到一个hou.py,我想应该是由它编译的。
但在hou.py中并没有实际函数的实现(或者说实际实现被注释掉了),最后实际是调用了_hou模块的函数。
在这里插入图片描述
在同级目录发现另一个文件_hou.pyd

查资料发现.pyd是非python语言编译好的模块。
关于如何生成.pyd文件还值得研究。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值