189 8069 5689

模块、包

1.模块

1.1模块定义

在Python中,一个.py文件就称为一个模块。

让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:申请域名网站空间、营销软件、网站建设、酒泉网站维护、网站推广。

1.2使用模块的好处

最大的好处是提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完成,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和第三方的模块。
使用模块可以避免函数名和变量名的冲突。每个模块有独立的命名空间,因此相同名字的函数和变量完全可以分别存在不同的模块中,所以,我们在编写模块时,不必考虑名字会和其他模块冲突。

1.3模块分类

模块分为三种:
内置标准模块(又称标准库)执行help('modules')查看所有python自带模块列表,如os,sys等等
第三方开源模块,可通过pip install模块名 联网安装
自定义模块

1.4模块调用

import module
from module import xx
from module.xx.xx import xx as rename  
from module.xx.xx import *
"注意:模块一旦被调用,即相当于执行了另外一个py文件里的代码"

1.5自定义模块

创建一个.py文件,就可以称为模块,就可以在另外一个程序中导入

1.6模块查找路径

我们会发现,自己写的模块只能在当前路径下的程序中才能导入,换一个目录再导入自己的模块就报错说找不到了,这主要是与导入路径有关

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
import sys
print(sys.path)

E:\PythonProject\python-test\venvP3\Scripts\python.exe E:/PythonProject/python-test/BasicGrammer/test.py
['E:\\PythonProject\\python-test\\BasicGrammer', 'E:\\PythonProject\\python-test\\BasicGrammer', 'D:\\software\\pycharm\\install\\PyCharm 2019.1.1\\helpers\\pycharm_display', 'E:\\PythonProject\\python-test\\venvP3\\Scripts\\python36.zip', 'D:\\software2\\Python3\\install\\DLLs', 'D:\\software2\\Python3\\install\\lib', 'D:\\software2\\Python3\\install', 'E:\\PythonProject\\python-test\\venvP3', 'E:\\PythonProject\\python-test\\venvP3\\lib\\site-packages', 'E:\\PythonProject\\python-test\\venvP3\\lib\\site-packages\\setuptools-40.8.0-py3.6.egg', 'E:\\PythonProject\\python-test\\venvP3\\lib\\site-packages\\pip-19.0.3-py3.6.egg', 'D:\\software\\pycharm\\install\\PyCharm 2019.1.1\\helpers\\pycharm_matplotlib_backend']

Process finished with exit code 0

前两个是当前.py程序所在的路径,python解释器会按照上面列表中的路径依次去寻找要导入的.py文件,找到了就立刻导入,不再继续往后找。
注意:可能有的人第一个元素为空(""),是代表当前目录,所以自己定义的模块在当前目录会被优先导入。

1.7开源模块安装、使用

https://pypi.org/ 是开源模块库

模块、包

安装方式1:
直接下载.tar.gz,解压后进入目录,执行下面命令完成安装

编译源码:python3 setup.py build
安装源码:python3 setup.py install

安装方式2:

pip3 install paramiko

pip会自动到开源模块库中下载安装包并安装
软件一般会自动安装到python的安装目录下的site-packages中
/your_python_install_path/3.6/lib/python3.6/site-packages
pip默认会连接国外的Python官网下载,下载速度比较慢,可以使用国内的豆瓣元,会同步国外的官网,速度快很多

sudo pip install -i http://pypi.douban.com/simple/ alex_sayhi --trusted-host pypi.douban.com   #alex_sayhi是模块名

1.8模块的使用

下载后,直接导入使用就可以

#coding:utf-8

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('192.168.1.108', 22, 'alex', '123')

stdin, stdout, stderr = ssh.exec_command('df')
print(stdout.read())
ssh.close();

执行命令 - 通过用户名和密码连接服务器

2.包

.
└── my_proj
    ├── crm #代码目录
    │   ├── admin.py
    │   ├── apps.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    ├── manage.py
    └── my_proj #配置文件目录
        ├── settings.py
        ├── urls.py
        └── wsgi.py

像上面那样,一个文件夹管理多个模块文件,这个文件夹就被称为包
不同包之间的模块导入

"crm/views.py内容"
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
def sayhi():
    print("hello")

"manage.py中内容"
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
from crm import views
views.sayhi()

>python2 E:/PythonProject/python-test/BasicGrammer/mypro/manage.py
Traceback (most recent call last):
  File "E:/PythonProject/python-test/BasicGrammer/mypro/manage.py", line 4, in 
    from crm import views
ImportError: No module named crm

"python2中,会报模块找不到,为什么?"
包是文件夹,但该文件夹下必须存在__init__.py文件,改文件的内容可以为空。__init__.py用于标识当前文件夹就是一个包。
在crm目录下创建一个空文件__init__.py,在执行一次就可以了
(venvP3) E:\PythonProject\python-test\BasicGrammer\mypro\crm>dir
 E:\PythonProject\python-test\BasicGrammer\mypro\crm 的目录

2019/05/05 周日  15:37                95 views.py
2019/05/05 周日  15:42               314 views.pyc
2019/05/05 周日  15:42                61 __init__.py

