Python 中的模块和包

原文引至:前端小吉米
对于python中的模块和包, 我简直就想说, js nmlgb 就是一个 trash... 在前端写js根本就没有什么模块和包, 所有都是全局... 真lj... css

畅快了. 写了这么久的js, 连内部的模块的包都搞的这么复杂... 艹...
在python中, 已经定义好了完美的模块和包的引用机制.
咱们先来看看Modulehtml

Module

在python中, 模块实际上,就至关于与业务逻辑解耦的可重用的一些函数方法. 因此, 咱们能够预先定义一个模块:前端

// 命令为sam.py
def add(a,b):
    return a+b

以后在同目录中,打开一个 Terminator.
接着输入:node

>>> import sam
>>> sam.add(1,2)
//结果为:
3

实际上, 这就是一个简单的模块. 但,当咱们导入的时候, 会在Module的目录中生成一个.pyc文件, 该其实就是用来对Module进行缓存,并编译为Binary 文件, 以便py之后再次引入.
如今, 咱们已经学会如何写入Module,引入Module. 这里,咱们须要更进一步去探索, python是如何进行Module Path的搜索的.python

模块路径搜索

在nodeJS中, 他的搜索方式是, 先看内部定义的Module 有没有. 没有的话,则会开始寻找每一层的node_modules. 而后在里面搜索你的文件.js
那么在py中,他是怎样一个过程呢?
py将搜索路径,放在了sys.path中.咱们能够查看一下. sys.path里面的内容.编程

import sys
sys.path

而后就会出现, 一些路径,好比这个:缓存

['',
'C:\\Python33\\Lib\\lib-dynload',
'C:\\Windows\\system32\\python33.zip',
'C:\\Python33\\DLLs',
'C:\\Python33\\lib',
'C:\\Python33\\plat-darwin',
'C:\\Python33\\lib\\site-packages']

能够看到, 第一个为空, 他实际表明的就是current directory.
具体的顺序是:app

  • 当前目录编程语言

  • sys.path定义的相关目录ide

  • 安装依赖的目录

因此, 若是你想自定义本身的Module 直接添加在sys.path里面便可.
那应该怎样进行添加呢?
实际上, 这就是查找关于sys.path的方法了. 还记得help()吗?
查找后,咱们基本上都会明白了. md, 这不就是list吗?
那剩下的不就是调用,list的方法进行添加和删除吗?
通常而言,python的工做目录是放在对应的pythonLib文件夹内.这里,我将我经常使用的py 模块路径添加进去

sys.path.append('/Users/jimmy_thr/Documents/pythonLib')

以后, 我只要将我写好的Module 放在指定的文件内便可.

模块进阶

上面, 咱们只是学会使用基本的Module 导入, 实际上,py提供了 更加丰富的Module statement.
好比, 重命名, 指定导入, 全导入

Module rename

这个算是一个py Module的一个附加值吧.
具体用法很简单.

import sam as sb
sb.add(1,2)

就酱, 实际上,就是使用as将模块的名字换一个. 而且, 换了以后sam, 也就不存在了.

Specific Module

直接看demo吧:

//直接导入 add方法
from sam import add
// 也能够导入多个
from sam import add,minus

这样导入的结果也是, 不能使用sam.
若是你想, 将module里面全部的方法都导入的话, 直接使用* 便可

from sam import *

不过, 真强烈不建议这么作. 由于, 并无什么卵用, 而且, 万一出现什么bug, 都不知道这个方法哪来的.

Module complement

在nodeJS中, 他的模块引用是值引用类型, 即就是, 一次引用以后, 就会放在缓存里面, 之后若是在引用的话, 会直接从缓存里面取了.
看一个demo:

def add(a,b):
    return a+b
print(add(1,2))
//接着,我屡次引用
>>> import sam
3
>>> import sam

只会出现一次, 说明, sam Module 只能导入一次. 其他的就 nonesense. 可是,若是你的模块是内部循环型的, 那这样不就go die了吗?
hehe ~ py 早教看到这一点了, 在内置的imp中提供了reload方法, 来帮助咱们实现, 模块的引用更新

