目录
python 语言的最大特色之一就是基于模块化开发,不仅在 python 标准库中包含了大量的模块,而且还有丰富的第三方模块,用户也可以自定义模块。借助这些种类齐全、应用丰富、功能强壮的模块库,python 具有强大的应用开发能力,也提升了开发者的开发效率。
【学习重点】
- 了解模块
- 能够正确创建模块和导入模块
- 了解 Python 包结构
- 掌握如何导入和使用标准模块
- 了解第三方模块的下载、安装和基本使用。
一、模块化
1.1 认识模块
在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。为了编写可维护的代码,需要把很多个类和函数进行分组,分门别类地放到不同的文件里,这样每个文件包含的代码就相对减少了,维护起来也变得轻松,很多编程语言都采用这种方式来组织代码。在 Python 中,一个以 .py
为扩展名的文件就叫作一个模块(Module),每一个模块在 Python 里都是一个独立的文件。
模块可以包含直接运行的代码、类定义、函数定义等任何 Python 源代码。模块可以被其他模块、脚本,甚至是交互式解析器导入(import)使用,也可以被其他程序引用。导入的源代码会直接被解析运行。使用模块的好处:
- 提高代码的可维护性
- 提高代码的可重用性
- 避免命名冲突,避免代码污染
Python 模块可以分为3种类型:
- 内置标准模块,又称标准库,如 sys、time、json 模块等。备注: Python 模块一般都位于安装目录下 Lib 文件夹中,执行
help("modules")
命令,可以查看已经安装的所有模块列表。help() 函数用法参考文章:Python 常用内置函数详解(十):help()函数——查看对象的帮助信息 👉 查看文章 - 第三方开源模块:这类模块可以通过
"pip install 模块名"
进行在线安装。如果 pip 安装失败,也可以直接访问模块所在官网下载安装包,在本地离线安装。 - 自定义模块:由开发者自己开发的模块,方便在其他程序或脚本中使用。注意: 自定义模块的名称不能与系统模块重名,否则有覆盖掉内置模块的风险。例如,自定义一个 sys.py 模块后,就不能再使用系统的 sys 模块。
1.2 使用模块
import 语句使用 .
点号作为分隔符分隔包、模块、成员
1.2.1 使用import语句导入模块
import 语句的基本语法格式如下:
import modulename [as alias]
# 1.import语句:
# 1.1 找到指定的模块,加载和初始化它,生成模块对象。找不到,抛出异常
# 1.2 在import所在的作用域的局部命名空间中,增加名称和上一步创建的对象关联
# 2.modulename为要导入模块的名称
# 3.[as alias]为给模块起的别名,通过该别名也可以使用模块
单独运行下面例子,体会区别:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 11:34
# @Author : AmoXiang
# @File : 1.import_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
# ====================第1次运行的代码====================
# import functools # 导入模块
#
# print(dir()) # [..., 'functools']
# print(functools, type(functools))
# # <module 'functools' from 'D:\\devTools\\Python\\Python312\\Lib\\functools.py'> <class 'module'>
# print(functools.wraps) # <function wraps at 0x0000022A0CCEFE20>
# ====================第2次运行的代码====================
# import os.path # 导入os.path,os加入当前名词空间
#
# # [...., 'os']
# print(dir())
# print(os, type(os)) # <module 'os' (frozen)> <class 'module'>
# # ====================第3次运行的代码====================
# # [...., 'osp']
# import os.path as osp # 导入os.path并赋给osp
#
# print(dir())
# print(osp) # <module 'ntpath' (frozen)>
# ====================第4次运行的代码====================
def test_import():
import os.path # 局部
print(dir()) # ['os']
test_import()
# dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__',
# '__annotations__', '__builtins__', '__file__', '__cached__', 'test_import'])
print(globals().keys())
总结:
-
在调用模块中的变量、函数或者类时,需要在变量名、函数名或者类名前添加
"模块名"
作为前缀。例如,上面代码中的 functools.wraps,表示调用 functools 模块中的 wraps() 函数 -
如果模块名比较长不容易记住,可以在导入模块时,使用 as 关键字为其设置一个别名,然后就可以通过这个别名来调用模块中的变量、函数和类等
-
导入顶级模块,其名称会加入到本地名词空间中,并绑定到其模块对象
-
导入非顶级模块,只将其顶级模块名称加入到本地名词空间中。导入的模块必须使用完全限定名称来访问
-
如果使用了 as,as 后的名称直接绑定到导入的模块对象,并将该名称加入到本地名词空间中
-
import 之后只能是模块类型(当然包括包),意思是单独的函数、类、变量不能直接 import
-
使用 import 语句还可以一次导入多个模块,在导入多个模块时,模块名之间使用逗号
,
进行分隔。示例代码:import random, functools, threading
1.2.2 使用from…import语句导入模块
import 语句在执行时,需在具体的变量、函数和类名前加上 "模块名"
前缀。如果不想在每次导入模块时都创建一个新的命名空间,而是将具体的定义导入到当前的命名空间中,这时可以使用 from…import 语句。使用 from…import 语句导入模块后,不需要再添加前缀,直接通过具体的变量、函数和类名等访问即可。from…import 语句的语法格式如下:
from modelname import member1 [as m1], member2 [as m2]
# 说明:
# 1.modelname: 模块名称,区分字母大小写,需要和定义模块时设置的模块名称的大小写保持一致。
# 2.member:
# 2.1 用于指定要导入的变量、函数或者类等。可以同时导入多个定义,各个定义之间使用逗号","分隔。
# 2.2 如果想导入全部定义,也可以使用通配符星号"*"代替。
# 2.3 同样可以使用as给导入的成员起别名
示例:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 19:09
# @Author : AmoXiang
# @File : 2.from_import_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
from pathlib import Path, PosixPath # 在当前名词空间导入该模块指定的成员
print(dir()) # ['Path', 'PosixPath', ....]
from pathlib import * # 在当前名词空间导入该模块所有公共成员(非下划线开头成员)或指定成员
# ['Path', 'PosixPath', 'PurePath', 'PurePosixPath', 'PureWindowsPath', 'WindowsPath', ....]
print(dir())
from functools import wraps as wr, partial # 别名
print(dir()) # ['Path', 'PosixPath', 'PurePath',......, 'partial', 'wr']
from os.path import exists # 加载、初始化os、os.path模块,exists加入本地名词空间并绑定
if exists(r'E:\projects\pyCode2025'):
print('Found')
else:
print('Not Found')
print(dir()) # ['Path', 'PosixPath', 'PurePath',......, 'exists', 'partial', 'wr']
print(exists) # <built-in function _path_exists>
import os
# 4种方式获得同一个对象exists
m1 = os.path.exists
m2 = exists
m3 = os.path.__dict__['exists'] # 字符串
m4 = getattr(os.path, 'exists') # 字符串
print(m1, m2, m3, m4)
print(id(m1), id(m2), id(m3), id(m4))
总结:
- 找到 from 子句中指定的模块,加载并初始化它(注意不是导入)
- 对于 import 子句后的名称
-
先查 from 子句导入的模块是否具有该名称的属性
-
如果没有,则尝试导入该名称的子模块
-
还没有找到,则抛出 ImportError 异常
-
这个名称保存到本地名词空间中,如果有 as 子句,则使用 as 子句后的名称
# -*- coding: utf-8 -*- # @Time : 2025-05-06 20:39 # @Author : AmoXiang # @File : 3.test.py # @Software: PyCharm # @Blog: https://blog.csdn.net/xw1680 from pathlib import Path # 导入类Path print(Path, id(Path)) import pathlib as pl # 导入模块使用别名 print(dir()) print(pl) print(pl.Path, id(pl.Path)) # 可以看出导入的名词Path和pl.Path是同一个对象
-
1.2.3 自定义模块
在文章的前面就已经说过 .py
文件就是一个模块。自定义模块命名规范:
- 模块名就是文件名
- 模块名必须符合标识符的要求,是非数字开头的字母、数字和下划线的组合。test-module.py 这样的文件名不能作为模块名。也不要使用中文。
- 不要使用系统模块名来避免冲突,除非你明确知道这个模块名的用途
- 通常模块名为全小写,下划线来分割
示例代码:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 20:42
# @Author : AmoXiang
# @File : test1.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
print('This is test1 module')
class A:
def show_module(self):
print(1, self.__module__, self)
print(2, __class__, id(__class__))
a = A()
a.show_module()
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 20:45
# @Author : AmoXiang
# @File : test2.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import test1
a = test1.A()
a.show_module()
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 20:45
# @Author : AmoXiang
# @File : test3.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
from test1 import A as cls
a = cls()
a.show_module()
1.2.4 模块搜索顺序
使用 sys.path 查看搜索顺序,示例:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 20:53
# @Author : AmoXiang
# @File : 4.模块搜索顺序.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import sys
'''
E:\projects\pyCode2025\base\day09-包
E:\projects\pyCode2025
E:\projects\pyCode2025\Django5Study
D:\devTools\JetBrains\PyCharm\plugins\python-ce\helpers\pycharm_display
D:\devTools\Python\Python312\python312.zip
D:\devTools\Python\Python312\DLLs
D:\devTools\Python\Python312\Lib
D:\devTools\Python\Python312
D:\devTools\Python\Python312\Lib\site-packages
D:\devTools\JetBrains\PyCharm\plugins\python-ce\helpers\pycharm_matplotlib_backend
D:\devTools\JetBrains\PyCharm\plugins\python-ce\helpers\pycharm_plotly_backend
'''
print(*sys.path, sep='\n')
显示结果为,python 模块的路径搜索顺序。当加载一个模块的时候,需要从这些搜索路径中从前到后依次查找,并不搜索这些目录的子目录。搜索到模块就加载,搜索不到就抛异常,路径也可以为字典、zip文件、egg文件。.egg文件,由 setuptools 库创建的包,第三方库常用的格式。添加了元数据(版本号、依赖项等)信息的 zip 文件。路径顺序为:
- 程序主目录,程序运行的主程序脚本所在的目录
- PYTHONPATH 目录,环境变量 PYTHONPATH 设置的目录也是搜索模块的路径
- 标准库目录,Python 自带的库模块所在目录
sys.path 可以被修改,增加新的目录。Pycharm 默认将当前的工作目录添加到了 PYTHONPATH 环境变量中,如下图所示:
1.2.5 模块的重复导入
示例代码:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 20:42
# @Author : AmoXiang
# @File : test1.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
print('This is test1 module')
class A:
def show_module(self):
print(1, self.__module__, self)
print(2, __class__, id(__class__))
a = A()
a.show_module()
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 20:45
# @Author : AmoXiang
# @File : test2.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import test1
print('local module')
import test1
import test1
从执行结果来看,不会产生重复导入的现象。所有加载的模块都会记录在 sys.modules 中,sys.modules 是存储已经加载过的所有模块的字典。打印 sys.modules 可以看到 builtins、os、os.path、sys 等模块都已经加载了,如下图所示:
1.2.6 模块运行
__name__
,每个模块都会定义一个 __name__
特殊变量来存储当前模块的名称,如果不指定,则默认为源代码文件名,如果是包则有限定名。解释器初始化的时候,会初始化 sys.modules 字典(保存已加载的模块),加载 builtins(全局函数、常量)模块、 __main__
模块、sys 模块,以及初始化模块搜索路径 sys.path,Python 是脚本语言,任何一个脚本都可以直接执行,也可以作为模块被导入。当从标准输入(命令行方式敲代码)、脚本($ python test.py)或交互式读取的时候,会将模块的 __name__
设置为 __main__
,模块的顶层代码就在 __main__
这个作用域中执行。顶层代码:模块中缩进最外层的代码。如果是 import 导入的,其 __name__
默认就是模块名。示例代码:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 21:04
# @Author : AmoXiang
# @File : test4.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import test5
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 21:04
# @Author : AmoXiang
# @File : test5.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
# 判断模块是否以程序的方式运行 $python test.py
if __name__ == '__main__':
print('in __main__') # # 程序的方式运行的代码
else:
print('in imported module') # 模块导入的方式运行的代码
if __name__ == '__main__':
用途:
- 本模块的功能测试。对于非主模块,测试本模块内的函数、类
- 避免主模块变更的副作用。顶层代码,没有封装,主模块使用时没有问题。但是,一旦有了新的主模块,老的主模块成了被导入模块,由于原来代码没有封装,一并执行了。
模块的属性:
属性名 | 作用说明 | 示例 |
---|---|---|
__name__ | 表示模块的名称。若模块作为主程序运行,其值为 "__main__" 。 | print(__name__) |
__file__ | 表示模块的文件路径(即.py文件的绝对路径)。 | print(__file__) |
__package__ | 表示模块所属的包名称,顶级模块时为 None 。 | print(__package__) |
__doc__ | 模块的文档字符串,即模块开头的三引号注释。 | print(__doc__) |
__cached__ | 表示编译后的.pyc文件路径(一般在 __pycache__ 中)。 | print(__cached__) |
__loader__ | 加载该模块的加载器对象(一般为 _frozen_importlib.BuiltinImporter )。 | print(__loader__) |
__spec__ | 模块的导入规格对象,包含其导入方式等元信息。 | print(__spec__) |
示例代码:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 21:14
# @Author : AmoXiang
# @File : test6.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
'''我是test6 module'''
print('in test6 ~~~~')
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 21:15
# @Author : AmoXiang
# @File : test7.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import test6
'''
in test6 ~~~~
__name__ test6
__doc__ 我是test6 module
__package__
__loader__ <_frozen_importlib_external.SourceFileLoader object at 0x000001E7DF279D90>
__spec__ ModuleSpec(name='test6', loader=<_frozen_importlib_external.SourceFileLoader obj
__file__ E:\projects\pyCode2025\base\day09-包\test6.py
__cached__ E:\projects\pyCode2025\base\day09-包\__pycache__\test6.cpython-312.pyc
__builtins__ {'__name__': 'builtins', '__doc__': "Built-in functions, types, exceptions, and
'''
# 模块的 __dict__ 属性是一个字典对象,它存储了模块中所有变量名和对应值的映射关系,
# 也可以理解为模块的命名空间(Namespace)。
for k, v in test6.__dict__.items():
print(k, str(v)[:80])
print(dir(test6))
for name in dir(test6):
print(getattr(test6, name))
1.3 Python中的包
使用模块可以避免函数名和变量名重名引发的冲突。那么,如果模块名重复应该怎么办呢?在 Python 中,提出了 包(Package) 的概念。包是一个分层次的目录结构,它将一组功能相近的模块组织在一个目录下。这样,既可以起到规范代码的作用,又能避免模块名重名引起的冲突,也可以将包理解为特殊的模块。 Python 模块支持目录吗?在 E:\projects\pyCode2025\base\day09-包
中新建一个目录 m,在新建 test8.py 文件,使用下面的代码:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 22:47
# @Author : AmoXiang
# @File : test8.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import m
print(m)
print(type(m))
print(dir(m))
print(*m.__dict__.items(), sep='\n') # __file__为None
print('-' * 30)
import test1
print(*test1.__dict__.items(), sep='\n') # 文件模块没有__path__
竟然可以导入目录 m,目录也是文件,所以可以导入,不过问题是,目录模块怎么写入代码?为了解决这个问题,Python 要求在目录下建立一个特殊文件 __init__.py
,在其中写入代码。
Pycharm 中,创建 Directory 和创建 Python Package 不同,前者是创建普通的目录,后者是创建一个带有 __init__.py
文件的目录即包。Python 中,目录可以作为模块,这就是包,不过代码需要写在该目录下 __init__.py
中。包的 __file__
就指向 __init__.py
这个文件。在实际项目开发时,通常情况下,会创建多个包用于存放不同类的文件。例如,开发一个网站时,可以创建如下图所示的包结构:
上图中,先创建一个名称为 shop 的项目,然后在该包下又创建了 admin、home 2个包和一个 manage.py 的文件,最后在每个包中,又创建了相应的模块。
子模块: 包目录下的 py 文件、子目录都是其子模块。假设你的目录结构如下:
your_project/
├── m/
│ ├── __init__.py # 内容: print(__name__)
│ ├── m1.py # 内容: print(__name__)
│ └── m2/
│ ├── __init__.py # 内容: print(__name__)
│ ├── m21/
│ │ └── __init__.py # 内容: print(__name__)
│ └── m22.py # 内容: print(__name__)
如上建立子模块目录和文件,所有的 py 文件中就写一句话 print(__name__)
。示例1:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 23:32
# @Author : AmoXiang
# @File : test10.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import sys
import m # 导入模块m,控制台输出结果为 m
'''
解释:
1.模块的 __name__ 是模块的名称
当你执行 import m,Python 会找到包 m,然后执行其 __init__.py 文件,用于初始化包。
在这个过程中,__name__ 的值就是 'm',因为当前正在导入的是名为 m 的包。
所以控制台输出:m。
2.只执行一次:
之后如果你再执行 import m,不会再执行 __init__.py,因为 Python 会从 sys.modules 中直接加载已有的模块实例。
'''
print(m) # <module 'm' from 'E:\\projects\\pyCode2025\\base\\day09-包\\m\\__init__.py'>
# 发现只有['m', 'marshal', 'math', 'mmap', 'msvcrt']
print(sorted(filter(lambda x: x.startswith('m'), sys.modules.keys())))
# m1模块都没有被加载到内存中,怎么能访问其中的变量呢?这里会优先当作属性处理,发现m模块中
# 没有m1属性,就报错了
# # AttributeError: module 'm' has no attribute 'm1'
# print(m.m1.width) # import 采用最小加载原则
import os
print(os.path.exists('/etc')) # 这样对吗? 对的 ==> False
# 为啥呢?我们明明没有导入 import os.path 模块?
# 那肯定有人帮我们做了嘛,要不然就报错了,那个人就是解释器,
# 解释器帮我们加载了os.path模块,所以能正常使用 os.path模块下的exists函数
示例2:
# -*- coding: utf-8 -*-
# @Time : 2025-05-06 23:36
# @Author : AmoXiang
# @File : test11.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import m.m1 # import + 完整包名 + 模块名 导入m包下的m1模块
'''
① 由于 m 是一个包,Python 首先会加载 m/__init__.py,执行其中的代码。
所以第一个输出是 m,即 print(__name__) 中的值,此时模块名为 m
② 接着加载 m.m1 模块
这会执行 m1.py 中的代码,输出 m.m1,因为此时模块的完整导入路径是 m.m1。
③ 不会加载 m2、m21、m22.py,因为这些模块没有被导入,Python 是按需加载模块的。
所有 __name__ 的值都是模块的完全限定名称(Fully Qualified Name),除非模块是被直接运行的脚本(此时是 '__main__')。
④ 为啥我导入了 m.m1,可以直接用 m,却不能直接用 m1?
==> 根本原因: import m.m1 只在当前命名空间引入了 m,没有引入 m1 这个在文章前面已经说过
'''
print(m)
# 通过该方式导入模块后,在使用时需要使用完整的名称
# 在m1模块中定义两个变量
width = 800 # 宽度
height = 600 # 高度
print(m.m1.width) # 800
print(m.m1.height) # 600
import m.m2.m21
print(m)
# 只是导入了 m.m2.m21,这在内存中加载了 m、m.m2、m.m2.m21 这三个模块,
# 但当前作用域中只存在 m 名字,与上面同理
# print(m2) # 错误的
# print(m21) # 错误的
示例3:
from m import m1
# print(m) # NameError: name 'm' is not defined
# 通过 "from + 完整包名 + import + 模块名" 形式加载指定模块
# 通过该方式导入模块后,在使用时不需要带包前缀,但是需要带模块名
print(m1.width) # 800
print(m1.height) # 600
# from m.m2 import m21
#
# print(m21)
# from + 完整包名 + 模块名 + import + 定义名
# 可以使用星号 "*" 代替定义名,表示加载该模块下的全部定义
# 通过该方式导入模块的函数、变量或类后,在使用时直接使用函数、变量或类名即可。
# from m.m1 import width, height
#
# print(width)
# print(height)
删除 __init__.py
试一试,可以发现删除并不影响导入,但是这不是良好的习惯,请保留 __init__.py
文件。模块和包的总结:
- 包能够更好的组织模块,尤其是大的模块,其代码行数很多,可以把它拆分成很多子模块,便于使用某些功能就加载相应的子模块。
- 包目录中
__init__.py
是在包第一次导入的时候就会执行,内容可以为空,也可以是用于该包初始化工作的代码,最好不要删除它(低版本 Python 不可删除__init__.py
文件) - 导入子模块一定会加载父模块,但是导入父模块一定不会导入子模块
- 包目录之间只能使用
.
点号作为间隔符,表示模块及其子模块的层级关系 - 模块也是封装,如同类、函数,不过它能够封装变量、类、函数。
- 模块就是命名空间,其内部的顶层标识符,都是它的属性,可以通过
__dict__
或 dir(module) 函数查看。 - 包也是模块,但模块不一定是包,包是特殊的模块,是一种组织方式,它包含
__path__
属性
问题1: from json import encoder 之后, json.dump() 用不了,为什么?
原因是 from json import encoder 之后,当前名词空间没有 json,json 模块已经加载过了,但是没有 json 的引用,无法使用 dump 函数。
问题2: import json.encoder 之后呢? json.dump 函数能用吗?
import json.encoder 也加载 json 模块,且当前名词空间有 json,因此可以调用 json.dump。
1.4 绝对导入与相对导入
- 绝对导入:
- 在 import 语句或者 from 导入模块,模块名称最前面不是以
.
点开头的 - 绝对导入总是去模块搜索路径中找,当然会查看一下该模块是否已经加载
- 在 import 语句或者 from 导入模块,模块名称最前面不是以
- 相对导入:
- 只能用在 from 语句中
- 使用
.
点号,表示当前目录内 - … 两点表示上一级目录
- … 三点表示上上一级
- 只在包内使用,一般不要在顶层模块中使用相对导入
- 一旦一个模块中使用相对导入,就不可以作为主模块运行了
按照下面的项目结构在 Pycharm 中新建包与模块:
myproject/
├── main.py
├── package_a/
│ ├── __init__.py
│ ├── module_a1.py
│ └── sub_a/
│ ├── __init__.py
│ └── module_a2.py
├── package_b/
│ ├── __init__.py
│ └── module_b1.py
完成之后如下图所示:
代码如下:
# package_a/sub_a/module_a2.py
def func_a2():
print("A2")
# package_a/module_a1.py
def func_a1():
print("A1")
# package_b/module_b1.py
def func_b1():
print("B1")
练习1:如果你位于 package_a/module_a1.py 文件中,想调用 sub_a/module_a2.py 中的 func_a2() 函数,应该使用什么样的导入语句?
# 直接当脚本运行
import sub_a.module_a2
sub_a.module_a2.func_a2()
from sub_a.module_a2 import func_a2
func_a2()
# 相对导入
from .sub_a import module_a2
module_a2.func_a2()
练习2:你现在在 package_a/sub_a/module_a2.py 中,想调用 module_a1.py 的 func_a1() 函数,应该使用什么样的相对导入?
from .. import module_a1
练习3:你处于 module_a2.py,想调用 package_b/module_b1.py 的 func_b1(),应该使用什么样的导入语句?
# 这种写法对吗?
from ...package_b import module_b1
from package_b import module_b1
module_b1.func_b1()
总结口诀:
- 绝对导入:始终从
"项目根目录"
(也就是 Python 的模块搜索路径 sys.path 中的路径)开始找。跨包访问,用绝对导入 - 相对导入:
从 "当前模块所在包的层级"
出发,按层级相对路径向上或向下找。相对导入,只适合包内跳转 - 别直接运行包中模块
- 测试一下有相对导入语句的模块,能够直接运行吗?不能了,很好理解,使用相对导入的模块就是为了内部互相的引用资源的,不是为了直接运行的,对于包来说,正确的使用方式还是在顶级模块使用这些包及其内部资源。相对导入,更像是目录操作。
1.5 访问控制和__all__
1.5.1 下划线开头的模块名
_
或者 __
开头的模块是否能够被导入呢?创建文件名为 _xyz.py 或者 __xyz.py 测试。都可以成功的导入,因为它们都是合法的标识符,就可以用作模块名。示例:
# -*- coding: utf-8 -*-
# @Time : 2025-05-08 5:00
# @Author : AmoXiang
# @File : __xyz.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
print('__xyz ~~~~')
# -*- coding: utf-8 -*-
# @Time : 2025-05-08 5:00
# @Author : AmoXiang
# @File : _xyz.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
print('_xyz ~~~~')
# -*- coding: utf-8 -*-
# @Time : 2025-05-08 5:00
# @Author : AmoXiang
# @File : test15.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import __xyz
import _xyz
运行结果如下所示:
1.5.2 模块内的标识符
示例代码:
# -*- coding: utf-8 -*-
# @Time : 2025-05-08 5:03
# @Author : AmoXiang
# @File : xyz.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
print(__name__)
A = 5
_B = 6
__C = 7
__my__ = 8
# -*- coding: utf-8 -*-
# @Time : 2025-05-08 5:05
# @Author : AmoXiang
# @File : test16.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
import xyz
import sys
print(sorted(sys.modules.keys()))
print(dir())
# 5 6 7 8
print(xyz.A, xyz._B, xyz.__C, xyz.__my__)
运行结果如下所示:
普通变量、保护变量、私有变量、特殊变量,都没有被隐藏,也就是说模块内没有私有的变量,在模块中定义不做特殊处理。test16.py 中:
# from语句导入
from xyz import A, _B as B, __my__, __C as C
import sys
print(sorted(sys.modules.keys()))
print(dir())
print(A, B, __my__, C)
使用 from 语句,依然可以访问所有变量。
1.5.3 from … import *和__all__
使用 from ... import *
导入:
# test16.py中
from xyz import *
import sys
print(sorted(sys.modules.keys()))
print(dir())
print(locals()['A'])
A = 55
print(locals()['A']) # 思考这个A是谁的A了
结果是只导入了 A,下划线开头的都没有导入。使用 __all__
,__all__
是一个列表,元素是字符串,每一个元素都是一个模块内的变量名。xyz.py 中:
__all__ = ["X", "Y"]
print(__name__)
A = 5
_B = 6
__C = 7
__my__ = 8
X = 10
Y = 20
test16.py 中:
from xyz import *
import sys
print(sorted(sys.modules.keys()))
print(dir())
# print(locals()['A'])
print(locals()['X'])
print(locals()['Y'])
修改 __all__
列表,加入下划线开头变量,看看什么效果:
# xyz.py
__all__ = ["X", "Y", "_B", "__C"]
print(__name__)
A = 5
_B = 6
__C = 7
__my__ = 8
X = 10
Y = 20
# test16.py
from xyz import *
import sys
print(sorted(sys.modules.keys()))
print(dir())
# print(locals()['A'])
print(locals()['X'])
print(locals()['Y'])
print(locals()['_B'])
print(locals()['__C'])
可以看到使用 from xyz import *
导入 __all__
列表中的名称。小练习:包和模块结构如下
代码:
#__init__.py 中
print(__name__)
x = 1
# m1.py
print(__name__)
y = 5
# 问: 在test.py中,如何访问到m1.py中的变量y?
# 访问到m.m1的变量y的几种实现:
import m
print(m.m1.y) # 可以吗?
# 方法1,直接导入m.m1的属性y
from m.m1 import y
print(y)
# 方法2,直接导入m1模块
import m.m1
print(m.m1.y)
from m import m1
print(m1.y)
# 方法3,
from m import * # 最小加载原则
print(dir())
# 该方法导入后,无法看到子模块m1,无法访问y
# 在__init__.py增加 ==> __all__ = ['x', 'm1'],使用__all__提供导出的名称
from m import *
print(m1.y)
# 方法4,不使用__all__
# 在__init__.py增加 ==> from . import m1
from m import *
print(m1.y)
# 不止以上4种,还有其他方式解决访问y,这里不再赘述
__init__.py
中有什么变量,则使用 from m import * 加载什么变量,这依然符合模块的访问控制。
# __init__.py中:
x = 1
from .m1 import y as _z
print(dir())
# test.py中:
import m
执行结果如下图所示:
总结:
- 使用
from xyz import *
导入:- 如果模块没有
__all__
,from xyz import *
只导入非下划线开头的该模块的变量。如果是包,子模块也不会导入,除非在__all__
中设置,或__init__.py
中导入它们 - 如果模块有
__all__
,from xyz import *
只导入__all__
列表中指定的名称,哪怕这个名词是下划线开头的,或者是子模块 - from xyz import *方式导入,使用简单,但是其副作用是导入大量不需要使用的变量,甚至有可能造成名称的冲突。而
__all__
可以控制被导入模块在这种导入方式下能够提供的变量名称,就是为了阻止from xyz import *
导入过多的模块变量,从而避免冲突。因此,编写模块时,应该尽量加入__all__
- 如果模块没有
- from module import name1, name2 导入。这种方式的导入是明确的,哪怕是导入子模块,或者导入下划线开头的名称,程序员可以有控制的导入名称和其对应的对象
1.6 导入和使用标准模块
在 Python 中,自带了很多实用的模块,称为标准模块(也可以称为标准库),对于标准模块,我们可以直接使用 import 语句导入到 Python 文件中使用。例如,导入标准模块 random(用于生成随机数),可以使用下面的代码:
import random # 导入标准模块random
在导入标准模块时,也可以使用 as 关键字为其指定别名。通常情况下,如果模块名比较长,则可以为其设置别名。导入标准模块后,可以通过模块名调用其提供的函数。例如,导入 random 模块后,就可以调用 randint() 函数生成一个指定范围的随机整数。例如,生成一个0~10(包括0和10)的随机整数的代码如下:
import random as ra # 导入标准模块random
print(ra.randint(0, 10)) # 输出0~10的随机数
除了 random 模块外,Python 还提供了大约200多个内置的标准模块,涵盖了 Python 运行时服务、文字模式匹配、操作系统接口、数学运算、对象永久保存、网络和 Internet 脚本和 GUI 构建等方面。
后续我们会学习在工作中经常使用到的模块。
1.7 第三方模块的下载与安装
在进行 Python 程序开发时,除了可以使用 Python 内置的标准模块外,还有很多第三方模块可以被我们所使用。对于这些第三方模块,可以在 Python 官方推出的 https://pypi.org/ 中找到。在使用第三方模块时,需要先下载并安装该模块,然后就可以像使用标准模块一样导入并使用了。本小节主要介绍如何下载和安装,下载和安装第三方模块可以使用 Python 提供的 pip 命令实现,pip 命令的语法格式如下:
pip <command> [modulename]
参数说明:
# 1.command: 用于指定要执行的命令。
# 1.1 常用的参数值有 install(用于安装第三方模块)
# 1.2 uninstall(用于卸载已经安装的第三方模块)
# 1.3 list(用于显示已经安装的第三方模块)等
# 2.modulename: 可选参数,用于指定要安装或者卸载的模块名,当command为install或者uninstall时不能省略。
# 例如,安装第三方wheel模块,可以在命令行窗口中输入以下代码:
C:\Users\amoxiang>pip install wheel
Collecting wheel
Downloading wheel-0.45.1-py3-none-any.whl.metadata (2.3 kB)
Downloading wheel-0.45.1-py3-none-any.whl (72 kB)
Installing collected packages: wheel
Successfully installed wheel-0.45.1
[notice] A new release of pip is available: 24.3.1 -> 25.1.1
[notice] To update, run: python.exe -m pip install --upgrade pip
说明: 在大型程序中可能需要导入很多模块,推荐先导入 Python 提供的标准模块,然后再导入第三方模块,最后导入自定义模块。如果想要查看 Python 中都有哪些模块(包括标准模块和第三方模块),可以输入以下命令:
help('modules')
如果只是想要查看已经安装的第三方模块,可以在命令行窗口中输入以下命令:
pip list
Python 标准模块也好,第三方模块也罢,导入的方式与我们自定义的模块没什么差别。
pip 常用命令汇总:
# 安装/卸载/升级包
pip install 包名 # 安装包
pip install 包名==1.2.3 # 安装指定版本
pip install 包名>=1.0,<2.0 # 安装符合版本范围的包
pip uninstall 包名 # 卸载包
pip install --upgrade 包名 # 升级包
# 查看信息
pip list # 显示已安装的所有包
pip show 包名 # 显示某个包的详细信息
pip freeze # 导出所有包和版本(通常用于 requirements.txt)
# requirements 文件操作
pip freeze > requirements.txt # 导出当前环境的包清单
pip install -r requirements.txt # 根据清单批量安装依赖
# 其他有用命令
pip check # 检查是否有包依赖冲突
pip cache dir # 查看 pip 缓存目录
pip search 关键字 # (⚠️ 已被弃用)搜索包
# 使用国内镜像源加速下载 -i http://example.com/simple 是你要使用的镜像地址
pip install 包名 -i https://pypi.tuna.tsinghua.edu.cn/simple
# 国内常用镜像源列表
镜像源 URL
清华大学 https://pypi.tuna.tsinghua.edu.cn/simple
阿里云 https://mirrors.aliyun.com/pypi/simple
中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple
华中理工大学 https://pypi.hustunique.com/simple
# --trusted-host 用于信任某个非 HTTPS 的源或自建镜像地址
# 在使用 HTTP 或非官方 HTTPS 源时,pip 可能会因 SSL 验证失败而拒绝连接,
# 此时就需要用 --trusted-host 表示你信任该主机。
# pip install some-package -i http://example.com/simple --trusted-host example.com
pip install flask -i http://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn
二、包管理
2.1 为什么使用包管理?
Python 的模块或者源文件直接可以复制到目标项目目录中,就可以导入使用了。但是为了更多项目调用使用,或者共享给别人,就需要打包,或发布到网络,以便供人使用。目的也是为了复用。Pypi(Python Package Index),公共的模块存储中心,https://pypi.python.org/pypi
2.2 主要工具
distutils: 官方库 distutils,使用安装脚本 setup.py 来构建、安装包。从1998年就是标准库的一部分,直到2000年停止开发。已被 setuptools 取代,官方不再推荐使用。不支持依赖自动安装;不支持打包非 .py
文件;功能简陋,维护已停止。
setuptools: 它是替代 distutils 的增强版工具集,包含 easy_install 工具,使用 ez_setup.py 文件。支持 egg 格式的构建和安装。提供查询、下载、安装、构建、发布、管理等包管理功能。setuptools 是包管理的核心模块。后来,setuptools 开发缓慢了,出现基于 setuptools 的 distribute 来替代 setuptools。2013年,这两个项目重新合并,distribute 被废弃,setuptools 依然是 Python 安装打包的标准方式。配合 wheel 使用可打包为 .whl 文件
pip: pip 目前包管理的事实标准。构建在 setuptools 之上,替代 easy_install 的。同样提供丰富的包管理功能。Python3.4 之前,需要单独安装,从 Python3.4 开始直接包含在安装文件中。
wheel: wheel 格式定义在 PEP427 中。wheel 是 zip 打包的扩展名为 .whl 的文件,文件中不包含 .pyc 文件。提供 bdist_wheel 作为 setuptools 的扩展命令,这个命令可以用来生成新打包格式 wheel。pip 从 1.4 版本开始提供了一个 wheel 子命令来安装 wheel 包。当然,需要先安装 wheel 模块。它可以让 Python 库以二进制形式安装,而不需要在本地编译。egg 包正在被 wheel 包代替。Pypi 网站越来越多的安装包新版本都采用了 wheel 包。使用 wheel 包,直接找到对应OS平台、对应 Python 版本的包下载安装,也不需要本地编译。
2.3 使用setup.py打包
Python 的 .py 文件就是模块,如果它只依赖 Python 标准库,就直接可以复制给别人使用,当然要注意 CPython 的版本。如果代码较多,组织到了包中,而且只依赖 Python 标准库,就可以使用 sdist 打包为 Source Distribute 源代码包。在线网址:https://packaging.python.org/tutorials/packaging-projects/#creating-setup-py
包结构:
your_project/
├── m/
│ ├── __init__.py # 内容: print(__name__)
│ ├── m1.py # 内容: print(__name__)
│ └── m2/
│ ├── __init__.py # 内容: print(__name__)
│ ├── m21/
│ │ └── __init__.py # 内容: print(__name__)
│ └── m22.py # 内容: print(__name__)
项目根目录下,构建一个 setup.py 文件,setup.py 代码如下:
# -*- coding: utf-8 -*-
# @Time : 2025-05-08 8:40
# @Author : AmoXiang
# @File : setup.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680
from setuptools import setup, find_packages
setup(
name='myproject',
version='0.1.0',
description='A sample Python project with multiple packages',
author='amoXiang',
author_email='amoXiang@qq.com',
url='https://blog.csdn.net/xw1680/category_12955592.html',
# packages=find_packages(),
packages=['m'],
python_requires='>=3.6',
)
'''
# name名字
# version 版本
# packages=[] 打包列表,
# packages=['m'],指定m,就会把m所有的非目录子模块打包
# ['m', 'm.m1.m2.m3'],逐级建立目录,但是只把m的所有非目录子模块打包,把m.m1.m2.m3打包
# ['m', 'm.m1', 'm.m1.m2', 'm.m1.m2.m3']
# description 描述信息
# author 作者
# author_email 作者邮件
# url 包的主页,可以不写
'''
data_files 参考 https://docs.python.org/3.9/distutils/setupscript.html#distutils-additional-files
执行: build 命令,编译创建一个 build 目录
PS C:\Users\amoxiang\Desktop\myproject> python .\setup.py build
# 以下是packages=['m']配置的结果
running build
running build_py
creating build\lib\m
copying m\m1.py -> build\lib\m
copying m\__init__.py -> build\lib\m
# 在项目目录下多了build目录,有一个lib子目录,lib下就是模块m的目录了。
# m目录下的*.py文件被复制了,但是子目录没有被复制。以下是packages=['m', 'm.m2.m21']配置的结果
running build
running build_py
copying m\m1.py -> build\lib\m
copying m\__init__.py -> build\lib\m
creating build\lib\m\m2\m21
copying m\m2\m21\__init__.py -> build\lib\m\m2\m21
# 可以看出,逐级构建了同样的目录结构,并只拷贝了m21的 __init__.py文件
# build得到的文件,直接拷贝到其他项目就可以用
# install 命令,安装
# build 后就可以install,直接运行
python setup.py install # 如果没有build,会先build编译,然后安装
sdist 命令: python setup.py sdist。创建源代码的分发包。产生一个 dist 目录,里面生成一个带版本号的压缩包。在其他地方解压缩这个文件,里面有 setup.py,就可以使用 $ python setup.py install 安装了, 也可以 $ pip install m-0.1.0.zip 直接使用 pip 安装这个压缩包。
bdist 命令: 二进制分发包,或称作安装程序。它可以生成目标操作系统的安装程序。
# 制作windows下的安装包
$ python setup.py bdist_wininst
$ python setup.py bdist_msi
$ python setup.py bdist --format=msi
rpm包
$ python setup.py bdist_rpm
$ python setup.py bdist --format=rpm
压缩文件
$ python setup.py bdist --format=zip$ python setup.py bdist --format=gztar
可以把自己写好的模块发布到公共的 Pypi 上,也可以搭建 Pypi 私服,供企业内部使用。注意:Pypi 里面的模块没有太好的审核机制,不保证安全,请慎重使用。
wheel 包: 安装 wheel 依赖。
C:\Users\amoxiang>pip install wheel
Collecting wheel
Downloading wheel-0.45.1-py3-none-any.whl.metadata (2.3 kB)
Downloading wheel-0.45.1-py3-none-any.whl (72 kB)
Installing collected packages: wheel
Successfully installed wheel-0.45.1
[notice] A new release of pip is available: 24.3.1 -> 25.1.1
[notice] To update, run: python.exe -m pip install --upgrade pip
# 打包命令:
$ python setup.py bdist_egg
$ python setup.py bdist_wheel
更多打包,请参考:https://packaging.python.org/en/latest/overview/
三、练习及讲解
1.如果待导入的变量与当前命名空间内的变量重名,则:
A.需要使用from..import语句导入
B.需要使用import语句导入
C.必须修改其中一个变量的名称
D.不可以导入该变量所在模块
此题答案为 C。A.需要使用from…import语句导入❌ 错。你可以使用 import 或 from … import …,都可能发生冲突。B.需要使用import语句导入❌ 错。同样不限制用哪种语法。D.不可以导入该变量所在模块❌ 错。你依然可以导入模块,只是可能会出现覆盖冲突。C选项答案也相对来说比较绝对,但是较其他答案要好。
2.查看已导入模块内的所有定义,可以使用:
A.dir()
B.show()
C.all()
D.findall()
此题答案为 A.dir()。在Python中,dir() 是用来查看一个模块(或对象)中所有可用的属性、函数、类等定义的内置函数。B.show()错误。show()不是Python的内置函数,也不是用来查看模块定义的标准方法。C.all()错误。没有all()这个函数来查看模块内容。你可能是在想__all__,但那是模块内部用于定义 *
导入行为的列表。D.findall()错误。findall()是re模块中的函数,用于正则表达式匹配,不用于查看模块结构。
3.下列说法正确的是:
A.不可以为标准模块指定别名
B.第三方模块可以直接使用import语句导入
C.需要导入多个模块时,最好先导入自定义模块
D.导入标准模块后,可以通过模块名调用其提供的函数
此题答案为 D。A.不可以为标准模块指定别名 ✘ 错误,可以给任何模块(包括标准模块)指定别名,用于简化调用。B.第三方模块可以直接使用 import 语句导入 ✘ 有条件错误。必须先安装第三方模块(如使用 pip install),安装后才能通过 import 使用。否则会报 ModuleNotFoundError。C.需要导入多个模块时,最好先导入自定义模块 ✘ 不推荐。Python 官方推荐的导入顺序是:标准库模块==>第三方模块==>自定义模块,这样更清晰、更易维护,也符合 PEP 8 的风格指南。
4.将模块中的对象加载到当前命名空间,应使用:
A.import
B.from...import...
C.import...as...
D.from...as...
此题正确答案是:B. from…import…。要将模块中的对象加载到当前命名空间,应使用 from 模块名 import 对象名 的形式,这会直接把对象(如函数、类、变量)加载进当前作用域,无需通过模块名来访问。A. import错。import是将整个模块加载,并不会把对象直接加载到当前命名空间,需要通过模块名访问。C.import…as…错。这只是给模块起别名,仍然不会把模块中的对象导入当前命名空间。D.from…as…。错误语法。Python中并没有from…as…这种写法。只能是 from 模块 import 对象 as 别名。
5.想要在模块路径添加到Python的导入检索目录后,在各版本Python中都能找到该路径,应如何添加:
A.使用append()方法添加
B.通过.pth文件添加
C.在PYTHONPATH环境变量中添加
D.以上均可
此题正确答案是:D.以上均可。Python查找模块的顺序主要依赖sys.path,而以下三种方式都可以将路径添加到模块的导入检索目录中,使其在不同版本的Python中可被找到。A.使用 append() 方法添加。通过 sys.path.append('your_path')
将目录临时添加到模块搜索路径中,此方法仅对当前运行的 Python 进程有效,重启后失效。B.通过.pth文件添加。将自定义路径写入Python安装目录或虚拟环境的site-packages下的 pth文件中。优点:永久生效;适用于所有版本和解释器,只要对应的 site-packages 被加载。C.在PYTHONPATH 环境变量中添加。设置环境变量PYTHONPATH,让系统自动将该路径加入到 sys.path 中。
6.导入模块的关键字是:
A.re
B.import
C.local
D.export
此题正确答案是:B。
7.通过 "from 包名 import 模块名"
的方式加载模块,使用该模块内变量时:
A.需要带包前缀和模块名
B.不需要带包前缀,需要带模块名
C.不需要带模块名,需要带包前缀
D.不需要带包前缀和模块名
此题正确答案是:B。from 包名 import 模块名导入方式后,如果你要使用该模块中的变量、函数或类,你需要带上模块名,但不需要带包名。A.需要带包前缀和模块名❌ 错误。在这种导入方式下,不需要带包名,仅需要带模块名。C.不需要带模块名,需要带包前缀❌ 错误。在 from … import … 语法下,只需要模块名,而不需要包前缀。D.不需要带包前缀和模块名❌ 错误。只有在 from … import … 导入具体对象(如变量、函数)时,才能不带模块名。
8.在调用导入模块中的函数时,需要在函数名前添加:
A.类名
B.包名
C.模块名
D.实例名
此题正确答案是:C。和上一题一个意思,这里不在赘述。
9.下列哪项无需创建新的命名空间就可以导入demo.py模块中的所有定义:
A.import demo
B.import demo.py
C.from demo import *
D.from * import demo
此题正确答案是:C。当使用 from demo import *
的方式时,Python 会直接将 demo.py 模块中的所有定义(如变量、函数、类等)导入当前命名空间,而不需要创建新的命名空间。A. import demo❌ 错误。使用 import demo 会将 demo 模块加载到当前命名空间,但你需要通过 demo.x 或 demo.func() 来访问其中的定义,而不是直接访问。B. import demo.py❌ 错误。Python 不支持直接导入 .py 文件。应该使用 import demo(不带 .py 后缀)。D. from * import demo
❌ 错误。from * import demo
不是有效的 Python 语法。from ... import *
是用于导入模块中的所有定义,而 * 不能作为模块名。
10.可以使用()命令安装第三方模块:
A.pip命令
B.pop命令
C.install命令
D.help 命令
此题正确答案是:A。没啥好说的
11.在IDLE中输入()可查看Python中的标准模块和第三方模块:
A.help('list')
B.pip list
C.help('modules')
D.pip modules
此题正确答案是:C。在IDLE中输入 help('modules')
可以列出当前Python环境中已安装的所有标准模块和第三方模块。它会显示一个模块的列表,并帮助你查找你可以使用的模块。A.help('list')
❌ 错误。help('list')
只会显示list类型的文档,而不是模块列表。list是Python内置的一个数据类型。B.pip list❌ 错误。pip list是在命令行中查看已安装的第三方Python包的命令,而不是在IDLE中运行的命令。D.pip modules❌ 错误。没有 pip modules 这个命令。pip list 才是正确的命令来查看已安装的第三方包。
12.下列说法错误的是:
A.使用模块可以避免函数名和类名冲突
B.一个扩展名为".py"的文件就是一个模块
C.使用模块可以提高代码的可维护性和可重用性
D.导入模块时,模块名不用区分大小写
此题正确答案是:D。A.正确。使用模块可以将不同的函数、类、变量放在不同的命名空间中,从而避免命名冲突。例如,module1.function() 和 module2.function() 是完全独立的。B.正确。Python 文件(扩展名为 .py)是一个模块,模块是用来组织代码的文件。你可以在 Python 中通过 import 来导入这些 .py 文件。C.正确。模块化的代码结构使得每个模块都可以独立开发、测试、维护和重用,提高了代码的可维护性和可重用性。D.错误。Python 是区分大小写的,在导入模块时,模块名是区分大小写的。例如,import math 和 import Math 是不同的模块,math 是正确的模块名,而 Math 并不是 Python 标准库中的模块。
13.下列关于__init__.py文件说法正确的是:
A.在导入包时,__init__.py文件会自动执行
B.__init__.py文件没有任何作用,可从包中删除
C.在导入包时,不会导入__init__.py文件
D.__init__.py文件是一个包文件
此题正确答案是:A。当你使用 import 包名 或 from 包名 import 模块名 等方式导入包时,Python 会自动执行该包目录下的 __init__.py
文件。这个文件的作用是:将该目录标识为 Python 包;可以用来执行初始化代码;可以定义包的对外接口(例如通过 __all__
);可以执行一些副作用或默认导入等。B.错误。虽然从 Python 3.3 起,即使没有 __init__.py
也可以识别为“命名空间包”,但它仍然很重要,尤其在传统包和兼容性方面,依然常用。C.错误。正相反,正是导入包时,__init__.py
会被自动执行。D.有误导性。__init__.py
文件属于包的一部分,但不能说它就是“包文件”。真正的包是一个包含 __init__.py
的目录,而不是某一个具体文件。
14.关于自定义模块说法正确的是:
A.自定义模块可随意命名
B.模块文件的扩展名可有可无
C.如果自定义模块名称与标准模块名称相同,将无法创建此模块
D.模块中能定义函数、类和变量,也可能包含可执行代码
此题正确答案是:D。一个自定义模块(即 .py 文件)可以包含:变量定义、函数定义、类定义,甚至可以包含可直接执行的代码(如用于测试的代码块,常用 if __name__ == "__main__":
来包裹)。A.错误。模块名虽然灵活,但必须符合 Python 标识符规范,不能包含空格、特殊符号,不能以数字开头,并且不能与已有的标准库模块重名(否则可能造成冲突)。B.错误。模块必须是以 .py 为扩展名的文件(或 .pyc 的已编译版本等),否则 Python 无法识别为模块。C.错误。你可以创建同名模块,但这会引发导入时的混淆,Python 会优先导入当前目录下的模块,可能导致标准库模块无法正常使用。因此不是“无法创建”,而是容易造成导入冲突,不推荐。
15.当使用import语句导入模块时,默认查找目录的位置是保存在:
A.os.path中
B.sys.path中
C.os.PYTHONPATH中
D.sys.PYTHONPATH中
此题正确答案是:B。当你使用 import 模块名 语句导入模块时,Python 会按照一定的顺序在多个目录中查找该模块。这些查找目录的路径就保存在 sys.path 中。A.错误。os.path 是用于处理路径的模块,不用于保存模块查找路径。C.错误。os 模块中没有 PYTHONPATH 这个属性。D.错误。sys 模块中没有 PYTHONPATH 这个属性,模块查找路径保存在 sys.path 中,而不是 sys.PYTHONPATH。
16.分别在demo.py和当前Python文件中输入如下代码,demo.py模块和当前文件的运行结果分别为:
01 # demo.py
02 print(__name__)
01 # 当前Python文件
02 import demo
A.__name__和空
B.__name__和__name__
C.__name__和__main__
D.__main__和 demo
此题正确答案是:D。当模块被导入时,其 __name__
就是模块名(即 demo);当模块被直接运行时,其 __name__
是 "__main__"
。
17.运行当前Python代码文件后,输出结果为:
01 # file:demo.py
02 a = "123"
03 b = 2
01 # 当前Python文件
02 from demo import a,b
03 def ff(a,b):
04 return a*b
05 print(ff(5,5))
06 print(a*b)
A.运行错误
B.25 123123
C.123123 123123
D.25 25
此题正确答案是:B。
18.小明在电脑桌面上创建了一个Python文件,他想要导入D盘下的game模块,所在路径为 "D:\Doc\play"
,然后调用game模块中的name变量,在当前Python文件中,第3行代码应填入:
01 # file:game.py
02 name = "League of Legends"
01 # 当前Python文件
02 import sys
03
04 import game
05 print(game.name)
A.sys.path.append(r"D:\Doc\play")
B.sys.append(r"D:\Doc\play")
C.path.append(r"D:\Doc\play")
D.append(r"D:\Doc\play")
此题正确答案是:A。可以用insert添加到列表第一个元素。
19.每一个模块都有一个内置的字符串变量__name__,下列代码的输出结果为:
01 def showname():
02 if __name__=="__main__":
03 print(__name__)
04
05 showname()
A.__name__
B.__main__
C.False
D.True
此题正确答案是:B。
20.demo模块内的代码如下:
# file:demo.py
def improvement():
print('用冲浪的勇气,对待波浪线般的人生。')
def saying():
print('对未来的真正慷慨,是把一切献给现在。')
improvement()
# 现在当前Python文件中输入:
import demo
demo.saying()
运行结果为:
A.用冲浪的勇气,对待波浪线般的人生。
对未来的真正慷慨,是把一切献给现在。
B.用冲浪的勇气,对待波浪线般的人生。
C.对未来的真正慷慨,是把一切献给现在。
D.对未来的真正慷慨,是把一切献给现在。
用冲浪的勇气,对待波浪线般的人生。
此题正确答案是:A。
21.下列哪项是错误的:
A.from random import *
B.import random, time
C.import random
import time
D.import random time
此题正确答案是:D。
22.下列哪项不能输出room模块中的变量sofa:
A.import room as M
print(M.sofa)
B.import room
print(room.sofa)
C.from room import sofa
print(sofa)
D.import room as M
print(room.sofa)
此题正确答案是:D。
23.想要输出两天后是星期几,下列代码能否正确运行?
c = time.localtime()
t = time.time()-3600 * 24 * 2
print(time.localtime(t).tm_wday)
A.可以
B.不能,应在代码的任意位置填入 import time
C.不能,应在第1行代码的上方填入 import time
D.不能,应在第1行代码的上方填入from time import localtime
此题正确答案是:C。要使用模块必须先导入。
24.下列哪项能正确安装第三方模块requests:
A.pip install requests
B.uninstall requests
C.pip list requests
D.get requests
此题正确答案是:A。
25.在music包中有一个claasical模块,该模块内有变量:
composer = "Mozart"
# 在当前Python文件中想要调用composer,下列哪项可以输出 "作曲家: Mozart":
A.import classical
print("作曲家:", classical.composer)
B.import music
print("作曲家:",music.composer)
C.import music.classical
print("作曲家:", classical.composer)
D.import music.classical
print("作曲家:",music.classical.composer)
此题正确答案是:D。
26.下列代码运行后显示错误,哪里出错了呢:
a='是谁?在敲打我窗?'
__name__== __main__
def aa():
print(a)
aa()
A.第1行代码应写在3、4行之间
B.第2行代码错误,应改为: if __name__== '__main__':
C.第2行代码错误,应改为: if __name__==__main__:
D.第4行代码错误,应改为: print(global a)
此题正确答案是:B。
27.demo模块内代码如下:
01 # file:demo.py
02 a = "3月8日"
03 b = "5月1日"
04 if __name__=='__main__':
05 def func(s):
06 if s == "妇女节":
07 return a
08 if s == "劳动节":
09 return b
10 print(func("妇女节"))
# 在当前Python文件中想要调用demo模块中的func函数,写入如下代码后却运行报错,怎样才能输出"3月8日":
01 # 当前Python文件
02 from demo import func
03 print(func("妇女节"))
A.当前Python文件的第2行代码应改为: from demo import func()
B.当前Python文件的第2行代码应改为: from demo import func(s)
C.demo文件中的第4行代码应删除,并将第5至9行代码的缩进量减少一个级别,第10行的代码缩进量增加一个级别
D.demo文件中的第4行代码应移动至第9、10行代码之间,并将第5至9行代码的缩进量减少一个级别,第10行的代码缩进量增加一个级别
此题正确答案是:D。
28.demo模块内代码如下:
01 # demo.py
02 class MyClass:
03 def __init__(self, a, b):
04 self.a = a
05 self.b = b
06 def method(self):
07 return self.a * self.b
# 在当前窗口输入如下代码却显示错误,请帮忙改正:
01 # 当前Python文件
02 import demo.py
03 c = demo.MyClass(2, 2)
04 print(c.method())
A.第2行应改为import demo
B.第3行应改为c = MyClass(2, 2)
C.第4行应改为print(demo.method())
D.A、B、C选项都对
此题正确答案是:A。
29.demo模块内代码如下:
01 # demo.py
02 class MyClass:
03 def __init__(self, a, b):
04 self.a = a
05 self.b = b
06 def method(self):
07 return self.a * self.b
# 在当前窗口输入如下代码却显示错误,请帮忙改正:
01 # 当前Python文件
02 from demo import MyClass, method
03 c = MyClass(2,2)
04 print(c.method())
A.第2行代码改为: from demo import *
B.第2行代码改为: from demo import MyClass
C.第3行代码改为: c = demo.MyClass(2, 2)
D.A、B选项都正确
此题正确答案是:D。
30.小明想要查看内置模块collections的语法信息,在IDLE中输入help collections运行后却报错,他错在哪里了呢:
A.应输入: >>>help(collections)
B.应输入: >>>import collections
>>>help(collections)
C.应输入: >>>import collections
>>>collections.help
D.不能在IDLE中查看,应新建一个Python文件,然后在其中查询
此题正确答案是:B。
至此今天的学习就到此结束了,笔者在这里声明,笔者写文章只是为了学习交流,以及让更多学习Python语言的读者少走一些弯路,节省时间,并不用做其他用途,如有侵权,联系博主删除即可。感谢您阅读本篇博文,希望本文能成为您编程路上的领航者。祝您阅读愉快!
好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
如果我的博客对你有帮助、如果你喜欢我的博客内容,请点赞
、评论
、收藏
一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
编码不易,大家的支持就是我坚持下去的动力。点赞后不要忘了关注
我哦!