模块:

python 中的模块相当于 C/C++ 中的头文件,在 C/C++ 中需要通过 #include 导入头文件,才可以使用头文件中的函数,而在 python 中导入模块,要使用 import 关键字,导入模块之后,才可以使用模块中的方法;

python 中的模块是以 .py 为后缀的文件,它既可以包含函数,也可以包含变量;模块文件也是源码文件;

python 中的所有模块,可以在安装路径下的 lib 文件夹下查看,如下所示:

Python面板模块 python模块放在哪里_python

ubuntu 环境下 python3 模块的位置在 /user/lib/python3.5/:

Python面板模块 python模块放在哪里_自定义_02


pip:

python 在安装好之后,就会自带很多模块,例如 sys、os、random 等;

但是除了 python 自带的模块之外,我们通常还需要使用一些第三方的模块,这时候就需要我们自己安装了;

而 pip 就是 python 里的模块管理工具,可以用来安装第三方的模块;

在 windows 系统下安装 python 的时候,会自动安装 pip 工具,可以使用 pip --version 命令查看:

Python面板模块 python模块放在哪里_私有属性_03

然后使用 pip 安装 pygame 模块,直接在终端输入命令:pip install pygame 即可,如下:

Python面板模块 python模块放在哪里_Python面板模块_04

查看安装好的模块的详细信息:

Python面板模块 python模块放在哪里_python_05

但是在导入 pygame 模块的时候,总是会输出 pygame 模块的版本信息:

Python面板模块 python模块放在哪里_python_06

解决办法是到 pygame 安装的路径下,找到 __init__.py 文件:

Python面板模块 python模块放在哪里_python_07

然后打开该文件,找到下面的输出语句,注释掉即可:(我的这条输出语句是倒数第二个语句块)

Python面板模块 python模块放在哪里_python_08

 

而在 ubuntu 下安装模块时需要注意,因为 pip 工具是在 python 2.x 下的,所以用 pip 工具安装模块时也是将模块安装到 python 2.x 中的;查看 pip 版本的时候可以看到如下信息:

Python面板模块 python模块放在哪里_自定义_09

如果 ubuntu 系统下默认没有安装 pip 工具,可以用 sudo apt install python-pip 命令安装:

Python面板模块 python模块放在哪里_Python面板模块_10

如果你用的是 python 3.x,那么也可以不用安装 pip 工具,直接安装 pip3 工具即可,

Python面板模块 python模块放在哪里_私有属性_11

查看安装好之后的 pip3 工具:

Python面板模块 python模块放在哪里_私有属性_12

安装好 pip3 工具之后,直接用 sudo pip3 install pygame 命令,就可以将 pygame 模块安装到 python 3.x 下了;

但是我用 pip3 工具安装模块时,报如下错误:

Exception:
Traceback (most recent call last):
  File "/usr/share/python-wheels/urllib3-1.13.1-py2.py3-none-any.whl/urllib3/response.py", line 226, in _error_catcher
    yield
  File "/usr/share/python-wheels/urllib3-1.13.1-py2.py3-none-any.whl/urllib3/response.py", line 301, in read
    data = self._fp.read(amt)
  ......
  File "/usr/share/python-wheels/urllib3-1.13.1-py2.py3-none-any.whl/urllib3/response.py", line 231, in _error_catcher
    raise ReadTimeoutError(self._pool, None, 'Read timed out.')
requests.packages.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.

Python面板模块 python模块放在哪里_自定义_13

Python面板模块 python模块放在哪里_自定义_14

这是因为用国内网络安装太慢,导致的超时错误,可以使用一些国内的镜像:

清华大学:        https://pypi.tuna.tsinghua.edu.cn/simple
阿里云:         http://mirrors.aliyun.com/pypi/simple
中国科技大学:    https://pypi.mirrors.ustc.edu.cn/simple
豆瓣(douban):    http://pypi.douban.com/simple
中国科学技术大学:    http://pypi.mirrors.ustc.edu.cn/simple

临时使用镜像可以在 pip3 工具后面加参数 -i,指定源,如下所示:

sudo pip3 install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple

Python面板模块 python模块放在哪里_python_15

永久使用镜像:修改 ~/.pip/pip.conf (没有就创建一个), 内容如下:

