Pythonic

### 代码规范   谈及Python编程,《PEP 8》总是说不过去的,它是比较官方的代码风格的规范和建议。除此之外,还有《Google编程风格指导》之类的文档等,都是非常不错的文档。代码规范的重要性不言而喻,但这也是人们学习编程时最常忽略的章节。   在我读过的入门Python书籍里,中这部分的内容都比较少。但在进阶的书籍中,有的不惜用上两个章节专门讲述,如何写出遵循PEP 8规范的Python代码,并介绍各种工具来审查代码、管理项目结构和文档。当然,事情也没这么复杂,很多时候只要配置一个顺手的IDE就够了。这里我非常推荐PyCharm,它是一款非常优秀的IDE,而且提供免费的社区版。

继续阅读 >>


Web Server Gateway Interface (wsgiref.handlers部分)

django ### wsgiref.handlers   这个模块是WSGI服务器和网关的实现。只要给予一个类CGI的环境,以及输入、输出和错误流,就可以用WSGI应用程序处理绝大部分的网络连接。 * __class__ wsgiref.handlers.__CGIHandler__ 使用sys.stdin、sys.stdout和sys.stderr流的基于CGI的调用。可以用在你想以一个CGI脚本来运行你写的WSGI应用程序时。它会直接调用```CGIHandler().run(app)```,这里的app就是你想调用的对象。 这个class是把wsgi.run_once设置为True、把wsgi.multithread设置为False,而且总是使用sys和os来获取必要的CGI流和环境变量的BaseCGIHandler的派生类。 * __class__ wsgiref.handlers.__BaseCGIHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)__ 与CGIHandler类似,但不使用sys和os,而是显式的指定CGI环境和IO流。*multithread*和*multiprocess*的值是用来给任何通过此实例来运行的应用程序设置*wsgi.multithread*和*wsgi.multiprocess*标志位的。 这个类是一个随非HTTP "origin servers"软件而使用的SimpleHandler的派生类。如果你想写一个网关接口的实现,比如CGI、FastCGI、SCGI等,使用```Status: ```头来发送一个HTTP的状态码,那您肯定很想用这个实例而不是SimpleHandler的实例。 * __class__ wsgiref.handlers.__SimpleHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)__ 和上述BaseCGIHandler类似,但为了HTTP origin servers来设计的。如果你正在写一个HTTP服务器的实现,那使用这个类的实例就比BaseCGIHandler要好得多。 这个类基于BaseHandler,但覆写了__init__()、get_stdin()、get_stderr()、add_cgi_vars()、_write()和_flush()方法来支持通过这个构造器来显式设置环境和流。支持的环境和流被存储在stdin、stdout、stderr和environ属性里。 * __class__ wsgiref.handlers.__BaseHandler__ 这是一个用来运行WSGI应用程序的抽象类,虽然原则上你可以派生出一个类来复用,使得他能接收多个请求,但每个实例都应该只处理一个HTTP请求。 __BaseHandler__只有一个用于外部调用的方法: - run(*app*) 运行指定的WSGI应用程序,如*app*。 所有其他的方法都只被这个方法调用,用来辅助这个app的运行。这样从根本上可以定制处理过程。 - _write(*data*) 给字符串*data*做缓冲用来传送到client。如果这个方法发送了data,是OK的,BaseHandler只是区分了写和刷新的操作用于给特定的系统提升效率。 - _flush() 强制把缓冲区中的数据发送到client。 - get_stdin()/get_stderr() 返回WSGI请求正在处理之时对应的流。 - get_stdvars() 插入当前的请求中的CGI变量到environ的属性中。 另外,有一些方法和属性你肯定想重写它。这里仅列举出一部分,而且在打算基于BaseHandler来定制自己的类之前, 应该翻阅更官方的文档和源码来获得更确切的信息。 用来定制WSGI环境的属性和方法如下: - wsgi_multithread 用于wsgi.multithread的环境变量。在BaseHandler中默认为真,但亦可能为不同的默认值,因为有可能被别的派生类的构造器设置成了别的值。 - wsgi_multiprocess 用于wsgi.multiprocess环境变量。在BaseHandler中默认为真,但亦可能为不同的默认值,因为有可能被别的派生类的构造器设置成了别的值。 - wsgi_run_once 用于wsgi.run_once环境变量.在BaseHandler中默认为False,但CGIHandler中默认为True。 - os_environ 是每一个请求的WSGI环境中的默认环境变量。默认情况下它是当wsgiref.handlers被import的时候os.environ的拷贝,但派生类也可以在class或者实例层单独创建它们。需要注意的是,这个dict应该被设计成只读的,因为这个默认值是被多个类和实例共享的。 - server_software 如果设置origin_server属性,它的值将用于设置默认的SERVER_SOFTWARE WSGI环境变量,也会在HTTP响应中设置默认的```Server:```头. 他被非 HTTP origin servers忽略,比如BaseCGIHandler和CGIHandler。 - get_scheme() 用来返回当前请求的URL方案。默认的实现是使用guess_scheme()方法从wsgiref.util中判定当前的方案是“http”还是“https”,它是基于当前请求的environ变量的。 - setup_environ() 设置*environ*属性为fully-populated的WSGI环境。默认的实现是使用上述所有的方法加上get_stdin()、get_stderr()、和add_cgi_vars()方法,以及wsgi_file_wrapper属性。如果不存在SERVER_SOFTWARE的key,并且origin_server属性设置为真而且server_software是有值的,它也会插入这个key。 用来定制处理过程的方法和属性如下: - log_exception(*exc_info*) 给*exc_info*元组加上log。*exc_info*是(type, value, traceback) 元组,默认的实现是单纯的写入到wsgi.errors流中,然后flush。派生类可以重写这个方法来改变格式或者重定向输出、发送信息给管理员等等。 - traceback_limit 定义log_exception()中包含tracebacks输出信息的最大的帧的大小。如果为None,就会包含所有的帧。 - error_output(*environ, start_response*) 这个方法时一个WSGI应用程序来给用户产生一个error页面。它仅在发送Header之前发生错误时调用。 这个方法可以使用sys.exc_info()来进入当前错误信息。并且在被调用时,应当pass这条信息到start_response,在PEP 333中的“Error Handling”章节定义。 默认的实现就是使用```error_status```、```error_headers```和```error_body```属性来产生输出的页面。派生类可以重写它来产生更多动态的信息。 需要注意的是,从安全的角度来输出诊断信息是不推荐的,要做一些额外的工作来启用诊断输出。这就是为什么默认的实现没有包含任何东西的原因。 - error_status 用来做HTTP错误回复的状态码。这里应该是PEP 333中定义的一个字符串。默认是一个500的错误码和信息。 - error_headers 用于错误回复的HTTP headers。它应当是PEP 333中定义的WSGI响应头元组的list,比如[(name, value)]。默认的就是设置“content type”为“text/plain”。 - error_body 错误回复的body。应该是HTTP响应的body字符串,默认的是纯文本“A server error occurred. Please contact the administrator.”。 PEP 333中定义的“Optional Platform-Specific File Handling”特性相关的方法和属性: - wsgi_file_wrapper 为wsgi.file_wrapper的factory,或者为None。默认的值是wsgiref.util中的__FileWrapper__的属性。 - sendfile() 重写以实现平台特异的文件传输。这个方法只会在应用程序返回的值为wsgi_file_wrapper属性指定的类的实例时被调用。如果成功传送了一个文件它应该返回一个Ture,这样默认的传送代码就不会执行。默认的实现就是返回一个False。 其他的方法和属性: - origin_server 当handler的_write()和_flush()被用来与客户端直接连接,而不是通过类CGI的希望在特殊的```Status:```头中到HTTP状态码网关接口时,这个属性应该被设置为True。 在BaseHandler中,这个属性的默认值为True,在BaseCGIHandler和CGIHandler中为假。 - http_version 如果origin_server为真,这个字符串属性被用来给client设置HTTP版本。默认的是”1.0“。 ### 示例用法:   一个“Hello World”的WSGI应用程序: ``` from wsgiref.simple_server import make_server # Every WSGI application must have an application object - a callable # object that accepts two arguments. For that purpose, we're going to # use a function (note that you're not limited to a function, you can # use a class for example). The first argument passed to the function # is a dictionary containing CGI-style environment variables and the # second variable is the callable object (see PEP 333). def hello_world_app(environ, start_response): status = '200 OK' # HTTP Status headers = [('Content-type', 'text/plain')] # HTTP Headers start_response(status, headers) # The returned object is going to be printed return ["Hello World"] httpd = make_server('', 8000, hello_world_app) print "Serving on port 8000..." # Serve until process is killed httpd.serve_forever() ```