>>> import imp
>>> imp.reload(sam)
3

最后在补充一个dir(module)方法. 他的做用,就是用来查看指定Module当中的全局变量和函数名.

>>> dir(sam)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'add']

其他的用underscore来链接的, 是py中 module的一部分. 比较重要的看一下__name__便可. 他是用来表示,你当前所在的程序是模块,仍是主程序.

  • 若是你是主程序则 __name__ 为 main

  • 若是为模块则 __name__ 为 你的模块名

另外,若是你忽略参数, 直接使用dir()的话,就是用来查看当前 全局中的变量和函数名.

>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '__warningregistry__', 'get', 'imp', 'sam', 'set']

但,若是你导入一个内置模块的话, 好比: copy

>>> import copy
>>> dir(copy)
['Error', 'PyStringMap', '_EmptyClass', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', ...]

仔细观察, 里面的内置属性, 会看到多出一个叫__all__的属性. 这其实和下面所说的包有一些关系. 实际上, __all__ 的做用, 是提供公共接口的, 但实际上, 当咱们导入方法的时候, 每每会所有倒入.好比这样.

import copy

那么此时, __all__ 对于这种方法是没有任何做用, 该语句就是用来导入copy下全部的全局变量.
如今, 假设 当前模块sam.py下有2个方法,add,minus.
我将__all__ 设置为

__all__ = ['add']

咱们来试验一下二者的区别:

//首先导入:
>>> import sam
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'sam']
>>> dir(sam)
['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'add', 'minus']

能够看到,有了sam这个模块名. 而且, 查看sam中,会看到有add和minus方法.
而后,咱们换一种方式导入:

>>> from sam import *
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'add']

咱们会发现, minus不见了.
因此, 这里咱们就能够搞懂了__all__ 究竟是用来作什么的.

  • __all__: 用来设置模块的公共接口. 而且只针对于 from module import * 的语句

最后在说一下,其中的另外两个默认属性 __doc__,__file__

  • __doc__: 实际上,就是咱们使用help()函数查看的内容. 内容具体就是咱们写在模块开头或者函数开头的注释

  • __file__: 模块真实的文件路径, 若是你想查看源码的时候就很重要了.

放图:
python Module

Package

说完了,py中的Module, 接着就是最让你66的包. Module只是帮助咱们完成了一个组件的一些小功能, 可是若是咱们想要写一个能够调用的总体组件的话, 那么一个single Module显然是不够了. 因此,py 推出了package 来帮助咱们完成这个巨大的工程(project). 咱们能够经过个文件,调用,该组件下全部的方法. 好比,咱们须要写一个html的评论框, 那么里面确定会设计, HTML,css,js样式设计, 接收评论,发布评论等不少功能. 在包里面, 咱们就能够把这些小功能进行拆分,达到复用的效果.
先看张图:
python 包
这实际上, 就是咱们python包的简单格式, 在每一个文件根目录都会存在__init.py__ 文件. 他的做用实际上,就是用来定义, 引用包时, 暴露的相关接口. 而关键的关键, 就是上面提到的__all__ 内置的默认关键字. how to use?
请, stackoverflow.
__init__.py就是一个导入文件
如今,咱们来写一个简单的包, 以上图为例。
在Game的根目录下, __init__.py内容为:

__all__ = ['Sound','Image','Level']
from Game import Sound,Image,Level

而后,咱们就能够直接应用Game 包了.

>>>import Game
>>>Game.Sound.xxx

这里,须要说明的是, 关于包的导入, 其实用不用all不是很重要, 换句话说, 应该是不推荐, 由于前文咱们已经了解到, __all__ 生效的机制是 使用 from xx import * 这样的语句. 而这样作的实际效果是, 彻底破坏了python的namespace机制, 也是编程语言中最重要的一个. 因此, 给的建议就是, 尽可能放弃all的使用, 直接使用 import 来判断你须要导出那些公共的接口便可.
引用一段话:

Leaving an __init__.py file empty is considered normal and even a good practice, if the package’s modules and sub-packages do not need to share any code.

出自: python guider

相关文章
相关标签/搜索