模块
在计算机程序的开发过程中,随着程序代码越写越多,一个文件里代码就会越来越长,越来越不容易维护。
为了编写可维护的代码,我们把很多函数分组,分别放在不同的文件里,这样每个文件包含的代码就相对较少,在python中,一个 .py文件就称之为一个模块 Module
使用模块的好处
1、提高可维护性;编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用
2、可以避免函数名和变量名冲突。每个模块有独立的命名空间,因此相同名字的函数和变量可以存在于不同的模块中,所以,在编写模块时,不必考虑名字会与其它模块冲突
模块分为3种:
1、内置标准模块(标准库),执行help(‘modules')查看所有python自带模块列表
2、第三方开源模块,可通过 pip install 模块名 联网安装
3、自定义模块
模块调用
import sys from os import replace from django.conf.urls import static as dj_st from django.conf.urls import *
注意:模块一旦被调用,即相当于执行了另一个py 文件里的代码
自定义模块
创建一个 .py文件,就可以称之为模块,就可以在另一个文件里就被调用
模块查找路径
自己写的模块只能在当前路径下的程序里才能导入,这与导入路径有关
>>> import sys >>> sys.path ['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/wxg/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages'] >>>
python解释器会按照列表顺序去依次到每个目录下去匹配你要导入的模块名,只要在一个目录下匹配到了该模块名,就立刻导入,不再继续往后找。
列表的第一个元素为空,即代表当前目录,所以自己定义的模块在当前目录会被优先导入
模块安装
直接通过pip安装
pip3 install django
安装后,直接导入使用就可以
包 Package
当模块文件越来越多,就需要对模块文件进行划分,比如把负责根数据库交互的都放进一个文件夹,把与页面交互相关的放另一个文件夹
─ my_proj
├── crm
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── manage.py
└── my_proj
├── settings.py
├── urls.py
└── wsgi.py
像上面这样,一个文件夹管理多个模块文件,这个文件夹就被称为包
执行manage.py
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ ls crm manage.py my_proj wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ python2 manage.py Traceback (most recent call last): File "manage.py", line 4, in <module> from crm import views ImportError: No module named crm
使用python2报错,找不到模块
包就是文件夹,但在该文件夹下必须存在__init__.py文件,该文件内容可以为空。__init__.py用于标识当前文件夹是一个包。
在crm目录下创建一个空文件__init__.py,再次执行 成功
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ touch crm/__init__.py wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ ls crm/ admin.py apps.py __init__.py models.py __pycache__ tests.py views.py wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ python2 manage.py hello world!
使用python3执行成功
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ ls crm manage.py my_proj wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ python3 manage.py hello world!
跨模块导入
目录结构如下
. ├── crm │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── __init__.pyc │ ├── models.py │ ├── __pycache__ │ │ └── views.cpython-36.pyc │ ├── tests.py │ ├── views.py │ └── views.pyc ├── __init__.py ├── manage.py └── proj ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
如何实现在crm/views.py 里导入proj/settings.py模块
直接导入会报错,找不到模块
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj/crm$ python3 views.py Traceback (most recent call last): File "views.py", line 3, in <module> from proj import settings ModuleNotFoundError: No module named 'proj'
因为路径找不到,
在 crm/views.py中添加环境变量
1 import sys, os 2 3 print(dir()) 4 print('file', __file__) 5 6 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 7 print(BASE_DIR) 8 sys.path.append(BASE_DIR) 9 10 from proj import settings 11 12 def sayhi(): 13 print('hello world!') 14 15 print(settings.DATABASES)
输出
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj/crm$ python3 views.py ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'os', 'sys'] file views.py /mnt/模块02/常用模块/my_proj in proj/settings.py {'host': 'localhost'}
在proj/settings.py写上 import urls:
1 DATABASES = { 2 'host': 'localhost' 3 } 4 5 import urls 6 7 print('in proj/settings.py')
执行views.py
ModuleNotFoundError: No module named 'urls'
因为现在程序入口是views.py,在settings.py中导入 import urls 相当于在crm目录中找urls.py,必然找不到
需要修改导入方法如下:
1 DATABASES = { 2 'host': 'localhost' 3 } 4 5 from proj import urls 6 7 print('in proj/settings.py')
再次执行views.py,成功
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj/crm$ python3 views.py ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'os', 'sys'] file views.py /mnt/模块02/常用模块/my_proj in proj/settings.py {'host': 'localhost'}
绝对导入 & 相对导入
views.py 中代码
1 from ..proj import settings 2 3 def sayhi(): 4 print('hello world!') 5 6 print(settings.DATABASES)
执行,报错
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj/crm$ python3 views.py Traceback (most recent call last): File "views.py", line 4, in <module> from ..proj import settings ValueError: attempted relative import beyond top-level package
报错原因:在涉及到相对导入时,package所对应的文件夹必须正确的被python解释器视作package,而不是普通文件夹。否则,由于不被视作package,无法利用package之间的嵌套关系实现python中包的相对导入。
文件夹被python解释器视作package需要满足两个条件:
1、文件夹中必须有__init__.py 文件,该文件可以为空,但必须存在
2、不能作为顶层模块来执行该文件夹中的py 文件(即不能作为主函数的入口)
所以,解决办法是:通过上一级的manage.py 调用views.py.......结果依然报错
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ python3 manage.py Traceback (most recent call last): File "manage.py", line 4, in <module> from crm import views File "/mnt/模块02/常用模块/my_proj/crm/views.py", line 4, in <module> from ..proj import settings ValueError: attempted relative import beyond top-level package
把 from ..proj import settings 改成 from . import models 后执行成功
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/my_proj$ python3 manage.py
hello world!
from ..proj import settings 会报错的原因是,这句代码会把manage.py所在的这一层视作package,但实际上它不是,因为package不能是顶层入口代码,若想不出错,只能把manage.py 往上移一层
目录结构:
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/package$ tree . ├── __init__.py ├── manage.py └── my_proj ├── crm │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── models.py │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ └── views.cpython-36.pyc │ ├── tests.py │ └── views.py ├── __init__.py ├── proj │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ └── settings.cpython-36.pyc │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── __pycache__ └── __init__.cpython-36.pyc 6 directories, 18 files
执行manage.py,成功
wxg@wxg-Lenovo-B4400:/mnt/模块02/常用模块/package$ python3 manage.py in proj/settings.py hello world!