继续阅读 >>


Web Server Gateway Interface (simple_server和validate部分)

django ### wsgiref.simple_server   这个模块实现了一个基于__BaseHTTPServer__的轻量级WSGI应用程序的服务器。每个server实例只能在设定的主机和端口上调用一个单一的WSGI应用程序,如果要想调用多个WSGI应用程序,必须手动解析PATH_INFO来给每个request做路由,然后决定调用哪个应用程序。 * wsgiref.simple_server.__make_server(*host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler*)__ 创建一个WSGI server 来监听主机的端口,给*app*接收请求。返回的是*server_class *的实例,并且用指定的*handler_class *来处理request。app必须为PEP 333中定义的WSGI 应用程序对象。 示例用法: from wsgiref.simple_server import make_server, demo_app httpd = make_server('', 8000, demo_app) print "Serving HTTP on port 8000..." # Respond to requests until process is killed httpd.serve_forever() # Alternative: serve one request, then exit httpd.handle_request() * wsgiref.simple_server.__demo_app(*environ, start_response*)__ 一个小但完整的WSGI应用程序,返回一个text的页面包含“Hello world!”和一个在*environ *中提供的键值对构成的list,这个主要用来测试WSGI 服务器能否正确的运行一个WSGI应用程序。 * __class__ wsgiref.simple_server.__WSGIServer(*server_address, RequestHandlerClass*)__ 创建一个WSGIServer的实例,*server_address*必须为(host, port)的元组,并且*RequestHandlerClass*也必须为__BaseHTTPServer.BaseHTTPRequestHandler__的派生类,否则不能正确的处理请求。 通常这个方法不需要被调用,因为*make_server()*方法可以处理所有的细节。 __WSGIServer__是以__BaseHTTPServer.HTTPServer__为基类的,所以所有BaseHTTPServer.HTTPServer支持的方法都是可用的,比如*server_forever()*、*handle_request()*。__WSGIServer__也提供了专有的方法,比如: * __get_environ()__ 返回WSGI环境变量的dict。默认的实现是,拷贝WSGIServer对象的base_environ dict的内容,然后加上HTTP请求Header导出来的变量再返回。每次请求都会返回PEP 333中定义的包含全部CGI相关的环境变量的全新的dict。 * __get_stderr()__ 返回必须用wsgi.errors流的对象。默认的实现其实就是返回__sys.stderr__。 * __handle()__ 处理HTTP请求。默认的实现是创建一个句柄实例使用__wsgiref.handlers__类来实际的WSGI API。 ### wsgiref.validate   这个模块主要用来检查代码与规范的的一致性。它创建一个在服务器或者网关和应用程序之间检查一致性的function,用以确保两边都相符。   需要注意的是,这个模块并不能保证全部的的PEP 333的规范,它没有报错并不意味错误不存在。但一旦它抛出错误,则服务器或者应用程序端必有错误。   这个模块基于Ian Bicking的 “Python Paste” 库中的__parse.lint__扩展的。 * wsgiref.validate.__validator(*application*)__ 装饰一个*application*并且返回一个新的application,返回的application会跟随原application所有的request,并且检查两边的处理是否都符合WSGI和 RFC 2616 中的定义。 任何检测到的不服从一致性的错误都将以AssertionError抛出来,但需要注意的是,怎么抛出错误和处理是取决于服务器的。比如__simple_server__和其他基于__handlers__的服务器在错误发生时,会输出一个简单的消息,但如果其他的覆盖了错误处理和做了类似处理的服务器就可能不会抛出。 这个装饰器也会用__warnings__模块生成警告,来标识没有明确在PEP 333中禁止但存在问题的行为。除非这些警告被命令行或者__warnings__ API禁止,否则都会被写入到__sys.stderr__。 示例用法: from wsgiref.validate import validator from wsgiref.simple_server import make_server # Our callable object which is intentionally not compliant to the # standard, so the validator is going to break def simple_app(environ, start_response): status = '200 OK' # HTTP Status headers = [('Content-type', 'text/plain')] # HTTP Headers start_response(status, headers) # This is going to break because we need to return a list, and # the validator is going to inform us return "Hello World" # This is the application wrapped in a validator validator_app = validator(simple_app) httpd = make_server('', 8000, validator_app) print "Listening on port 8000...." httpd.serve_forever()  

