原文引至:前端小吉米
对于python中的模块和包, 我简直就想说, js nmlgb 就是一个 trash... 在前端写js根本就没有什么模块和包, 所有都是全局... 真lj... css
畅快了. 写了这么久的js, 连内部的模块的包都搞的这么复杂... 艹...
在python中, 已经定义好了完美的模块和包的引用机制.
咱们先来看看Modulehtml
在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.
好比, 重命名, 指定导入, 全导入
这个算是一个py Module的一个附加值吧.
具体用法很简单.
import sam as sb sb.add(1,2)
就酱, 实际上,就是使用as
将模块的名字换一个. 而且, 换了以后sam, 也就不存在了.
直接看demo吧:
//直接导入 add方法 from sam import add // 也能够导入多个 from sam import add,minus
这样导入的结果也是, 不能使用sam.
若是你想, 将module里面全部的方法都导入的话, 直接使用*
便可
from sam import *
不过, 真强烈不建议这么作. 由于, 并无什么卵用, 而且, 万一出现什么bug, 都不知道这个方法哪来的.
在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__: 模块真实的文件路径, 若是你想查看源码的时候就很重要了.
放图:
说完了,py中的Module, 接着就是最让你66的包. Module只是帮助咱们完成了一个组件的一些小功能, 可是若是咱们想要写一个能够调用的总体组件的话, 那么一个single Module显然是不够了. 因此,py 推出了package 来帮助咱们完成这个巨大的工程(project). 咱们能够经过个文件,调用,该组件下全部的方法. 好比,咱们须要写一个html的评论框, 那么里面确定会设计, HTML,css,js样式设计, 接收评论,发布评论等不少功能. 在包里面, 咱们就能够把这些小功能进行拆分,达到复用的效果.
先看张图:
这实际上, 就是咱们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