今天买了一本关于模块的书,说实话,模块真的太多了,小编许多也不知道,要是把模块全讲完,可能得出本书了,所以小编在自己有限的能力范围内在这里浅析一下自己的见解,同时讲讲几个常用的模块。

  这里是2018.3.6对此文章更新,为了让此文章更详细,此前文章标题为python 浅析模块的导入和调用,写于此示己。

一,模块

什么是模块?

  在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里面,代码会越来越长,越来越不容易维护。

  为了编写可以维护的代码,我们把很多函数分组,分别放到不同额文件,这样,每个文件包含的代码就相对比较少,很多编程语言都采用这种组织代码的方式。在python中,一个.py文件就称之为一个模块。

使用模块有什么好处?

  1,最大的好处就是大大的提高了代码的可维护性,其次,编写代码不必从零开始,当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括python内置的模块和来自第三方的模块。

  2,使用模块还可以避免函数名和变量名之间的冲突,每个模块有独立的命名空间,因此相同名字的函数和变量完全可以分别存在不同的模块中,所以,我们自己编写模块时候,不必考虑名字会和其他模块冲突。

模块分类

  模块分为三种:

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

下面介绍一下如何导入模块:

模块调用的方法
import module from module import xx from module.xx.xx import xx as rename from module.xx.xx import *

  注意:模块一旦被调用,即相当于执行了另一个py文件里面的代码

在Python 中用关键字import来导入某个模块:

import  modname

比如要导入模块numpy,就可以在文件最开始的地方用import numpy 来引入。在调用numpy模块的函数时,必须这样引入:

模块名.函数名(比如:import numpy        numpy.arange(5))

与第一种方法的区别是:funcname被直接导入到本地名字空间取了,所以他可以直接使用,而不需要加上模块名的限定 * 表示,该模块的所有公共对象(public objects)都被导入到当前的名称空间,也就是任何只要不是以    "_"   开始的东西都会被导入。

为什么必须加上模块名这样调用呢?因为可能存在这样一种情况,在多个模块下含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用那个函数,所以如果像上述这种情况引入模块的时候,调用函数必须加上模块名。

有时候我们只需要引入模块中的某个函数,只需要引入该函数即可,此时通过下面语句实现:

form modname   import    funcname

(form  modname  import    fa,fb,fc

form modname  import  *      但是这个得谨慎使用         )

当然可以通过通过这种方法不仅可以引入函数,还可以引入常量,通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块,但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。所以有以下建议:

1) 如果你经常访问模块的属性和方法,且不想一遍又一遍的敲入模块名称,使用  form  module import

2) 如果你想要有选择性地导入某些属性和方法,而不想要其他的,使用  form  module import

3)如果模块包含的属性和方法与你的某个模块同名,你必须使用  import module 来避免名字冲突

4)尽量少使用   form  module import  *,因为判定一个特殊的函数或属性是从哪里来的有些困难,并且会造成调试和重构都更困难

还有一种导入模块的方法就是内建函数 _import_ ()

除了前两种使用 import 导入的方法以外,我们还可以使用内建函数来导入 module。两者的区别是: import 后面必须跟的是一个类型(type),而 _import_()的参数是一个字符串,这个字符串可能来自配置文件,也可能是某个表达式计算结果。例如:

mymodule =  _import_ ( 'module_name ' )

一般情况应该使用import , 但有几个例外 
      1)module文档告诉你要用from-import的 
      2)导入一个包组件。需要一个包里面的某个子模块,一般用from A.b import c比import A.b.c 更方便 且不会冒混淆的危险.

你也许会想到,如果不同的人编写的模块名称相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)

包的引入解决了模块名冲突,就是只要顶层的包名字不与别人冲突,那么模块都不会与别人冲突。

注意:每个包目录下都会有一个  _init_.py  的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。 _init_.py 可以是空文件,也可以是有Python代码,因为  _init_.py  本身就是一个模块,而它的模块名就是   mycompany

模块查找路径

  初学者会发现,自己写的模块只能在当前路径下的程序里面才能导入,换一个目录再导入自己的模块就报错了,,这是为什么呢?

  答案就是:这与导入路径有关

import sys

print(sys.path)

  输出结果入下(这是windows下的目录):