继续阅读 >>


Web Server Gateway Interface (wsgiref.headers部分)

django ### wsgiref.headers   这个模块提供一个Headers的类,用于方便的使用一个mapping-like的接口来操作WSGI头的响应。 * __class__ wsgiref.headers.__Headers(*headers*)__ 创建一个mapping-like的对象来装饰headers,这个对象必须是由PEP 333中定义的header的name/value元组构成的list。任何更改将直接更新新的Headers对象。 Headers对象支持典型的map操作有```__getitem()__```、```__get()__```、```__setitem()__```、```__setdefault()__```、```__delitem()__```、```__contains()__```、```__haskey()__```等。 不管哪种操作,key都是header的name,value是name接下来的第一个值。设置一个header将会删除任何已存在的值,然后追加一个新的值到装饰header的list的末尾。 与dict不同的是,即使你试图get或删除一个不存在的key,Headers对象也不会抛出异常,取不存在的key会返回一个None,删除不存在的key则是什么也不做。 Headers对象也同样支持```keys()```、```values()```和```items()```方法。如果有一键多值的Header,可以返回多个list并且keys和items可以包含同一个key多次。对一个Headers对象使用```len()```方法跟len它的items有相同的效果,返回的是装饰Headers的list的长度。```items()```方法指挥返回这个装饰Header的list的副本。 对Headers对象使用```str()```方法将会得到一个格式化的字符串,来适配HTTP headers响应的传送。每个header都和它的值置于一行,以冒号和一个空格相隔。每行都终止于“\r\n”,并且这个字符串终止于一个空行。 除上述之外,Headers对象还支持两种方法来查找和追加一键多值的header、给header添加MIME参数。 * __get_all(*name*)__ 返回一个包含所有这个header中的name/value的list。 返回的list的顺序是根据他们在原header中出现的先后、添加到实例的先后来决定的,而且可能会重复。任何的字段删除并重新插入,都将追加到header list的末尾。如果没有给定的name没有存在的字段,就返回一个空的list。 * __add_header(*name, value, **params*)__ 添加一个header,并且可能是一键多值的header,可以通过params中特定的key给此方法传入MIME参数。 name是要添加的字段,keyword参数可以给这个字段添加MIME参数。每个参数必须为字符串或者None。“_”将会被转化成“-”,因为“-”在Python中是不合法的标识符,但很多MIME参数都包含它。如果参数的值是一个字符串,就会被追加到header的值中,比如```name="value"```。如果是None,就只有name会被添加,这种情况用在无值的MIME参数中。 生产实例: h.add_header('content-disposition', 'attachment', filename='bud.gif') 将会回复: Content-Disposition: attachment; filename="bud.gif"