>python2 E:/PythonProject/python-test/BasicGrammer/mypro/manage.py
hello

>python3 E:/PythonProject/python-test/BasicGrammer/mypro/manage.py
hello

(venvP3) E:\PythonProject\python-test\BasicGrammer>
"注意:在Python3中,即使目录下没有__Init__.py文件也能创建成功,应该是解释器优化所致,但创建包最好还是加上__init__.py文件"
实际使用中,我们会使用pycharm创建一个package时,会自动创建__init__.py,不需要我们手动创建

3.跨模块导入

目录结构如下
.
├── __init__.py
├── crm
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   ├── views.py  
├── manage.py   
└── proj
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

根据上面的结构,如何实现在crm/views.py里导入proj/settings.py模块?
直接导入的话,会报错,说找到不模块
因为当前入口是views.py,那么当前sys.path中的当前路径是crm,在crm下没有proj

$ python3 views.py
Traceback (most recent call last):
  File "views.py", line 2, in 
    from proj import settings
ModuleNotFoundError: No module named 'proj'

那要怎么办呢,可以自己设置环境变量,把crm的父级路径添加到sys.path中,就可以了,这样导入就相当于从父级开始找模块了。

crm/views.py中添加环境变量
import sys ,os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #__file__的是打印当前被执行的模块.py文件相对路径,注意是相对路径
print(BASE_DIR)

sys.path.append(BASE_DIR)  

from proj import settings

def sayhi():
    print('hello world!')

print(settings.DATABASES)

$ python3 views.py
/Users/alex/Documents/work/PyProjects/luffy_课件/21天入门/chapter4-常用模块/packages/my_proj
---my proj init---  #proj/__init__.py输出
in proj/settings.py #proj/settings.py输出
{'host': 'localhost'}

那此时依旧执行views.py,在proj/settings.py写上import urls会有问题么?

DATABASES= {
    'host':'localhost'
}

import urls  #这行刚加的 
print('in proj/settings.py')

结果报错了
ModuleNotFoundError: No module named 'urls'

因为程序入口是views.py,刚刚加入环境变量的是crm和proj的父级目录,当前目录又是crm目录,所以在这两个路径下都没有urls.py需要改成下面这样

DATABASES= {
    'host':'localhost'
}

from proj import urls  #proj的父级目录已经添加到sys.path里,可以直接在proj中找到urls.py
print('in proj/settings.py')

4.绝对导入和相对导入

在linux里可以通过cd ..回到上一层目录 ,cd ../.. 往上回2层,这个..就是指相对路径,在python里,导入也可以通过..
例如:

.
├── __init__.py
├── crm
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   ├── views.py  #from ..proj import settings 
├── manage.py   
└── proj
    ├── __init__.py
    ├── settings.py #from .import urls  
    ├── urls.py
    └── wsgi.py

views.py中代码

from ..proj import settings
def sayhi():
    print('hello world!')

print(settings.DATABASES)
执行结果报错了
Traceback (most recent call last):
File "my_proj/crm/views.py", line 4, in 
 from ..proj import settings
SystemError: Parent module '' not loaded, cannot perform relative import
或有人看到下面的错误
ValueError: attempted relative import beyond top-level package
其实这两个错误的原因归根结底是一样的:
在涉及到相对导入时,package所对应的文件夹必须正确的被python解释器视作package,而不是普通文件夹。否则由于不被视作package,无法利用package之间的嵌套关系实现python中包的相对导入。
文件夹被python解释器视作package需要满足两个条件:
1.文件夹中必须有__init__.py文件,该文件可以为空,但必须存在该文件。
2.不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口)。
所以这个问题的解决办法就是,既然你在views.py里执行了相对导入,那就不要把views.py当作入口程序,可以通过上一级的manage.py调用views.py
.
├── __init__.py
├── crm
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   ├── views.py  #from ..proj import settings 
├── manage.py  #from crm import views 
└── proj
    ├── __init__.py
    ├── settings.py #from .import urls  
    ├── urls.py
    └── wsgi.py
事实证明还是报错
ValueError: attempted relative import beyond top-level package
但把from ..proj import settings 改成from . import models 后却执行成功了,为什么呢?

from ..proj import settings 会报错的原因是,这句代码会把manage.py所在的这一层视作package,但实际上它不是,因为package不能是顶层入口代码,若想不出错,只能把manage.py往上再移一层。

正确的代码目录结构如下
    packages/
    ├── __init__.py
    ├── manage.py #from my_proj.crm  import views
    └── my_proj
        ├── crm
        │   ├── admin.py
        │   ├── apps.py
        │   ├── models.py
        │   ├── tests.py
        │   ├── views.py  #from . import models;  from ..proj import settings 
        └── proj
            ├── __init__.py
            ├── settings.py
            ├── urls.py
            └── wsgi.py
再执行manage.py就不会报错了。
"注:虽然python支持相对导入,但对模块间的路径关系要求比较严格,处理不当就容易出错,所以并不建议在项目里经常使用。"

文章题目:模块、包
URL地址:http://cdxtjz.com/article/jsgsos.html

其他资讯