[Python] 06 - Modules --> Packages
故事背景
阶级关系
1. Programs are composed of modules.
2. Modules contain statements.
3. Statements contain expressions.
4. Expressions create and process objects.
Package 用来管理 modules。
教学大纲
Modules 模块
基础概念
一、导入module的过程
导入文件时,没有任何缩进的代码 都会被执行一遍。
1. Find the module’s file.
2. Compile it to byte code (if needed).【Python解释器已经把编译的字节码放在__pycache__
文件夹中,*.pyc 文件】
3. Run the module’s code to build the objects it defines.
二、寻址策略
按照如下方式查找导入模块:
1. The home directory of the program # 项目路径
2. PYTHONPATH directories (if set) # 设置路径
3. Standard library directories # 系统路径
4. The contents of any .pth files (if present)
5. The site-packages home of third-party extensions
查看 PYTHONPATH
>>> import sys >>> sys.path ['', '/usr/local/anaconda3/lib/python35.zip', '/usr/local/anaconda3/lib/python3.5', '/usr/local/anaconda3/lib/python3.5/plat-linux', '/usr/local/anaconda3/lib/python3.5/lib-dynload', '/home/unsw/.local/lib/python3.5/site-packages', '/usr/local/anaconda3/lib/python3.5/site-packages', '/usr/local/anaconda3/lib/python3.5/site-packages/Mako-1.0.7-py3.5.egg', '/usr/local/anaconda3/lib/python3.5/site-packages/Sphinx-1.5.1-py3.5.egg', '/usr/local/anaconda3/lib/python3.5/site-packages/textteaser-0.3-py3.5.egg', '/usr/local/anaconda3/lib/python3.5/site-packages/requests-1.2.3-py3.5.egg', '/usr/local/anaconda3/lib/python3.5/site-packages/sputnik-0.9.3-py3.5.egg']
设置 PYTHONPATH
>>> import sys >>> sys.path.append("C:\Python34\PCI_Code\chapter2") >>> from recommendations import critics >>>
C:\Python34\PCI_Code\chapter2>python >>> from recommendations import * >>>
"Imports" 使用法则
from <范围> import <功能> as <别名>
导入所有,还是导入一部分?
一、“模块” 的属性查看
例如,尝试查看下np的属性。
>>> import numpy as np >>> list(np.__dict__.keys()) ['add_docstring', 'longlong', 'geomspace', '__all__', 'moveaxis', 'character', 'unicode', 'fromstring', 'asarray_chkfinite', 'void', 'find_common_type', 'triu_indices', '_mat', 'uint64', 'get_printoptions', 'WRAP', 'recfromcsv', '_globals', 'PackageLoader', 'FPE_UNDERFLOW', 'require', 'isneginf', 'uintc', 'fill_diagonal', 'select', 'inexact', 'issubsctype', 'trunc', 'insert', 'CLIP', 'savetxt', 'int_asbuffer', 'log1p', 'base_repr', 'stack', 'in1d', 'Infinity', 'int32', 'ERR_IGNORE', 'str_', 'iscomplex', 'diag_indices', 'sinc', 'pv', 'info', 'float64', 'fv', 'timedelta64', 'floor', 'concatenate', 'einsum_path', 'ogrid', 'NaN', '__cached__', 'tile', 'testing', 'poly1d', 'ScalarType', 'numarray', 'atleast_1d', 'i0', 'object0', 'arccosh', 'isscalar', 'polysub', 'isclose', 'PZERO', 'tan', 's_', 'clongfloat', 'bitwise_not', 'ushort', 'rint', 'prod', 'inf', 'uint0', 'inner', 'sort_complex', 'amax', 'int16', 'fastCopyAndTranspose', 'real_if_close', 'not_equal', 'lib', 'SHIFT_INVALID', 'median', 'packbits', 'max', 'longfloat', 'bytes0', 'linalg', 'dot', 'float128', 'unicode_', 'interp', 'absolute', 'result_type', 'FPE_INVALID', 'mean', 'frombuffer', 'true_divide', 'nancumprod', 'float_', 'hypot', 'typename', 'percentile', 'savez_compressed', 'put', 'recarray', 'PINF', 'square', 'real', 'unpackbits', 'str0', 'remainder', 'polyadd', 'ones', 'uint32', 'sin', 'maximum', 'matrix', 'nbytes', 'safe_eval', 'datetime_data', 'rank', 'nanargmin', 'RankWarning', 'loads', 'str', 'string_', 'subtract', 'cumprod', 'amin', 'deg2rad', 'e', 'blackman', 'arccos', 'seterr', 'unique', 'sctype2char', 'recfromtxt', 'exp2', 'FLOATING_POINT_SUPPORT', 'deprecate_with_doc', 'sinh', 'bool', 'disp', 'seterrcall', 'finfo', 'repeat', 'add_newdocs', 'equal', 'UFUNC_PYVALS_NAME', 'frompyfunc', 'pmt', 'ravel', 'roots', 'extract', 'isin', 'unwrap', 'tri', 'genfromtxt', 'ix_', 'bitwise_and', 'sctypeDict', 'any', 'complex_', 'nonzero', 'iscomplexobj', 'swapaxes', 'flexible', 'mod', 'ptp', 'nan_to_num', 'sys', 'TooHardError', 'mafromtxt', 'asfortranarray', 'byte_bounds', 'cumsum', '__version__', 'uintp', 'ERR_PRINT', 'nanstd', 'hsplit', 'einsum', 'array_split', 'fabs', 'print_function', 'add_newdoc', 'arctan', 'half', 'ERR_LOG', 'broadcast_to', 'reshape', 'ComplexWarning', 'pkgload', 'MachAr', 'copyto', 'hamming', 'float16', 'polyint', 'issubdtype', 'ascontiguousarray', 'VisibleDeprecationWarning', 'RAISE', 'unravel_index', 'logical_xor', 'complex128', 'ctypeslib', 'tril', 'complexfloating', 'complex64', 'alen', 'ceil', '__name__', 'union1d', 'reciprocal', 'greater', 'zeros_like', 'polyval', 'irr', 'rad2deg', 'busdaycalendar', 'NAN', 'c_', 'bitwise_or', 'record', 'ndfromtxt', '__git_revision__', 'ERR_DEFAULT', 'fft', 'typecodes', 'kron', 'logical_and', 'is_busday', 'show_config', 'pi', 'frexp', 'number', 'rate', 'FPE_OVERFLOW', 'sort', 'where', 'ALLOW_THREADS', 'ipmt', 'modf', 'set_numeric_ops', 'typeNA', 'bitwise_xor', 'MAY_SHARE_BOUNDS', 'NINF', 'generic', 'mask_indices', 'MAXDIMS', 'take', 'intersect1d', 'matmul', 'isnat', 'place', 'searchsorted', 'argwhere', '__builtins__', 'deprecate', 'sctypeNA', 'isrealobj', '_import_tools', 'logspace', 'alltrue', 'array_str', 'test', 'array_equal', 'asscalar', 'obj2sctype', 'nanprod', 'poly', 'empty', 'arange', '__doc__', 'arcsin', 'promote_types', 'ma', 'polyfit', 'partition', 'ubyte', 'busday_count', 'set_printoptions', 'eye', 'longdouble', 'log', 'ModuleDeprecationWarning', 'geterrobj', 'fromiter', 'ppmt', 'block', 'log10', 'conj', 'rec', 'euler_gamma', 'add_newdoc_ufunc', 'sctypes', 'compress', 'ones_like', 'broadcast', 'conjugate', 'rot90', 'logical_not', 'apply_along_axis', 'round', 'vsplit', 'cross', '__file__', 'polymul', 'roll', 'logaddexp', 'sqrt', 'trapz', 'zeros', 'little_endian', 'may_share_memory', 'single', 'abs', 'resize', 'trace', '__loader__', 'fromregex', 'mgrid', 'spacing', 'vander', 'expand_dims', 'min', 'source', 'object', 'sign', 'fromfile', 'atleast_3d', 'get_include', 'tril_indices', '__package__', 'setbufsize', 'isreal', 'shape', 'ndarray', 'nanmax', 'newaxis', 'choose', 'Inf', 'tril_indices_from', 'infty', 'lookfor', 'negative', 'warnings', 'division', 'isfortran', 'log2', 'round_', 'degrees', 'array', 'average', 'split', 'argsort', 'column_stack', 'setxor1d', 'diagflat', 'compat', '_distributor_init', 'gradient', 'multiply', 'signbit', 'polyder', 'isnan', 'arctanh', 'SHIFT_DIVIDEBYZERO', 'UFUNC_BUFSIZE_DEFAULT', 'ediff1d', 'apply_over_axes', 'nanpercentile', 'indices', 'ERR_RAISE', 'digitize', 'datetime64', '__path__', 'float', 'SHIFT_UNDERFLOW', 'minimum', 'memmap', 'npv', 'fmod', 'int8', 'kaiser', 'vdot', 'arctan2', 'typeDict', 'cfloat', 'r_', 'int0', 'bincount', 'nested_iters', 'compare_chararrays', 'uint16', 'flatiter', 'tracemalloc_domain', 'ndindex', 'heaviside', 'convolve', 'flip', 'cov', 'triu_indices_from', 'arcsinh', 'row_stack', 'flatnonzero', 'identity', 'int64', 'bool8', 'dstack', 'cosh', 'meshgrid', 'loadtxt', 'fromfunction', 'lexsort', 'oldnumeric', 'nditer', 'squeeze', 'index_exp', 'floor_divide', 'tensordot', 'absolute_import', 'argpartition', 'geterr', 'Tester', 'invert', 'count_nonzero', 'nan', 'BUFSIZE', 'positive', 'mat', 'transpose', 'intp', 'csingle', 'delete', 'rollaxis', 'MAY_SHARE_EXACT', 'setdiff1d', 'singlecomplex', 'nanvar', 'corrcoef', 'iinfo', 'ERR_CALL', 'integer', 'histogramdd', 'savez', 'clip', 'allclose', 'nanmin', 'emath', 'argmax', 'fmax', 'histogram2d', 'core', 'common_type', 'load', 'piecewise', 'vectorize', 'complex256', 'nancumsum', 'flipud', 'logical_or', 'argmin', 'ldexp', 'signedinteger', 'bmat', 'mintypecode', 'bool_', 'less_equal', 'ERR_WARN', 'char', 'correlate', 'matrixlib', 'math', 'errstate', 'less', 'bytes_', 'asmatrix', 'NZERO', 'SHIFT_OVERFLOW', 'datetime_as_string', 'get_array_wrap', 'array_repr', 'diag', 'issctype', 'isinf', 'ndim', 'ravel_multi_index', 'maximum_sctype', 'triu', 'save', 'asanyarray', 'nansum', 'ufunc', 'hanning', 'expm1', 'imag', 'diagonal', 'ulonglong', '__spec__', 'geterrcall', 'nanargmax', 'full', 'chararray', 'msort', 'trim_zeros', 'random', 'std', 'int', 'FPE_DIVIDEBYZERO', 'cos', 'nanmean', 'min_scalar_type', 'greater_equal', 'True_', 'left_shift', 'linspace', 'set_string_function', 'floating', 'fmin', 'vstack', 'issubclass_', 'fliplr', 'logaddexp2', 'busday_offset', 'right_shift', 'iterable', 'bartlett', 'nanmedian', 'hstack', 'float_power', 'atleast_2d', 'isfinite', '_NoValue', 'full_like', 'short', 'ndenumerate', 'sometrue', 'shares_memory', 'asarray', 'angle', 'product', 'object_', 'cumproduct', 'uint8', 'array2string', 'var', 'dtype', 'diag_indices_from', 'histogram', 'unsignedinteger', 'divmod', 'can_cast', 'long', 'isposinf', 'array_equiv', 'putmask', 'add', 'nper', 'sum', 'polynomial', 'int_', 'complex', 'nextafter', 'polydiv', 'binary_repr', 'clongdouble', 'exp', 'cdouble', 'pad', 'intc', 'size', 'around', 'diff', 'asfarray', 'version', 'fix', 'outer', 'empty_like', 'float32', 'cbrt', 'getbufsize', '__config__', 'append', 'all', 'longcomplex', 'AxisError', 'seterrobj', 'format_parser', 'void0', 'False_', 'double', 'broadcast_arrays', 'who', 'dsplit', 'copy', 'power', 'copysign', 'uint', 'divide', 'cast', 'byte', 'DataSource', 'tanh', 'mirr', 'bench', '__NUMPY_SETUP__', 'radians'] >>>
[小知识] dir()的子集__dict__
Python 下一切皆对象,每个对象都有多个属性(attribute),Python对属性有一套统一的管理方案。与dir()
的区别:
dir() 是一个函数,返回的是list;
__dict__
是一个字典,键为属性名,值为属性值;
dir()用来寻找一个对象的所有属性,包括__dict__
中的属性,__dict__
是dir()的子集;
二、设置“被导入”标记
表示:让自己能用(当然自己能用),也能让其他人导入使用(具有了函数的“被调用”的功能)。
Ref: https://www.cnblogs.com/alan-babyblog/p/5147770.html
自己使用 --> __main__
没必要显示文件名,显示__main__就好啦。
# module.py def main(): print "we are in %s"%__name__
if __name__ == '__main__': # 是作为主程序调用 main()
打印结果:
”we are in __main__“
供他人导入使用 --> file name
显示整体的文件名,module name。
# anothermodle.py from module import main main()
打印结果:
we are in module # 这里直接是文件名字
三、from import导入同名工具
跟导入的顺序有关;
从上到下,say_hello()会使用后导入的,因为覆盖了之前的“导入”。
[解决方案] 使用 as 别名即可。
Packages 包
为何需要 “package”
一个包含 “多个模块” 的 特殊目录。
一、“包” 是一个目录
Ref: http://www.cnitblog.com/seeyeah/archive/2009/03/15/55440.html
[1] 同级目录
`-- src |-- mod1.py `-- test1.py
test1.py要使用mod1,则:
import mod1 or from mod1 import *;
[2] 子目录
需要目录下加 __init__.py。mod2就是个Package。
`-- src |-- mod1.py |-- mod2 | `-- mod2.py
| -- __init__.py `-- test1.py
需要在mod2文件夹中建立空文件__init__.py文件 (也可以在该文件中自定义输出模块接口);
test1.py要使用mod2.py:
from mod2.mod2 import *
or
import mod2.mod2
[3] 表亲目录
mod2就是个Package。
`-- src |-- mod1.py |-- mod2 | `-- mod2.py
| -- __init__.py |-- sub | `-- test2.py `-- test1.py
首先需要在mod2下建立__init__.py文件 (同(2)),src下不必建立该文件。
test2.py要使用mode2.py:
import sys sys.path.append("..") # <----
import mod1 import mod2.mod2
二、“子目录” 示范
目录(包)名字为 ./hm_message/
文件:__init__.py,对外界提供的模块列表。
from . import send_message (文件) from . import receive_message (文件)
调用如下:
import hm_message # 代表了一组包的集合 hm_message.send_message.send("hello") txt = hm_message.receive_message.receive() print(txt)
三个作用
__init__.py文件 的作用有如下几点:
1) 初始化模块:相当于class中的 def __init__(self):函数。
2) 把所在目录当作一个package处理
3) from-import 语句导入子包时需要用到它。 如果没有用到, 他们可以是空文件。
三、__init__ 文件的 "设置"
Ref: python的包 - Tiffany's world 提出了三个问题。
-
静态调用
[问题一] 使一个目录变成包,如何 import
# 设计一个包:Sound,且内部包含各个子模块
Sound/ 包 |-- Effects Sound的一个子包 | |-- __init__.py | |-- errors.py | `-- iobuffer.py |-- Filters Sound的一个子包 | |-- __init__.py | |-- dolby.py | |-- equalizer.py | |-- karaoke.py | `-- vocoder.py |-- Utils Sound的一个子包 | |-- __init__.py | |-- echo.py <---- | |-- reverse.py | `-- surround.py `-- __init__.py 文件夹下放一个__init__.py文件, 则此文件夹为包
需要用到 Sound/Utils/echo.py时,则:
import Sound.Utils.echo
[问题二] 导入包中的哪些子模块?
__all__变量 指定的是指此包被import * 的时候, 哪些模块会被import进来。
[1] 如果,空文件:
Sound/__init__.py 是一个空文件,则:
>>> from Sound import * >>> dir() ['__builtins__', '__doc__', '__name__']
[2] 如果,加一行:
__all__ = ['Effects', 'Filters', 'Utils']
如下可见对外暴露出了更多的接口:
>>> from Sound import * >>> dir() ['Effects', 'Filters', 'Utils', '__builtins__', '__doc__', '__name__']
在这里,有必要关注下“包”中自定义属性的理解。
-
动态调用
[问题三] __init__.py 的 __path__ 变量。
之前的是静态调用模块中的方法,以下介绍的是“动态的策略"。
Sound/Utils/ |-- Linux 目录下没有__init__.py文件, 不是包, 只是一个普通目录 | `-- echo.py "I'm Linux.echo" |-- Windows 目录下没有__init__.py文件, 不是包, 只是一个普通目录 | `-- echo.py "I'm Windows.echo" |-- __init__.py |-- echo.py "I'm Sound.Utils.echo" |-- reverse.py `-- surround.py
[1] 只调用外层 echo.py,则 __init__.py 为空即可。
>>> import Sound.Utils.echo
I'm Sound.Utils.echo
[2] 想调用所有的echo.py,则填写 __init__.py 如下。
import sys import os print "Sound.Utils.__init__.__path__ before change:", __path__ # path显示出了 __init__文件所在的(默认)路径 dirname = __path__[0] if sys.platform[0:5] == 'linux': __path__.insert( 0, os.path.join(dirname, 'Linux') ) else: __path__.insert( 0, os.path.join(dirname, 'Windows') )
print "Sound.Utils.__init__.__path__ AFTER change:", __path__
执行结果如下:【注意,这里只执行了第一个,就不执行后面的echo了】
>>> import Sound.Utils.echo
Sound.Utils.__init__.__path__ before change: ['Sound/Utils'] Sound.Utils.__init__.__path__ AFTER change: ['Sound/Utils/Linux', 'Sound/Utils']
I'm Linux.echo
发布模块
Private 发布
一、制作压缩包
第一步,setup.py 文件
from distutils.core import setup setup(name = "hm_message", version="1.0", description="this is a description.", long_description="this is a long description.", author="jeffrey", author_email="jeffrey@gmail.com", url="www.cnblogs.com", py_modules=["hm_message.send_message", "hm_message.receive_message"] )
第二步
# 构建模块
python3 setup.py build
# 生成发布压缩包
python3 setup.py sdist
[OUTPUT]
02-02_zip$ tree . ├── build │ └── lib │ └── hm_message │ ├── __init__.py │ ├── receive_message.py │ └── send_message.py ├── dist │ └── hm_message-1.0.tar.gz # <---- ├── hm_message │ ├── __init__.py │ ├── receive_message.py │ └── send_message.py ├── MANIFEST └── setup.py
二、使用压缩包
第一步,解压。
第二步,自动安装到系统目录下。
$ sudo python3 setup.py install
第三步,支持导入。
import hm_message
三、卸载压缩包(模块)
第一步,查看安装目录。
import hm_message hm_message.__file__
第二步,删除。
rm -r hm_message*
Public 发布
Goto: 实战教程:如何将自己的Python包发布到PyPI上
End.