继续阅读 >>


Web Server Gateway Interface (wsgiref.util部分)

django ### WSGI Utilities and Reference Implementation   WSGI是一个介于web服务器与Python应用程序之间的标准接口,采用标准接口可以使应用程序方便的在各个web服务器间复用和移植。   只有web服务器工程师和软件框架的作者才需要了解和关心WSGI设计的每个细节,对于应用层来讲,只需要遵循WSGI协议来安装和使用现有的框架去编写网络程序就够了。wsgiref提供WSGI环境变量以及HTTP header的回复等的各种操作方法,以及性能评测工具。 ## wsgiref.util – WSGI environment utilities   此模块包含操作WSGI环境变量的众多方法。WSGI环境变量是一个包含HTTP请求参数的dict,处理函数要使用一个*environ* 的参数来接收它。 * __wsgiref.util.guess_scheme(*environ*)__ 返回```wsgi.url_scheme```为“http”还是“https”,它是通过检查*environ* dict中的“HTTP”环境变量来实现的。返回值为string类型。 此方法在创建一个CGI或CGI类(比如FastCGI)协议的装饰器时非常有用。比如服务器在收到基于SSL的请求时,在协议中会包含一个“HTTPS”的变量,其值为“1”、“yes”或“on”等,那么使用此方法将会返回一个“https”,否则就是“http”。 * __wsgiref.util.request_uri(*environ, include_query=1*)__ 返回完整的请求的URI,通过*include_query* 参数来决定是否包含query string。判定算法使用的是PEP 333中的”URL Reconstruction“。 * __wsgiref.util.application_uri(*environ*)__ 与request_uri方法类似,但这里忽略了PATH_INFO和QUERY_STRING变量。结果就是请求的应用程序对象地址的base URI。 * __wsgiref.util.shift_path_info(*environ*)__ 从PATH_INFO中移出一个单词到SCRIPT_NAME,并且将之返回。*environ* 将会以空格填补,如果需要的话必须先保存原始的PATH_INFO和SCRIPT_NAME变量。 如果PATH_INFO再没有可以移出的部分,执行此方法就会返回一个None。 典型情况,一个需求要处理请求URI路径的每个部分,比如遍历一系列的dict的键来修改传入的环境使其适合调用另一个位于目标URI的WSGI程序。比如,有一个WSGI程序位于/foo,而请求的URI路径是/foo/bar/baz,那么位于/foo的应用程序调用 ```shift_path_info()```,将会返回"bar"。然后环境将更新来适配位于/foo/bar的WSGI应用程序。这样一来,SCRIPT_NAME将会从/foo变成/foo/bar,PATH_INFO将从/bar/baz变成/baz。 当PATH_INFO只剩“/”,就返回一个空的string并且给SCRIPT_NAME追加一个反斜杠,即便是空的路径被忽略或者SCRIPT_NAME没有正常的终止于反斜杠。这是故意设置的,来确保在对象遍历时应用程序能够区分以“/x/”和“/x”结尾的URI。 * __wsgiref.util.setup_testing_defaults(*environ*)__ 通过默认值来更新*environ*变量,用于测试用途。 这个路由添加多个用于请求WSGI的参数,包括HTTP_HOST、SERVER_NAME、SERVER_PORT、REQUEST_METHOD、SCRIPT_NAME、PATH_INFO和所有在PEP 333中定义的以“wsgi.”开头的变量。只支持默认的值,并且不会替换他们当中任何已经存在的设定值。 此方法主要用来方便的模拟一个环境用于单元测试。由于数据是模拟的,所以不应用于生产服务器和应用程序中。 一个示例: from wsgiref.util import setup_testing_defaults from wsgiref.simple_server import make_server # A relatively simple WSGI application. It's going to print out the # environment dictionary after being updated by setup_testing_defaults def simple_app(environ, start_response): setup_testing_defaults(environ) status = '200 OK' headers = [('Content-type', 'text/plain')] start_response(status, headers) ret = ["%s: %s\n" % (key, value) for key, value in environ.iteritems()] return ret httpd = make_server('', 8000, simple_app) print "Serving on port 8000..." httpd.serve_forever() 除了上述功能,wsgiref.util还提供了一些杂项工具: * __wsgiref.util.is_hop_by_hop(*header_name*)__ 如果“‘header_name”是RFC 2616中定义的HTTP/1.1 “Hop-by-Hop” header,则返回True。 * ___class___ wsgiref.util.__FileWrapper(*filelike, blksize=8192*)__ 一个装饰器,用来把file-like对象转换成一个迭代器,返回的对象支持```__getitem__()```和```__iter__()```两种循环风格。当对象迭代时,可选的*blksize*参数将被传入file-like对象的```read()```方法中用来获取产生的字符串。```当read()```方法返回一个空字符串时,迭代结束,且此对象不可恢复。 如果file-like对象有一个```close()```方法,那么转换后的对象依然有一个```close()```方法,并且在调用这个对象的```close()```方法时触发file-like对象的```close()```方法。 示例: from StringIO import StringIO from wsgiref.util import FileWrapper # We're using a StringIO-buffer for as the file-like object filelike = StringIO("This is an example file-like object"*10) wrapper = FileWrapper(filelike, blksize=5) for chunk in wrapper: print chunk

继续阅读 >>