['D:\\pycode\\模块学习', 'D:\\pycode', 'D:\\python3\\python36.zip',
'D:\\python3\\DLLs', 'D:\\python3\\lib',
'D:\\python3',
'D:\\python3\\lib\\site-packages',
'D:\\python3\\lib\\site-packages\\win32',
'D:\\python3\\lib\\site-packages\\win32\\lib',
'D:\\python3\\lib\\site-packages\\Pythonwin']

  所以python解释器就会按照列表顺序去依次到每隔目录下去匹配你要导入的模块名,只要在一个目录下匹配到了该模块名,就立马不继续往下找,如果找完了依旧没有找到,那么就会报错。

  (注意,可能是linux下,列表的第一个元素为空,即代表当前目录,所以你自己定义的模块在当前目录会被优先导入)

开源模块安装,使用

  

https://pypi.python.org/pypi

  是python的开源模块库,截止2018年一月 ,已经收录了119870个来自全世界python开发者贡献的模块,几乎涵盖了你想用python做的任何事情。 事实上每个python开发者,只要注册一个账号就可以往这个平台上传你自己的模块,这样全世界的开发者都可以容易的下载并使用你的模块。

  那么如何从这个平台上下载代码?

1,直接在上面这个页面点download,下载后,解压并进入目录,执行一下命令完成安装。

编译源码    python setup.py build

安装源码    python setup.py install

  

2,直接pip安装

pip install module #module 是模块名

  软件一般会被自动安装在你的python安装目录的这个子目录里面

/your_python_install_path/3.6/lib/python3.6/site-packages

  建议:pip命令默认会连接在国外的python官方服务器下载,速度比较慢,你还可以使用国内的豆瓣源,数据会定期同步国外官网,速度快好多

sudo pip install -i http://pypi.douban.com/simple/ module --trusted-host pypi.douban.com   

#module是模块名

  

模块的调用

  首先举个例子:

def  main()
pass mian()

  如果直接在模块里面调用这个函数,那么,假设其他模块需要import当前模块,那么这个程序也会执行,但是其他模块想要的只是import而已,所以显然,这样是不可取的,我们需要将这种调用方式改成下面这种。

  

if __name__  == '__main__':
main()

  这样的话,只有当前模块被执行的时候,这个函数才被调用,程序才执行。

二,包(package)

包的导入

  当你的模块文件越来越多的时候,就需要对模块文件进行划分,比如把负责跟数据库交互的都放在一个文件夹,把页面交互相关的放在一个文件夹。

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

比如上面这样的,一个文件夹管理多个模块文件,这个文件夹就称为包

那么不同的包之间如何相互导入呢?

  包就是文件夹,但该文件夹下必须存在 __init__.py 文件, 该文件的内容可以为空。__int__.py用于标识当前文件夹是一个包

from crm import views

views.sayhi()

其中crm/views.py内容如下:

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

 

跨模块导入包

目录结构如下:

├── __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模块?

from proj import views

结果:
Traceback (most recent call last):
File "D:/crm/views.py", line 1, in <module>
from proj import views
ModuleNotFoundError: No module named 'proj'

  为什么直接导入会报错呢?

是因为路径找不到,proj/settings.py 相当于是crm/views.py的父亲(crm)的兄弟(proj)的儿子(settings.py),settings.py算是views.py的表弟啦,在views.py里只能导入同级别兄弟模块代码,或者子级别包里的模块,根本不知道表弟表哥的存在。这可怎么办呢?

  答案是添加环境变量,把父亲级的路径添加到sys.path中,就可以了,这样导入 就相当于从父亲级开始找模块了。

crm/views.py中添加环境变量

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

  注意:此时在proj/settings.py写上import urls会有问题么?

  答案是肯定会有问题的,因为现在的程序入口是views.py , 你在settings.py导入import urls,其实相当于在crm目录找urls.py,而不是proj目录,若想正常导入,要改成如下:

DATABASES= {
'host':'localhost'
} from proj import urls #proj这一层目录已经添加到sys.path里,可以直接找到
print('in proj/settings.py')

  这里就涉及了绝对导入和相对导入了,下面直接说一下

绝对导入和相对导入

  在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)

  执行结果报错了(linux)

Traceback (most recent call last):
File "my_proj/crm/views.py", line 4, in <module>
from ..proj import settings
SystemError: Parent module '' not loaded, cannot perform relative import

  或者报错如下(windows):

Traceback (most recent call last):
D:/模块学习
File "D:/crm/views.py", line 9, in <module>
from .. import settings
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 .. import models会报错的原因是,这句代码会把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支持相对导入,但对模块间的路径关系要求比较严格,处理不当就容易出错,so并不建议在项目里经常使用。

