包和模块

Posted demon_gdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了包和模块相关的知识,希望对你有一定的参考价值。

控制模块被全部导入的内容

问题:

  当使用 ‘from module import * ‘ 语句时,希望对从模块或包导出的符号进行精确控

 解决方案:

  在你的模块中定义一个变量__all__ 来明确地列出需要导出的内容

 1 # someodule.py
 2 
 3 def spam():
 4     pass
 5 
 6 def grok():
 7     pass
 8 
 9 blah = 42
10 
11 __all__ = [spma, pass]

注意:

  尽管强烈反对使用‘from module import *‘, 但是在定义了大量变量名的模块中频繁使用。如果你不做任何事, 这样的导入将会导入所有不以下划线开头的。另一方面, 如果定义了all , 那么只有被列举出的东西会被导出。

  如果你将all 定义成一个空列表, 没有东西将被导出。如果all 包含未定义的名字, 在导入时引起AttributeError。

 

使用相对路径名导入包中子模块

问题:

  将代码组织成包, 想用import 语句从另一个包名没有硬编码过的包的中导入子模块 

解决方案:

  使用包的相对导入,使一个的模块导入同一个包的另一个模块举个例子,假设在你的文件系统上有mypackage 包,组织如下:

mypackage/
    __init__.py
    A/
        __init__.py
        spam.py
        grok.py
    B/
        __init__.py
        bar.py

如果模块mypackage.A.spam 要导入同目录下的模块grok,它应该包括的import语句如下:

# mypackage/A/spam.py
from . import grok

如果模块mypackage.A.spam 要导入不同目录下的模块B.bar,它应该使用的import语句如下:

# mypackage/A/spam.py
from ..B import bar

两个import 语句都没包含顶层包名,而是使用了spam.py 的相对路径

 

注意:

相对导入只适用于在合适的包中的模块。尤其是在顶层的脚本的简单模块中,它们将不起作用。如果包的部分被作为脚本直接执行,那它们将不起作用例如:

% python3 mypackage/A/spam.py # Relative imports fail

另一方面,如果你使用Python 的-m 选项来执行先前的脚本,相对导入将会正确运行。例如:

% python3 -m mypackage.A.spam # Relative imports work

 

将模块分割成多个文件

问题:

  你想将一个模块分割成多个文件。但是你不想将分离的文件统一成一个逻辑模块时使已有的代码遭到破坏

解决方案:

  程序模块可以通过变成包来分割成多个独立的文件。考虑下下面简单的模块:

# mymodule.py
class A:
    def spam(self):
            print(A.spam)


class B(A):
    def bar(self):
        print(B.bar)

假设你想mymodule.py 分为两个文件,每个定义的一个类。要做到这一点,首先用mymodule 目录来替换文件mymodule.py。这这个目录下,创建以下文件:

mymodule/
    __init__.py
    a.py
    b.py

在a.py 文件中插入以下代码:

# a.py
class A:
    def spam(self):
        print(A.spam)    

在b.py 文件中插入以下代码:

# b.py
from .a import A
class B(A):
    def bar(self):
        print(B.bar)

最后,在init .py 中,将2 个文件粘合在一起:

# __init__.py
from .a import A
from .b import B

如果按照这些步骤,所产生的包MyModule 将作为一个单一的逻辑模块:

>>> import mymodule
>>> a = mymodule.A()
>>> a.spam()
A.spam
>>> b = mymodule.B()
>>> b.bar()
B.bar

 

读取位于包中的数据文件

问题:

  你的包中包含代码需要去读取的数据文件。你需要尽可能地用最便捷的方式来做这件事 

解决方案:

  假设你的包中的文件组织成如下:

mypackage/
    __init__.py
    somedata.dat
    spam.py

现在假设spam.py 文件需要读取somedata.dat 文件中的内容。你可以用以下代码来完成:

# spam.py
import pkgutil
data = pkgutil.get_data(__package__, somedata.dat)

 

将文件夹加入到sys.path

问题:

  你无法导入你的Python 代码因为它所在的目录不在sys.path 里。你想将添加新目录到Python 路径,但是不想硬链接到你的代码

解决方案:

  常用的方式将新目录添加到sys.path.例如:

import sys
from os.path import abspath, join, dirname
sys.path.insert(0, abspath(dirname(__file__), src))

 

通过字符串名导入模块

问题:

  你想导入一个模块,但是模块的名字在字符串里。你想对字符串调用导入命令

解决方案:

  使用importlib.import module() 函数来手动导入名字为字符串给出的一个模块或者包的一部分。举个例子:

import importlib

‘‘‘
直接导入模块,import math
‘‘‘
math = importlib.import_module(math)
res = math.sin(2)
print(math sin:, res)

‘‘‘
直接导入模块,类似于import urllib.request
‘‘‘
mod = importlib.import_module(urllib.request)
req = mod.urlopen(http://www.meizitu.com/)
response = req.read().decode(gbk)

 

分发包

问题:

  你已经编写了一个有用的库,想将它分享给其他人

解决方案:

  如果你想分发你的代码,第一件事就是给它一个唯一的名字,并且清理它的目录结构。例如,一个典型的函数库包会类似下面这样:

projectname/
    README.txt
    Doc/
        documentation.txt
    projectname/
        __init__.py
        foo.py
        bar.py
    utils/
        __init__.py
        spam.py
        grok.py
    examples/
        helloworld.py

要让你的包可以发布出去,首先你要编写一个setup.py ,类似下面这样:

# setup.py
from distutils.core import setup


setup(name=projectname,
    version=1.0,
    author=Your Name,
    author_email=[email protected],
    url=http://www.you.com/projectname,
    packages=[projectname, projectname.utils],
)

下一步,就是创建一个MANIFEST.in 文件,列出所有在你的包中需要包含进来的非源码文件:

# MANIFEST.in
include *.txt
recursive-include examples *
recursive-include Doc *

确保setup.py 和MANIFEST.in 文件放在你的包的最顶级目录中。一旦你已经做了这些,你就可以像下面这样执行命令来创建一个源码分发包了:

$ bash python3 setup.py sdist

它会创建一个文件比如”projectname-1.0.zip” 或“projectname-1.0.tar.gz”, 具体依赖于你的系统平台。如果一切正常,这个文件就可以发送给别人使用或者上传至Python Package Index.

 

以上是关于包和模块的主要内容,如果未能解决你的问题,请参考以下文章

模块包和异常

包和其他模块

包和一些常用模块

导包和模块注意的问题

3. python中的包和库

第七章 Python 盒子:模块包和程序