目录
前言
你是否会出现下图中导模块时找不到的情况呢?
ModuleNotFoundError,也就是模块没有找到,不要慌,今天总结导包的所有问题。
模块导入
什么是模块?
容器->数据的封装
函数->语句的封装
类一>方法和属性的封装
模块->模块就是程序,.py文件就是模块
import
import sys
import sys就没有错了,这是为什么呢?这就要提到搜索路径了
搜索路径
print(sys.path)
我们打印出了搜索路径,接下来就看看里面有什么
在其中的一个路径下面有sys,也就是说.py文件所在目录在sys.path中就可以了,我们看到第一个路径就是当前的包路径,在needmodule.py同级目录下写xxx.py就可以了
xxx.py
print("I'm xxx,welcome to import me, i have a hi function")
def hi():
print(f'hi!')
import xxx
xxx.hi()
我们可以导入,并且使用里面的函数
as
如果模块的名字很长,我们可以改个别名
import xxx as x
x.hi()
dir
使用dir函数,可以查看模块里面有什么
有一些默认的,__name__就是模块名字,__doc__是一些说明文字,其他的可以自行探索
忘记列表有哪些函数,就可以使用dir查看一下
>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
__name__
刚才提到了__name__,这是一个很特殊的属性,你开发模块时可能进行一些测试,如果有些代码你想导入时不运行,你可以使用这个
运行xxx.py是,也就是xxx作为主要(main)文件,就会运行另一个分支的代码。
from xxx import ...
如果只想部分导入的话,如何做呢?例如,只想使用某个模块的某个函数,这是就需要使用from了
xxx.py中添加一个函数
def useful():
print("I'm a useful function!!!")
needmodule.py
from xxx import useful
useful()
hi()
导入的可以使用,没导入的会报NameError
包导入
包:包含__init__.py的目录
在上面“搜索路径”一节,展示sys模块的时候,它就在一个包中,可以看到__init__.py文件,同样,xxx.py和needmodule.py在learn_mod_pak包中
命名空间
一般有三种命名空间:
- 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间。
dir在内置命名空间,hi在全局命名空间,所以我们尽量不要和系统内置函数名一样
写一样的函数名,导致运行自己的函数(先在全局命名空间找),可能会出现一些错误。
通过一个例子,说明包的作用:假设你是李华,你的朋友叫小明,你很喜欢♂他,想要和他表白。于是,你告诉了学校广播站的同学,但是广播员广播时直接说了“小明,xxx年级的xxx班的李华喜欢你”。结果你喜欢的小明在二年级三班,另一个暗恋你的小伙子也叫小明,他在三年级四班。三年级四班的小明来找你...这就很尴尬。
上面的年级和班就类似包,模块就类似人,加上前缀就不会出错了,当然,一个包内的模块不能重名。
包中模块的import
needmodule.py
import hi.sayhi
from hello.sayhello import hello
hello()
包结构及结果如下
导入了hi包的sayhi模块,以及hello包的sayhello模块的hello函数。相对于前面导入模块,只需要 包名.模块名 即可
注意,包的__init__.py也是一个模块,它的名字就是对应的包名,当你导入包或包里面的东西时,__init__.py也被导入了
我们在hi包的__init__.py中加入一句话
print('我是hi包的__init__.py文件,我也是模块,我的名字就是hi')
先导入的hi模块,再导入的hi包的sayhi模块
动态导入
动态导入:程序执行时对导入的包进行导入和移除
内置函数 __import__()
__import__
(name, globals=None, locals=None, fromlist=(), level=0)
该函数会导入 name 模块,有可能使用给定的 globals 和 locals 来确定如何在包的上下文中解读名称。 fromlist 给出了应该从由 name 指定的模块导入对象或子模块的名称。 标准实现完全不使用其 locals 参数,而仅使用 globals 参数来确定import语句的包上下文。level 指定是使用绝对还是相对导入。 0
(默认值) 意味着仅执行绝对导入。 level 为正数值表示相对于模块调用__import__()的目录,当 name 变量的形式为 package.module
时,通常将会返回最高层级的包(第一个点号之前的名称),而 不是 以 name 命名的模块。 但是,当给出了非空的 fromlist 参数时,则将返回以 name 命名的模块。
__import__(module)相当于import module
__import__(package.module)相当于from package import name,如果fromlist不传入值,则返回package对应的模块,如果fromlist传入值,则返回package.module对应的模块。
程序刚开始没有导入sayhello模块,无法使用hello函数,所以报异常,导入后可以使用
importlib
这个包有一个import_module
(name, package=None)函数,和__import__()有一些不同
这两个函数之间最重要的不同点在于import_module()
返回指定的包或模块 (例如 pkg.mod
),而__import__()返回最高层级的包或模块 (例如 pkg
)。如果您只想按名称导入模块(可能在包中),请使用 import_module
(name, package=None)
参考
更多python相关内容:【python总结】python学习框架梳理
本人b站账号:lady_killer9
有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。