python 浅析模块,包及其相关用法的更多相关文章

  1. python之模块pprint之常见用法

    # -*- coding: cp936 -*- #python 27 #xiaodeng #python之模块pprint之常见用法 import pprint data = [(1,{'a':'A' ...

  2. python之模块poplib之常见用法

    # -*- coding: cp936 -*- #python 27 #xiaodeng #python之模块poplib之常见用法 ''' 所以,收取邮件分两步: 第一步:用poplib把邮件的原始 ...

  3. 【python库模块】Python subprocess模块功能与常见用法实例详解

    前言 这篇文章主要介绍了Python subprocess模块功能与常见用法,结合实例形式详细分析了subprocess模块功能.常用函数相关使用技巧. 参考 1. Python subprocess ...

  4. python中模块包的离线下载教程

    1.简介 当我们进行Python项目的迁移时(例如迁移到另外一台服务器上),如果该服务器要求离线安装, 往往需要我们将项目中的所需模块包进行离线操作. 2.教程 2.1 首先安装pip2pi模块,它可 ...

  5. Python安装模块包

    可以利用pycharm安装模块包 使用这种方法安装时,可能会报下面类型的异常 AttributeError: module 'pip' has no attribute 'main' 出现这这样的异常 ...

  6. python浅析模块,包及其相关用法

    一,模块 什么是模块? 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里面,代码会越来越长,越来越不容易维护. 为了编写可以维护的代码,我们把很多函数分组,分别放到不同额文件,这样,每个文 ...

  7. python 浅析模块

    今天买了一本关于模块的书,说实话,模块真的太多了,小编许多也不知道,要是把模块全讲完,可能得出本书了,所以小编在自己有限的能力范围内在这里浅析一下自己的见解,同时讲讲几个常用的模块. 首先说一下对模块 ...

  8. python基础--模块&包

    一.模块 1.模块是程序 任何Python程序都可以作为模块导入. 程序的保存也很重要,如果想把程序保存在C:\python (Windows)目录下,需要告诉解释器在哪里寻找模块了. >> ...

  9. Python Day5 模块 包

    一:区分Python文件的2种用途 1个Python文件的2种用途 1.1 当作脚本执行:        if __name__ == '__main__': 1.2 当作模块导入使用     if ...

随机推荐

  1. RNA-seq差异表达基因分析之TopHat篇

    RNA-seq差异表达基因分析之TopHat篇 发表于2012 年 10 月 23 日 TopHat是基于Bowtie的将RNA-Seq数据mapping到参考基因组上,从而鉴定可变剪切(exon-e ...

  2. 微信浏览器Ajax请求返回值走error

    微信浏览器Ajax post请求是返回值走的error $.ajax({ type: "POST", url: "https://XXXX", cache: f ...

  3. 学以致用二十三-----shell脚本里调用脚本

    当前脚本可以调用其他目录下的脚本,并可以直接使用其他脚本里的函数. 首先查看脚本目录 执行net_set.sh,同时执行colos.sh 并可直接使用 color.sh中的函数 net_set.sh ...

  4. Python开发——7.迭代器、生成器和装饰器

    一.迭代器 1.迭代器协议 (1)迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么引起一个StopIteration移除异常以中止迭代. (2)可迭代对象:实现了迭 ...

  5. Oracle OMF管理数据文件

    1.什么是OMF? Oracle managed file的缩写,简单的理解,就是oracle自己管理自己的文件,可以是dbf,redolog 等等,具体可以参考官方文档Adiministrator中 ...

  6. Microsoft在8月7号发布的帮助文档更新中,HelpLibrary2安装Cab文档包出现签名问题

    在VS 2017 8月2号发布15.7.6版本后,在8月7号推送了helpview程序中的绝大部分更新文档,在本次推送中多数Cab文件出现了无法进行安装的签名问题, 不论是单个下载,还是删除本地所有已 ...

  7. 网易易盾最新一代Java2c加固究竟有什么厉害之处?

    导语:几个月前,网易易盾正式推出Java2c加固.它以独有的"静态保护"技术,使得应用程序中的代码出现"下沉",达到不可逆的效果,兼顾"冷热启动时间& ...

  8. InnoDB体系架构(三)Checkpoint技术

    Checkpoint技术 前篇 InnoDB体系架构(二)内存 从缓冲池.缓冲池的管理.重做日志缓冲.额外内存缓冲这四个点介绍了InnoDB存储引擎的内存结构,而在将缓冲池的数据刷新到磁盘的过程中使用 ...

  9. react写一个todo

    概述 最近学习redux,打算先复习一下react,所以用react写了一个todo.记录下来,供以后开发时参考,相信对其他人也有用. 代码 代码请见我的github 组织架构如下图:

  10. jQuery应用实例5:表单验证

    1.validation插件的使用: 入门案例: <html> <head> <meta charset="UTF-8"> <title& ...