###项目结构html
model.py 项目关键的类python
util.py 项目帮助文件git
api.py 开放的apigithub
main.py 项目的启动脚本api
###0 __init__.py文件 python 的模块是经过__init__.py文件组织,当用户import module时,该文件自动执行。网络
""" XXX library ~~~~~~~~~~~~~~~~~~~~~ how to use usage: >>> print "ok" ok """ __title__ = '' __version__ = '1.0.0' __author__ = 'jchluo' #__license__ = 'Apache 2.0' #__copyright__ = '' #import api from .model import ToyModel # Set default logging handler to avoid "No handler found" warnings. import logging try: # Python 2.7+ from logging import NullHandler except ImportError: class NullHandler(logging.Handler): def emit(self, record): pass logging.getLogger(__name__).addHandler(NullHandler())
分为四部分,分别是注释、元数据、公开API、其余操做。session
提供模块名、描述等信息和简单的使用样例,以方便用户使用。app
使用样例应该遵循doctest包的格式,以进行自动化测试。格式是post
- ">>> "表示输入,注意:>>>后面的一个空格必须
- 下一行表示期待的输出
- 注意:样例必须写在源文件、方法或者类的开头
- 测试的命令
python -m doctest -v your_module.py
例如著名的网络模块requests使用样例以下测试
""" usage: >>> import requests >>> r = requests.get('https://www.python.org') >>> r.status_code 200 >>> 'Python is a programming language' in r.content True """
提供包的标题、版本号、做者等信息,若是是开源模块,最好提供licence和copyright.
在这里import
你但愿用户使用的类和方法,用户代码经过包的名字直接访问。
例如著名的网络模块requests公开的部分API以下
from .models import Request, Response, PreparedRequest from .api import request, get, head, post, patch, put, delete, options from .sessions import session, Session
当用户须要使用get
方法时,能够经过
>>>import requests >>>r = request.get("http://www.baidu.com")
代码中requests
的 get
方法就是经过from .api import get
导进来的。 若是不在这里import
,即必须
>>>import requests.api >>>r = request.api.get("http://www.baidu.com")
不在这里import
有不少缺点。
一、用户使用不方便,容易出错,经过import
具体的api
包来调用方法。
二、泄露了requests
的具体实现。假设未来有更好的访问网络方式,api
过期,可是requests
不能删除api
模块,由于用户的代码中都写了api
包,一旦删除了,用户代码所有出错。
三、用户可能会调用api
的私有方法,致使程序出错。由于私有方法是内部使用的。
这里提供一些logging
和 warnings
的配置。
咱们进行一些重要的操做时,通常经过打log的方式以进行记录,以方便后续的分析等。
request
包的底层urllib3的connectionpool.py是这样打log
:
>>> import logging >>> log = logging.getLogger(__name__) >>> log.warn("Get xxx ") No handlers could be found for logger "__main__"
尝试一下就会发现,这时会提示第4行的"No handlers"的提示。
这是由于若是没有配置好log的handler信息,log不知道怎么处理这个warn信息。
**通常来讲,咱们但愿log的配置由用户的代码来控制。由用户来决定打log的格式,输出的位置,是到文件仍是屏幕。**因此模块包通常不对log进行配置。
模块包须要对log进行操做,例如log.warn("xxx")
,可是又不能配置log的输出位置,因而就有上面No handler
的提示。
为了没有上面的提示,模块包只好给log配置了一个空handler
,这个hander
什么都不作,只是占位,由于有了hander
, 因此提示就再也不出现了。同时,若是用户配置了log,就会把这个空handler
覆盖,采用了用户的配置。下面代码 是模块包配置的空handler
import logging try: # Python 2.7+ from logging import NullHandler except ImportError: class NullHandler(logging.Handler): def emit(self, record): pass logging.getLogger(__name__).addHandler(NullHandler())
假设用户本身处理log, 能够输入如下代码
>>> import logging >>> logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s', filename='myapp.log') >>> import requests >>> requests.get("http://www.baidu.com")
注意:上面是用户的代码,不是模块包的代码
这时候,urlllib3
的 log就打到了文件myapp.log
2015-12-19 22:07:36,032 DEBUG "GET / HTTP/1.1" 200 None
###1 类
###2 方法