[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple

但是,我用这种配置文件的方式,还是会报超时异常;

参考资料:http://www.mamicode.com/info-detail-2349450.html

 

pip 模块管理工具还有一些其他的用法:

  • 安装已经下载好的安装包:
pip install 下载好的安装包
  • 查看已经安装了哪些模块:
pip list

Python面板模块 python模块放在哪里_自定义_16

  • 显示已安装模块的具体信息:
pip show --files pygame

Python面板模块 python模块放在哪里_自定义_17

  • 列出哪些软件包已过期,即有新的软件包可以升级:
pip list --outdated

Python面板模块 python模块放在哪里_Python面板模块_18

  • 升级软件包:

windows 系统下要在 pip 工具前面加 python -m,否则会升级失败:

python -m pip install --upgrade pip

Python面板模块 python模块放在哪里_自定义_19

  • 卸载软件包:
pip uninstall pygame

Python面板模块 python模块放在哪里_自定义_20


自定义模块:

一个模块就是一个 .py 文件,里面可以包含函数和变量;

比如定义一个模块叫 MyMath,就是创建一个 MyMath.py 文件;然后在文件中声明一个变量,和一个函数:

# 变量
dec = "自定义的模块"

# 函数:求和
def getSum(a, b):
    return a + b

然后在主程序中导入该模块,并使用模块中的函数和变量:

# 导入自定义的模块:import 模块文件的名字(不用带 .py 后缀)
import MyMath

print("MyMath.dec:", MyMath.dec)        # 使用模块中的变量
print("2 + 3 = ", MyMath.getSum(2, 3))  # 使用模块中的函数

输出结果:

Python面板模块 python模块放在哪里_私有属性_21

注意:在使用我们自定义的模块时,会自动生成一个 __pycache__ 文件夹,然后在该文件夹中自动生成一个 MyMath.cpython-38.pyc 文件;

Python面板模块 python模块放在哪里_自定义_22

这个文件是 python 解析器将 MyMath 模块解析之后生成的字节码文件,相当于 java 的 .class 文件;cpython 表示 python 解析器是用 c 语言写的,38 表示 python 的版本是 3.8,.pyc 是字节码文件的后缀名;


 

导入模块:

在 python 中可以用 import 或 from ... import ... 来导入模块;

  • 将整个模块(somemodule)导入,格式为:import somemodule
# 导入 MyMath 模块
import MyMath

# 使用 MyMath 模块中的变量和函数:
# 如果只导入了模块名,那么在使用模块中的变量和函数时,必须在前面加上模块名
print("MyMath.dec:", MyMath.dec)        # 使用模块中的变量
print("MyMath.getSum:", MyMath.getSum(2, 3))  # 使用模块中的函数
print("getSum:", getSum(2, 3))	# 如果加模块名会报错:name 'getSum' is not defined
  • 将某个模块中的某个函数(somefunction)导入,格式为:from somemodule import somefunction
# 将 MyMath 模块中的 getSum 函数导入
from MyMath import getSum

# 因为已经导入了 getSum 函数,所以可以直接使用
print("getSum:", getSum(2, 3))

# 反而如果在 getSum 函数前面加模块名,就会报错:name 'MyMath' is not defined
# print("MyMath.getSum:", MyMath.getSum(2, 3))

# 因为导入的是 MyMath 模块中的 getSum 函数,而不是导入了 MyMath 模块,
# 所以不能使用 MyMath 模块中的其他功能;
print("MyMath.dec:", MyMath.dec)    # 报错:name 'MyMath' is not defined
  • 将某个模块中的多个函数或变量导入,格式为:from somemodule import firstfunc, secondfunc
# 将 MyMath 模块中的 dec 变量和 getSum 函数导入
from MyMath import dec, getSum

# 因为已经导入了 dec 变量和 getSum 函数,所以可以直接使用
print("dec:", dec)
print("getSum:", getSum(2, 3))
  • 将某个模块中的全部函数和变量导入,格式为:from somemodule import *
# 将 MyMath 模块中的全部变量和函数导入
from MyMath import *

# 因为已经导入了 MyMath 模块中的所有功能,所以可以直接使用
print("dec:", dec)
print("getSum:", getSum(2, 3))
  • 为导入的模块起别名:(如果模块的名称比较长,可以使用别名)
# 导入 MyMath 模块,并为 MyMath 模块起个别名 mm
import MyMath as mm

# 使用 mm 代替 MyMath 调用模块中的变量和函数
print("dec:", mm.dec)
print("getSum:", mm.getSum(2, 3))

注意:如果在不同的模块中,有名称相同的函数都被导入了,那么后一次导入的函数有效;所以,应尽量避免使用 import * 这种方式,因为存在一定的风险;推荐使用 import somemodule 的方式,可以明确的知道哪个函数出自那个模块;

导入模块的时候,先在当前项目路径下进行搜索,如果搜索不到,再到 python 系统目录下进行搜索;


 

模块中的私有属性:

python 中变量命名的规则:

  • num:前后都没有下划线的是公有变量;
  • __num:前置双下划线的是私有变量;
  • __init__:前后双下划线的是 python 系统内置的变量;
  • _num:前置单下划线的是私有化的属性;私有化的属性在类中的用法跟公有属性一样,类对象和子类都可以访问;但是如果私有属性用在模块中,当使用 from somemodule import * 导入模块时,私有属性无法使用;
  • num_:单后置下划线用于避免与 python 关键词的冲突;比如 if_ 可以作为一个变量;

将自定义模块 MyMath.py 改为:

# 变量
dec = "自定义的模块"

# 模块中的私有属性
_num = 100
__num2 = 200

# 函数:求和
def getSum(a, b):
    return a + b

然后在外部使用 from MyMath import * 方式导入模块:

# 将 MyMath 模块中的全部变量和函数导入
from MyMath import *

# 因为已经导入了 MyMath 模块中的所有功能,所以可以直接使用
print("dec:", dec)
print("getSum:", getSum(2, 3))

# 无法使用模块中的私有属性
print("_num:", _num)
print("__num2:", __num)

但是如果在外部使用 import MyMath 方式导入模块,则可以使用模块中的私有属性:

# 导入 MyMath 模块
import MyMath

# 可以使用模块中的私有属性
print("_num:", MyMath._num)
print("__num2:", MyMath.__num2)

 

在模块中进行测试(__name__ 变量的用法):

python 中在导入一个模块的时候,会将模块中的代码从头到尾执行一遍;如果我们在模块中写了测试程序输出一些信息,那么在主程序中导入该模块的时候,也会执行模块中的测试代码输出信息;

例如,在模块中写一个测试语句,如下所示:

# 变量
dec = "自定义的模块"

# 函数:求和
def getSum(a, b):
    return a + b

print("测试:", getSum(22, 33))

然后在主程序中导入该模块:

# 导入 MyMath 模块
import MyMath

# 使用模块中的函数
print("getSum:", MyMath.getSum(2, 3))

输出结果:

Python面板模块 python模块放在哪里_私有属性_23

那么应该怎么解决在主程序中导入模块时,不执行模块中的测试代码呢?

此时需要用到一个系统内置的变量 __name__,我们在 MyMath 模块中输出该变量的值:

# 变量
dec = "自定义的模块"

# 函数:求和
def getSum(a, b):
    return a + b

# 输出 __name__ 变量的值
print("__name__:", __name__)

输出该变量的值为:__main__

Python面板模块 python模块放在哪里_python_24

但是,当我们在外部程序中导入 MyMath 模块,因为导入模块的时候会执行一遍模块中的所有代码,此时模块中输出 __name__ 变量的值变成了 MyMath 模块的名字,如下:

Python面板模块 python模块放在哪里_python_25

所以,如果我们想在模块中写一些测试代码,但是又不想被外部程序导入该模块的时候,执行这些测试代码,可以如下操作:

# 变量
dec = "自定义的模块"

# 函数:求和
def getSum(a, b):
    return a + b

# 测试代码都写在该条件语句中,在外部导入该模块的时候,就不会执行了
if __name__ == "__main__":
    print("测试:", getSum(22, 33))

 

模块中 __all__ 变量的用法:

我们知道导入模块中的所有功能可以使用方法:from somemodule import *,而 __all__ 变量的作用就是在使用该方法时限制导入模块中的某些功能;

自定义一个模块,名字为 sendMsg.py,在模块中使用 __all__ 变量:

# __all__ 变量的作用是限制外部使用 from sendMsg import *
# 方法导入该模块时,只能导入 __all__ 变量指定的成员;
# __all__ 变量的值是一个字符串列表,列表中的元素不管是变量,
# 还是函数,或是类,都用字符串表示;
# 下面的语句表示 from sendMsg import * 导入该模块时,
# 只能使用模块中的变量 num 和 test1 函数,而不能使用 test2 函数;
__all__ = ["num", "test1"]

# 在模块中声明一个全局变量
num = 100

# 在模块中定义两个函数
def test1():
    print("=== test1 ===")

def test2():
    print("=== test2 ===")

在 main.py 中导入 sendMsg 模块:

# 导入模块
from sendMsg import *

# 调用模块中的变量
print("num:", num)

# 调用模块中的方法
test1()
test2() # 会调用失败

输出结果:

Python面板模块 python模块放在哪里_自定义_26


 

包:

一个模块是指一个 .py 文件,而包是一个包含多个 .py 文件的文件夹,并且该文件夹中必须有一个 __init__.py 文件,有了该文件才能被称之为包;即如果文件夹中含有多个 .py 文件,但是没有 __init__.py 文件,则只是一个普通的文件夹,不能称之为包;如下所示;

Python面板模块 python模块放在哪里_私有属性_27

Python面板模块 python模块放在哪里_Python面板模块_28

其中 recvMsg.py 中有一个函数:

# 在 recvMsg 模块中定义一个函数
def recvTest():
    print("=== recvTest() ===")

而 sendMsg.py 中也有一个函数:

# 在 sendMsg 模块中定义一个函数
def sendTest():
    print("=== sendTest() ===")

当然,一个普通的文件夹下包含多个模块,也是可以通过下面方法被外部导入的:

Python面板模块 python模块放在哪里_python_29

但是,如果文件夹下有很多模块,我们就需要写很多个 from ... import ... 语句,那么能不能通过 import msg 或者 from msg import * 来导入 msg 文件夹下的所有模块呢?答案是否定的。但是如果 msg 是包,就可以实现。

不过,如果 __init__.py 为空,也不能直接导入包中的模块,需要对 __init__.py 进行编辑;

1、在 __init__.py 中使用 __all__ 变量:

前面已经讲过 __all__ 变量用在模块中,用于指定外部使用 from 模块名 import * 导入该模块时,可以使用模块中的哪些功能;

而包中使用 __all__ 变量,用于限制外部使用 from 包名 import * 导入该包时,可以使用包中的哪些模块;

比如在 __init__.py 中添加如下代码:

__all__ = ["sendMsg"]

表示外部只能使用包中的 sendMsg 模块:

# 导入包中的模块
from msg import *

# 使用包中的模块
# 因为 __init__ 中指定 __all__ 变量的值为 sendMsg,
# 所以可以使用 sendMsg 模块中的所有功能,
# 而不能使用 recvMsg 模块中的功能;
sendMsg.sendTest()
recvMsg.recvTest()

输出结果:

Python面板模块 python模块放在哪里_私有属性_30

但是,__all__ 变量只能影响 from msg import * 方法,当外部使用 import msg 的时候,还是不能使用包中的模块;

2、在 __init__.py 中导入包中的模块:

用于指定当外部使用 import msg 导入包的时候,可以使用包中的哪些模块;修改 __init__.py 文件为:

# 导入包中的模块,下面两种方法都可以
from . import sendMsg       # 从当前路径下导入模块
from msg import recvMsg     # 从 msg 文件夹下导入模块

在 main.py 中导入 msg 包时,就可以直接使用包中的模块了:

# 导入包
import msg

# 使用包中的模块
msg.sendMsg.sendTest()
msg.recvMsg.recvTest()

3、在 __init__.py 中输出数据:

__all__ = ["sendMsg"]
# 在 __init__.py 中输出数据
print("=== init ===")

当外部导入包时,会执行 __init__.py 中的所有代码,所以会直接输出数据;

前面我们已经讲过,当导入模块时,也会执行模块中的所有代码;


 

包的发布(安装):

我们知道,当导入一个模块的时候,首先会在当前项目路径下搜索该模块,如果搜不到,再到 Python 系统路径下搜索;导入包也是一样的;

而我们自己创建的模块或包,只能在当前项目路径下才能使用,如果换个其他的项目,或者路径,就不能使用了;

如果想不管在什么路径下都可以使用我们自定义的模块或包,那么就需要把包发布到 python 的系统路径下;

发布包的步骤:

1、在包的同级目录下创建一个 setup.py 文件,里面的内容如下:

# 这是固定写法
from distutils.core import setup

# name:生成的包的名字
# version:包的版本
# description:包的描述信息
# author:作者
# py_modules:用来指定包中的模块
setup(name="chenhx", version="1.0", description="chenhx's module", author="chenhx", py_modules=['msg.sendMsg', 'msg.recvMsg'])

2、执行 python setup.py build 命令构建包:

Python面板模块 python模块放在哪里_Python面板模块_31

Python面板模块 python模块放在哪里_Python面板模块_32

3、执行 python setup.py sdist 命令生成发布压缩包:

Python面板模块 python模块放在哪里_python_33

Python面板模块 python模块放在哪里_私有属性_34

4、安装:

将 chenhx-1.0.tar.gz 随便放在哪个路径下都可以,然后解压 chenhx-1.0.tar.gz,解压之后变成:

Python面板模块 python模块放在哪里_Python面板模块_35

然后在命令提示符下进入该路径,执行 python setup.py install 命令进行安装:

Python面板模块 python模块放在哪里_私有属性_36

5、到此为止,已经将包发布到了 python 的系统路径下了,不管在什么位置都可以使用了;我们在 D 盘根目录下创建一个 main.py 文件,内容为:

# 导入包
import msg

# 使用包中的模块
msg.sendMsg.sendTest()
msg.recvMsg.recvTest()

执行结果为:

Python面板模块 python模块放在哪里_python_37