Skip to content Skip to main navigation Skip to footer

python

Python: 【Python爬虫实战】爬取糗事百科段子

来自: 静觅丨崔庆才的个人博客

链接:http://cuiqingcai.com/990.html

声明:本文仅限技术交流讨论

这次为大家带来,Python爬取糗事百科的小段子的例子。

首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来。

本篇目标

1.抓取糗事百科热门段子

2.过滤带有图片的段子

3.实现每按一次回车显示一个段子的发布时间,发布人,段子内容,点赞数。

糗事百科是不需要登录的,所以也没必要用到Cookie,另外糗事百科有的段子是附图的,我们把图抓下来图片不便于显示,那么我们就尝试过滤掉有图的段子吧。

好,现在我们尝试抓取一下糗事百科的热门段子吧,每按下一次回车我们显示一个段子。

1 . 确定URL并抓取页面代码

首先我们确定好页面的URL是 http://www.qiushibaike.com/hot/page/1,其中最后一个数字1代表页数,我们可以传入不同的值来获得某一页的段子内容。

我们初步构建如下的代码来打印页面代码内容试试看,先构造最基本的页面抓取方式,看看会不会成功

# -*- coding:utf-8 -*-

import urllib

import urllib2

page = 1

url = ‘http://www.qiushibaike.com/hot/page/’ + str(page)

try:

request = urllib2.Request(url)

response = urllib2.urlopen(request)

print response.read()

except urllib2.URLError, e:

if hasattr(e,”code>”):

print e.code

if hasattr(e,”reason>”):

print e.reason

运行程序,哦不,它竟然报错了,真是时运不济,命途多舛啊

line 373, in _read_status

raise BadStatusLine(line)

httplib.BadStatusLine: ”

好吧,应该是headers验证的问题,我们加上一个headers验证试试看吧,将代码修改如下

# -*- coding:utf-8 -*-

import urllib

import urllib2

page = 1

url = ‘http://www.qiushibaike.com/hot/page/’ + str(page)

user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’

headers = { ‘User-Agent’ : user_agent }

try:

request = urllib2.Request(url,headers = headers)

response = urllib2.urlopen(request)

print response.read()

except urllib2.URLError, e:

if hasattr(e,”code>”):

print e.code

if hasattr(e,”reason>”):

print e.reason

嘿嘿,这次运行终于正常了,打印出了第一页的HTML代码,大家可以运行下代码试试看。在这里运行结果太长就不贴了。

2.提取某一页的所有段子

好,获取了HTML代码之后,我们开始分析怎样获取某一页的所有段子。

首先我们审查元素看一下,按浏览器的F12,截图如下

我们可以看到,每一个段子都是

包裹的内容。

现在我们想获取发布人,发布日期,段子内容,以及点赞的个数。不过另外注意的是,段子有些是带图片的,如果我们想在控制台显示图片是不现实的,所以我们直接把带有图片的段子给它剔除掉,只保存仅含文本的段子。

所以我们加入如下正则表达式来匹配一下,用到的方法是 re.findall 是找寻所有匹配的内容。方法的用法详情可以看前面说的正则表达式的介绍。

好,我们的正则表达式匹配语句书写如下,在原来的基础上追加如下代码

content = response.read().decode(‘utf-8’)

pattern = re.compile(‘.*?.*?(.*?).*?

‘=>”content”.*?title=>”(.*?)”>(.*?)

(.*?)

“stats.*?class=”number>”>(.*?)‘,re.S)

items = re.findall(pattern,content)

for item in items:

print item[0],item[1],item[2],item[3],item[4]

现在正则表达式在这里稍作说明

1).*? 是一个固定的搭配,.和*代表可以匹配任意无限多个字符,加上?表示使用非贪婪模式进行匹配,也就是我们会尽可能短地做匹配,以后我们还会大量用到 .*? 的搭配。

2)(.*?)代表一个分组,在这个正则表达式中我们匹配了五个分组,在后面的遍历item中,item[0]就代表第一个(.*?)所指代的内容,item[1]就代表第二个(.*?)所指代的内容,以此类推。

3)re.S 标志代表在匹配时为点任意匹配模式,点 . 也可以代表换行符。

现在我们可以看一下部分运行结果

儒雅男神 2015-02-17 14:34:42

小时候一个一个拆着放的举个爪…

7093

奇怪的名字啊 2015-02-17 14:49:16

回家的路,你追我赶,回家的心情和窗外的阳光一样灿烂。一路向前,离亲人越来越近了。哪里有爸妈哪里才是家,希望所有糗友的爸爸妈妈都身体健康…….

4803

这是其中的两个段子,分别打印了发布人,发布时间,发布内容,附加图片以及点赞数。

其中,附加图片的内容我把图片代码整体抠了出来,这个对应item[3],所以我们只需要进一步判断item[3]里面是否含有img这个字样就可以进行过滤了。

好,我们再把上述代码中的for循环改为下面的样子

for item in items:

haveImg = re.search(“img>”,item[3])

if not haveImg:

print item[0],item[1],item[2],item[4]

现在,整体的代码如下

# -*- coding:utf-8 -*-

import urllib

import urllib2

import re

page = 1

url = ‘http://www.qiushibaike.com/hot/page/’ + str(page)

user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’

headers = { ‘User-Agent’ : user_agent }

try:

request = urllib2.Request(url,headers = headers)

response = urllib2.urlopen(request)

content = response.read().decode(‘utf-8’)

pattern = re.compile(‘.*?.*?(.*?).*?

‘=>”content”.*?title=>”(.*?)”>(.*?)

(.*?)

“stats.*?class=”number>”>(.*?)‘,re.S)

items = re.findall(pattern,content)

for item in items:

haveImg = re.search(“img>”,item[3])

if not haveImg:

print item[0],item[1],item[2],item[4]

except urllib2.URLError, e:

if hasattr(e,”code>”):

print e.code

if hasattr(e,”reason>”):

print e.reason

运行一下看下效果

恩,带有图片的段子已经被剔除啦。是不是很开森?

3.完善交互,设计面向对象模式

好啦,现在最核心的部分我们已经完成啦,剩下的就是修一下边边角角的东西,我们想达到的目的是:

按下回车,读取一个段子,显示出段子的发布人,发布日期,内容以及点赞个数。

另外我们需要设计面向对象模式,引入类和方法,将代码做一下优化和封装,最后,我们的代码如下所示

__author__ = ‘CQC’

# -*- coding:utf-8 -*-

import urllib

import urllib2

import re

import thread

import time

#糗事百科爬虫类

class QSBK:

#初始化方法,定义一些变量

def __init__(self):

self.pageIndex = 1

self.user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’

#初始化headers

self.headers = { ‘User-Agent’ : self.user_agent }

#存放段子的变量,每一个元素是每一页的段子们

self.stories = []

#存放程序是否继续运行的变量

self.enable = False

#传入某一页的索引获得页面代码

def getPage(self,pageIndex):

try:

url = ‘http://www.qiushibaike.com/hot/page/’ + str(pageIndex)

#构建请求的request

request = urllib2.Request(url,headers = self.headers)

#利用urlopen获取页面代码

response = urllib2.urlopen(request)

#将页面转化为UTF-8编码

pageCode = response.read().decode(‘utf-8’)

return pageCode

except urllib2.URLError, e:

if hasattr(e,”reason>”):

print u”连接糗事百科失败,错误原因>”,e.reason

return None

#传入某一页代码,返回本页不带图片的段子列表

def getPageItems(self,pageIndex):

pageCode = self.getPage(pageIndex)

if not pageCode:

print “页面加载失败….>”

return None

pattern = re.compile(‘.*?.*?(.*?).*?

‘=>”content”.*?title=>”(.*?)”>(.*?)

(.*?)

“stats.*?class=”number>”>(.*?)‘,re.S)

items = re.findall(pattern,pageCode)

#用来存储每页的段子们

pageStories = []

#遍历正则表达式匹配的信息

for item in items:

#是否含有图片

haveImg = re.search(“img>”,item[3])

#如果不含有图片,把它加入list中

if not haveImg:

#item[0]是一个段子的发布者,item[1]是发布时间,item[2]是内容,item[4]是点赞数

pageStories.append([item[0].strip(),item[1].strip(),item[2].strip(),item[4].strip()])

return pageStories

#加载并提取页面的内容,加入到列表中

def loadPage(self):

#如果当前未看的页数少于2页,则加载新一页

if self.enable == True:

if len(self.stories) < 2:

#获取新一页

pageStories = self.getPageItems(self.pageIndex)

#将该页的段子存放到全局list中

if pageStories:

self.stories.append(pageStories)

#获取完之后页码索引加一,表示下次读取下一页

self.pageIndex += 1

#调用该方法,每次敲回车打印输出一个段子

def getOneStory(self,pageStories,page):

#遍历一页的段子

for story in pageStories:

#等待用户输入

input = raw_input()

#每当输入回车一次,判断一下是否要加载新页面

self.loadPage()

#如果输入Q则程序结束

if input == “Q>”:

self.enable = False

return

print u”第%d页\t发布人:%s\t发布时间:%s\n%s\n赞:%s\n>” %(page,story[0],story[1],story[2],story[3])

#开始方法

def start(self):

print u”正在读取糗事百科,按回车查看新段子,Q退出>”

#使变量为True,程序可以正常运行

self.enable = True

#先加载一页内容

self.loadPage()

#局部变量,控制当前读到了第几页

nowPage = 0

while self.enable:

if len(self.stories)>0:

#从全局list中获取一页的段子

pageStories = self.stories[0]

#当前读到的页数加一

nowPage += 1

#将全局list中第一个元素删除,因为已经取出

del self.stories[0]

#输出该页的段子

self.getOneStory(pageStories,nowPage)

spider = QSBK()

spider.start()

好啦,大家来测试一下吧,点一下回车会输出一个段子,包括发布人,发布时间,段子内容以及点赞数,是不是感觉爽爆了!

我们第一个爬虫实战项目介绍到这里,欢迎大家继续关注,小伙伴们加油!

来自: 静觅丨崔庆才的个人博客

链接:http://cuiqingcai.com/990.html

荐号:IT创业网

互联网创业的时代,创业更具人文气息。聚最经典的IT创业技巧,最顶尖的商界精英交流平台。

微信号: chuangyetech

↑↑↑长摁二维码试试

●本文编号856,以后想阅读这篇文章直接输入856即可。

●本文分类“ 搜索引擎技术 ”,搜索分类名可以获得相关文章。

●输入m可以获取到全部文章目录

●输入r可以获取到热门文章推荐

●输入f可以获取到全部分类名称

原文:http://mp.weixin.qq.com/s?__biz=MjM5NzA1MTcyMA==&mid=206571806&idx=5&sn=59a2ddfac1da6804345538c16d01c661&3rd=MzA3MDU4NTYzMw==&scene=6#rd

Python: MicroPython:针对微控制器的Python

Python: MicroPython:针对微控制器的Python
Python: MicroPython:针对微控制器的Python

剑桥大学数学科学中心的 Damien P. George 在研究各种深奥数学、物理问题之余,还搞了一个 MicroPython 项目,将Python移植到ARM Cortex M微处理器上,并开发了电路板。2013年曾经在 KickStarter 上成功筹得近10万英镑。2014年成功完成项目,发货。

同时,这个项目也在 GitHub 上开源,至今已有1800+星,60位贡献者。

George曾在2014年PyCon UK上 介绍 MicroPython,所用硬件平台叫pyboard,规格是:

  • STM32F405RG: 192k RAM, 1M ROM, 168MHz, Cortex M4F.
  • USB micro connector for device (and host).
  • Micro SD card.
  • 3-axis accelerometer (MMA7660).
  • Real-time clock, 4 LEDs, 2 switches.
  • 30 GPIO: symmetric pin layout, plus extra pins.
  • Internal file system. ”/flash” and ”/sd”.

由于存储太小,CPython都太大,只能自行开发Python实现,采取了很多优化措施:

  • Interned strings, most already in ROM.
  • Small integers stuffed in a pointer.
  • Optimised method calls (thanks PyPy!).
  • Range object is optimised (if possible).
  • Python stack frames live on the C stack.
  • ROM absolutely everything that can be ROMed!
  • Garbage collection only (no reference counts).
  • Exceptions implemented with custom setjmp/longjmp.

优化后,比原生的Python 2和Python 3都快了几个数量级: https://news.ycombinator.com/item?id=7841642

MicroPython的生态系统现在也开始起来了,就在本月前几天,荷兰埃因霍温的一个团队 WiPy 刚刚在KickStarter上成功众筹到75000多英镑,他们的项目是基于MicroPython软件的另一款硬件:超低功耗的物联网WiFi硬件。

SparkFun上也有WiFi模块 ESP8266

HN上的两次讨论:

https://news.ycombinator.com/item?id=9558969

https://news.ycombinator.com/item?id=7840566

原文:http://www.iteye.com/news/30549

Python: gevent源代码分析之用gevent threadpool实现多进程任务调度

这两天出了两个事故,一个是因为正负面的接口被被人疯狂访问而变得堵塞,导致整个动态网页解析解析的崩溃,最后redis挂掉。 还有一个事情是动态ip轮询模块的bug。。。 多事之秋呀。  这几个晚上一直尝试看gevent的源代码,收获特别的大,gevent本身的一些实现就特别的灵巧,背靠这内核的epoll调度,实现一系列的io调度非堵塞。 

大家知道gevent是协程,协程是用户态层面自己解决io堵塞的问题,他会把每次堵塞时间都注册是epoll里面。 那么,gevent是单线程的形态,那么gevent可以实现多进程么? 今天看了下threadpool的相关代码,发现光看他的名字的话,是多线程的意思 。 thread就一线程的意思。   python的线程就是个坑爹的东西,我现在的服务端架构基本是多进程加多协程的架构。 言归正传,gevent是如何实现多进程?   看了下官方的issue,有人提出用threadpool实现。  简单过了下代码,他是利用os.fork 来派生多进程的,具体的调度我就多说了,主要是在from gevent.hub import get_hub这里。 

gevent的文章, http://xiaorui.cc/?p=1530

Python: gevent源代码分析之用gevent threadpool实现多进程任务调度
Python: gevent源代码分析之用gevent threadpool实现多进程任务调度

下面是我测试的表现,效果还是可以的,计算任务跑的还算平均。 测试是在一个云主机测试的,有些片面性。 

测试的代码如下:

Python

import time
import gevent
from gevent.threadpool import ThreadPool
def sum(i):
    i = 0
    for i in xrange(100000000):
        i += i+1 * 20 / 10 * 10 /10
def test(n,m):
    m=m
    vals = []
    keys = []
    for i in xrange(m):
        vals.append(i)
        keys.append('a%s'%i)
    d = None
    for i in xrange(n):
        d = dict(zip(keys, vals))
    return d
pool = ThreadPool(20)
start = time.time()
for _ in xrange(10):
    pool.spawn(test, 1000000,100)
gevent.wait()
delay = time.time() - start
print 'Running "time.sleep(1)>" 4 times with 3 threads. Should take about 2 seconds: %.3fs' % delay 

下面是Threadpool 的部分源代码,set_size是创建进程的数目,on_fork是fork进程,kill是干掉进程,spawn是触发进程,add_thread是增加进程。 

Python

def _set_size(self, size):
    if size < 0:
        raise ValueError('Size of the pool cannot be negative: %r' % (size, ))
    if size > self._maxsize:
        raise ValueError('Size of the pool cannot be bigger than maxsize: %r &gt; %r' % (size, self._maxsize))
    if self.manager:
        self.manager.kill()
    while self._size < size:
        self._add_thread()
    delay = 0.0001
    while self._size > size:
        while self._size - size &gt; self.task_queue.unfinished_tasks:
            self.task_queue.put(None)
        if getcurrent() is self.hub:
            break
        sleep(delay)
        delay = min(delay * 2, .05)
    if self._size:
        self.fork_watcher.start(self._on_fork)
    else:
        self.fork_watcher.stop()
size = property(_get_size, _set_size)
def _init(self, maxsize):
    self._size = 0
    self._semaphore = Semaphore(1)
    self._lock = Lock()
    self.task_queue = Queue()
    self._set_maxsize(maxsize)
def _on_fork(self):
    # fork() only leaves one thread; also screws up locks;
    # let's re-create locks and threads
    pid = os.getpid()
    if pid != self.pid:
        self.pid = pid
        # Do not mix fork() and threads; since fork() only copies one thread
        # all objects referenced by other threads has refcount that will never
        # go down to 0.
        self._init(self._maxsize)
def join(self):
    delay = 0.0005
    while self.task_queue.unfinished_tasks &gt; 0:
        sleep(delay)
        delay = min(delay * 2, .05)
def kill(self):
    self.size = 0
def _adjust_step(self):
    # if there is a possibility &amp; necessity for adding a thread, do it
    while self._size < self._maxsize and self.task_queue.unfinished_tasks > self._size:
        self._add_thread()
    # while the number of threads is more than maxsize, kill one
    # we do not check what's already in task_queue - it could be all Nones
    while self._size - self._maxsize &gt; self.task_queue.unfinished_tasks:
        self.task_queue.put(None)
    if self._size:
        self.fork_watcher.start(self._on_fork)
    else:
        self.fork_watcher.stop()
def _adjust_wait(self):
    delay = 0.0001
    while True:
        self._adjust_step()
        if self._size <= self._maxsize:
            return
        sleep(delay)
        delay = min(delay * 2, .05)
def adjust(self):
    self._adjust_step()
    if not self.manager and self._size > self._maxsize:
        # might need to feed more Nones into the pool
        self.manager = Greenlet.spawn(self._adjust_wait)
def _add_thread(self):
    with self._lock:
        self._size += 1
    try:
        start_new_thread(self._worker, ())
    except:
        with self._lock:
            self._size -= 1
        raise
def spawn(self, func, *args, **kwargs):
    while True:
        semaphore = self._semaphore
        semaphore.acquire()
        if semaphore is self._semaphore:
            break
    try:
        task_queue = self.task_queue
        result = AsyncResult()
        thread_result = ThreadResult(result, hub=self.hub)
        task_queue.put((func, args, kwargs, thread_result))
        self.adjust()
        # rawlink() must be the last call
        result.rawlink(lambda *args: self._semaphore.release())
        # XXX this _semaphore.release() is competing for order with get()
        # XXX this is not good, just make ThreadResult release the semaphore before doing anything else
    except:
        semaphore.release()
        raise
    return result 

原文:http://xiaorui.cc/2015/05/29/gevent源代码分析之用gevent-threadpool实现多进程任务调度/

Python: 用python验证蒙提霍尔问题

最初看到这个问题是初中的时候买了一本有关数学谜题的书里面概率论的一张的课后拓展就是说到三门问题,当时作为一个扩展阅读看了一下,里面说到了一个世界智商最高的女人秒杀了美国一大群的数学高材生的精彩故事(比较夸张),当时对这个问题也是似懂非懂。

什么是蒙提霍尔问题?

蒙提霍尔问题,亦称为蒙特霍问题或三门问题(英文:Monty Hall problem),是一个源自博弈论的数学游戏问题,大致出自美国的电视游戏节目Let’s Make a Deal。问题的名字来自该节目的主持人蒙提·霍尔(Monty Hall)。

最初的表述是:

参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,选中后面有车的那扇门就可以赢得该汽车,而另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门,但未去开启它的时候,节目主持人开启剩下两扇门的其中一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。问题是:换另一扇门会否增加参赛者赢得汽车的机会率?

这个古老的问题一经提出就引起了剧烈的争论,有人认为换与不换最终得到车的概率都是$\frac{1}{2}$,有人认为换门之后得到车的概率更大,应该选择换门之后得到车的概率为$\frac{2}{3}$在撰写这篇文章的时候在 果壳上还有人在为此争吵, 知乎上也有许多关于这方面的讨论,其实这些争论很多情况下都是因这个问题的模糊表述所引起的,关键点在于 主持人对于门后的情况是否了解:

  1. 如果主持人事先知道哪个门里有山羊并且他特意选择了有山羊的门打开了,那么参赛者应该换另一扇门,这可以将他胜利的概率从$\frac{1}{3}$升到$\frac{2}{3}$
  2. 如果主持人事先不知道哪个门里有山羊或者他只是随机的选择了一个门,但事实发现里面恰好是山羊。这时候参赛者没有换门的必要,胜利概率总是$\frac{1}{2}$

为了后续的讨论,这里采用 维基百科上对于这一个问题的不含糊的定义

严格的表述如下:

  • 参赛者在三扇门中挑选一扇。他并不知道内里有什么。
  • 主持人知道每扇门后面有什么。
  • 主持人必须开启剩下的其中一扇门,并且必须提供换门的机会。
  • 主持人永远都会挑一扇有山羊的门。

    • 如果参赛者挑了一扇有山羊的门,主持人必须挑另一扇有山羊的门。
    • 如果参赛者挑了一扇有汽车的门,主持人随机在另外两扇门中挑一扇有山羊的门。
  • 参赛者会被问是否保持他的原来选择,还是转而选择剩下的那一道门。

那么这个问题这可以很好的理解了,引用维基的一幅图片解析:

有三种可能的情况,全部都有相等的可能性($\frac{1}{3}$):

  • 参赛者挑汽车,主持人挑两头羊的任何一头。转换将失败。
  • 参赛者挑A羊,主持人挑B羊。转换将赢得汽车。
  • 参赛者挑B羊,主持人挑A羊。转换将赢得汽车。

所以玩家选择换门之后获胜的概率应为$\frac{2}{3}$

证明?

定义:

  • 事件A为一开始玩家选择的一扇门
  • 事件H为最后门后的结果

  • 如果是选择不换门的策略

    $P \left(H=car \right) = P \left(A=car \right) = \frac{1}{3} $

    因为选择的是不交换的策略,所有只有一开始选中的是汽车,最后才能选中汽车。

  • 选择交换门的策略

    $P \left(H=car \right) = P \left(A=sheep \right) = \frac{2}{3} $

    因为选择的是交换的策略,所有只有一开始选中的是羊,最后才能选中汽车。

程序验证

实践是检验真理的唯一标准,在流言终结者看到他们人工重复这个实验区验证,发现这样很浪费时间。何通过计算机去去模拟这一段过程呢?下面使用python程序来模拟这一段过程:

from __future__ import division
import logging
from matplotlib import pyplot as plt
import numpy as np
import random
class MontyHall(object):
	">""docstring for MontyHall>"">"
	def __init__(self, num=3):
		">""
		创建一个door列表
		0 代表关门
		1 表示后面有车
		-1 代表门被打开
		>"">"
		super(MontyHall, self).__init__()
		self.doors = [0] * num
		self.doors[0] = 1
		self.choice = -1
		self.exclude_car = False
		self.shuffle()
	def shuffle(self):
		">""
		开始新游戏
		重新分配门后的东西
		>"">"
		if self.exclude_car == True:
			self.doors[0] = 1
			self.exclude_car = False
		for i in xrange(len(self.doors)):
			if self.doors[i] == -1:
				self.doors[i] = 0
		random.shuffle(self.doors)
	def make_choice(self):
		">""
		player随机选择一扇门
		>"">"
		self.choice = random.randint(0, len(self.doors) - 1)
		logging.info("choice: %d>" % self.choice)
		logging.info("original: %s>" % self.doors)
	def exclude_doors(self):
		">""
		主持人知道门后的情况排除门
		直到剩余两扇门
		>"">"
		to_be_excluded = []
		for i in xrange(len(self.doors)):
			if self.doors[i] == 0 and self.choice != i:
				to_be_excluded.append(i)
		random.shuffle(to_be_excluded)
		for i in xrange(len(self.doors) - 2):
			self.doors[to_be_excluded[i]] = -1
		logging.info("final: %s>" % self.doors)
	def random_exclude_doors(self):
		">""
		主持人并不知道门后面的情况随机的开门
		直到剩余两扇门
		>"">"
		to_be_excluded = []
		for i in xrange(len(self.doors)):
			if self.doors[i] != -1 and i != self.choice:
				to_be_excluded.append(i)
		random.shuffle(to_be_excluded)
		for i in xrange(len(self.doors) - 2):
			if self.doors[to_be_excluded[i]] == 1:
				self.exclude_car = True
			self.doors[to_be_excluded[i]] = -1
		logging.info("final: %s>" % self.doors)
	def change_choice(self):
		">""
		player改变选择
		>"">"
		to_change = []
		for i in xrange(len(self.doors)):
			if self.doors[i] != -1 and i != self.choice:
				to_change.append(i)
		self.choice = random.choice(to_change)
		logging.info("choice changed: %d>" % self.choice)
	def random_choice(self):
		">""
		player 第二次随机选择门
		>"">"
		to_select = []
		for i in xrange(len(self.doors)):
			if self.doors[i] != -1:
				to_select.append(i)
		self.choice = random.choice(to_select)
		logging.info("random choice : %d>" % self.choice)
	def show_answer(self):
		">""
		展示门后的情况
		>"">"
		logging.info(self.doors)
	def check_result(self):
		">""
		验证结果
		>"">"
		got_it = False
		if self.doors[self.choice] == 1:
			got_it = True
		return got_it
 

模拟1000轮,每一轮重复试验1000次

  • 不改变选择:
def unchange_choice_test(n):
	">""
	不改变初始的选择
	>"">"
	result = {}
	game = MontyHall()
	for i in xrange(n):
		game.shuffle()
		game.make_choice()
		game.exclude_doors()
		if game.check_result():
			result["yes>"] = result.get("yes>", 0) + 1
		else:
			result["no>"] = result.get("no>", 0) + 1
	for key in result:
		print "%s: %d>" % (key, result[key])
	return result["yes>"] / n
if __name__ == '__main__':
	logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.WARNING)
	results = []
	test_num = 1000
	round_num = 1000
	for x in xrange(0,round_num):
		results.append(change_random_test(test_num) )
	y_mean = np.mean(results)
	y_std = np.std(results)
	x = range(0,round_num)
	y = results
	plt.figure(figsize=(8,4))
	plt.xlabel("round>")
	plt.ylabel("frequency>")
	plt.title("The frequency of the success>")
	tx = round_num / 2
	ty = y_mean
	label_var = "$\sigma \left( X \\right)=$%f>" % y_std
	label_mean = "$ X =$%f>" % y_mean
	p1_label = "%s and %s>" % (label_var,label_mean)
	p1 = plt.plot(x,y,"->",label=p1_label,linewidth=2)
	plt.legend(loc='upper left')
	pl2 = plt.figure(2)
	plt.figure(2)
	plt.hist(results,40,normed=1,alpha=0.8)
	plt.show()
 

结果:

概率分布:

成功的概率均值在 $\frac{1}{3}$ 附近

  • 改变选择:
def change_choice_test(n):
">""
交换选择的门
>"">"
result = {}
game = MontyHall()
for i in xrange(n):
	game.shuffle()
	game.make_choice()
	game.exclude_doors()
	game.change_choice()
	if game.check_result():
		result["yes>"] = result.get("yes>", 0) + 1
	else:
		result["no>"] = result.get("no>", 0) + 1
for key in result:
	print "%s: %d>" % (key, result[key])
return result["yes>"] / n
 

同样的方法绘图得到结果:

概率分布:

成功的概率均值在 $\frac{2}{3}$ 附近

通过上面的分析与模拟可知最佳的策略当然就是换门。

更加深入的讨论

  • 如果门的数量不止是3个,如果是50扇门呢?

这种情况下,主持人打开48扇都是羊的门后,再给你选择,很多人这个时候应该就不会固守那$\frac{1}{2}$,而会选择换门

把门的数据增大到100,1000,这种情况会更加明显。

还是通过一段程序模拟说明:

def change_choice_test_large(n,m):
	">""
	交换选择的门
	>"">"
	result = {}
	game = MontyHall(m)
	for i in xrange(n):
		game.shuffle()
		game.make_choice()
		game.exclude_doors()
		game.change_choice()
		if game.check_result():
			result["yes>"] = result.get("yes>", 0) + 1
		else:
			result["no>"] = result.get("no>", 0) + 1
	for key in result:
		print "%s: %d>" % (key, result[key])
	return result["yes>"] / n
if __name__ == '__main__':
	logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.WARNING)
	results = []
	test_num = 1000
	round_num = 1000
	for x in xrange(0,round_num):
		results.append(change_choice_test_large(test_num,50) )
 

结果:


这时候就要选择 交换门。

  • 遇到这种情况我很困惑,我决定抛硬币决定,这个时候成功的概率?

这是第3种策略,成功的概率和硬币有关,也就是$\frac1 2$,这种情况就是从剩下的门中随机选择一扇,这个策略从上面分析来看不是最好的,但是比不改变的策略要好。

程序的模拟结果:


  • 比如门意外打开的情况呢,也就是上面描述的第二种情况(主持在不知门后的情况下打开门呢)?

这种情况下其实就是一个条件概率,事件A是玩家最后开到的是车,事件B是主持人打开的门是羊。

$$

P(A|B) = \dfrac{P(B|A) \cdot P(A) }{P(B)}

$$

因为只有主持人开到是羊的情况下,玩家才有可能开到车所以 $P(B|A) = 1$

设玩家第一次选择的门为 事件C

  • 不交换策略下的条件概率是:

    $$

    P(B) = P(C=’汽车’) + P(C=’羊’) \times \frac {1}{2}

    \Rightarrow P(B)= \frac{1}{3} + \frac{1}{3} = \frac{2}{3}

    $$

$$

P(A) = P(C=’汽车’) = \frac{1}{3}

$$

$$

P(A|B) = \dfrac{P(A) }{P(B) } = \dfrac{\frac{1}{3}}{\frac{2}{3}}= \frac{1}{2}

$$

  • 交换策略下的条件概率是:

    $$

    P(B) = P(C=’汽车’) + P(C=’羊’) \times \frac {1}{2}

    \Rightarrow P(B)= \frac{1}{3} + \frac{1}{3} = \frac{2}{3}

    $$

$$

P(A) = P(C=’羊’) \times \frac{1}{2} = \frac{1}{3}

$$

$$

P(A|B) = \dfrac{P(A) }{P(B) } = \dfrac{\frac{1}{3}}{\frac{2}{3}}= \frac{1}{2}

$$

因此在主持人不知道门后的情况下打开一扇,然后发现门后是羊的情况下,换门与不换门最终的概率都是$\frac{1}{2}$

还是可以通过程序进行模拟:

def unknown_doors_choice_test(n):
">""
主持人并不知道门后面的情况随机的开门
交换选择的门
>"">"
result = {}
game = MontyHall()
continue_count = 0
for i in xrange(n):
	game.shuffle()
	game.make_choice()
	game.random_exclude_doors()
	game.change_choice()
	if game.exclude_car == False:
		continue_count += 1
	if game.check_result():
		result["yes>"] = result.get("yes>", 0) + 1
	else:
		result["no>"] = result.get("no>", 0) + 1
#for key in result:
#	print "%s: %d>" % (key, result[key])
logging.info("continue_count: %d>" % continue_count)
if continue_count == 0:
	return 0.0
return result["yes>"] / continue_count
 

在这种情况下交换门也没有提升成功的概率

总结

今天写的这篇东西也算是了解我童年的一个遗憾,人的直觉有时候是很不可靠,要摆脱个人局限的认知才能拥抱更大的世界。什么?看完这些解析,你还觉得不满意那么你还可以从下面的参考中寻找更好的解析,本文撰写过程有部分的图片引用自一下的参考,如果你还有疑问欢迎你联系我进一步的讨论。

练习

下面是三门问题的两个翻版,引用自 三门问题及相关

女孩的概率

  • 你结交一位新朋友,问她是否有孩子。她说有,有两个。你问,有女孩吗?她说有。那么,两个都是女孩的概率是多少?

    答:三分之一。因为生两个孩子的可能性有四种等可能:BB、GG、BG、GB(即男男、女女、男女、女男)。 因为我们已知至少有一个女儿,所以BB是不可能的。因此GG是可能出现的三个等可能的结果之一,所以两个孩子都是女儿的概率为三分之一。这对应了三门问题的第一种情况。

  • 你结交一位新朋友,问她是否有孩子。她说有,有两个。你问,有女孩吗?她说有。第二天,你看见她带了一个小女孩。你问她,这是你女儿吗?她说,是。她的两个孩子都是女孩的概率是多少?

    这个概率和生女孩的概率相同,二分之一。这似乎非常奇怪,因为我们所拥有的信息看起来并不比第一种情况时多,但概率却不同。但是这里的问题其实是,那个你没>见过的孩子是女孩的概率是多少?这个概率和生女孩的概率相同,二分之一。

    这对应了三门问题的第二种情况。当然这里也有语言问题,必须假定这位母亲不是特定带出一个小女孩来给你看的。也就是说你只是碰巧发现了它是位小女孩。这取决于是判断选择 或q 随机选择。如果是被你碰巧撞见这是属于随机选择。这就对应了三门问题的第二种情况。这其实是增加了信息的。否则如果她主动带一个小女孩过来给你,则属于判断选择。

    你得到的答案依赖于所讲的故事;它依赖于你是如何得知至少一个孩子是女孩的。

三囚犯问题

  • 亚当、比尔和查尔斯被关在一个监狱里,只有监狱看守知道谁会被判死刑,另外两位将会获释。有1/3的概率会被处死刑的亚当,给他母亲写了一封信,想要获释的比尔或查尔斯帮忙代寄。当亚当问看守他应当把他的信交给比尔还是查尔斯时,这位富有同情心的看守很为难。他认为如果他把将要获释的人的名字告诉亚当,那么亚当就会有1/2的概率被判死刑,因为剩下的人和亚当这两人中一定有一个人被处死。如果他隐瞒这信息,亚当被处死的概率是1/3。既然亚当知道其他两人中必有一人会获释,那么亚当自己被处死的概率怎么可能会因为看守告诉他其他两人中被获释者的姓名后而改变呢?

    正确的答案是:看守不用当心,因为即使把获释人的姓名告诉亚当,亚当被处死的概率仍然是1/3,没有改变。但是,剩下的那位没被点名的人就有2/3的概率被处死(被处死的可能性升高了)。如果这个问题换一种说法,就是看守无意间说出了查尔斯不会死。那么概率就会发生改变。

类似的问题还有

  • 抛两枚硬币其中有一枚硬币是正面,问两枚硬币都是正面的概率是?
  • 抛两枚硬币其中第一枚硬币是正面,问两枚硬币都是正面的概率是?

the end.

参考:

  1. 蒙提霍尔问题 – 维基百科,自由的百科全书

  2. 三扇门问题 | 左岸读书

  3. 蒙提霍尔问题(又称三门问题、山羊汽车问题)的正解是什么?

  4. 趣味编程:三门问题

  5. 三门问题及相关

  6. 换还是不换?争议从未停止过的三门问题

  7. 在「三门问题」中,参与者应该选择「换」还是「不换」?主持人是否知道门后情形对结论有何影响?
  8. THE MONTY HALL PROBLEM
  9. 流言终结者第九季
  10. 某个家庭中有 2 个小孩,已知其中一个是女孩,则另一个是男孩的概率是多少?-知乎

2015-05-09 第一次撰写

原文:http://www.cnblogs.com/ruochenchen/p/4511579.html

Python: 深入Python流程控制

1. if 语句

# 求x的绝对值
x = int(input("Please enter an interge: >"))
if x < 0 :
    print(-x)
elif x == 0:
    print(0)
else:
    print(x) &#91;/code&#93;
<ol>
<li>
<b1>if</b1>或      <b1>elif</b1>后的条件语句没有括号,条件语句后接冒号。    </li>
<li>
<b1>if</b1>...      <b1>elif</b1>...      <b1>elif</b1>...序列用于替代其他语言中的      <b1>switch</b1>或      <b1>case</b1>语句。    </li>
</ol>
<h2>2. for 语句</h2>
<ol>
<li>
<p class="no-text-indent">
Python中的
for
语句依据任意序列(链表或字符串)中的子项,按它们在序列中的顺序来进行迭代。      </p>

a = ['cat', 'window', 'defenestrate']
for x in a:
    print(x, len(x)) 
  • 不要在遍历序列的同时,改变序列的大小,如果你非要这么做,那就在for循环时遍历序列的一个副本

    a = ['cat', 'window', 'defenestrate']
    for x in a[:]:
        if len(x) > 6:
            a.insert(0,x) 
  • 如果需要一个数值序列,内置函数
    range()
    会很方便,
    range(start,end,step)
    会按步长为step,生成一个[start, end)范围内的等差数列。

    a = ['Mary', 'had', 'a', 'litte', 'lamb']
    for i in range(len(a)):
        print(i, a[i]) 
  • 在序列循环时,索引位置与对应值可以使用
    enumerate()
    函数同时得到:

    a = ['Mary', 'had', 'a', 'litte', 'lamb']
    for i,v in enumerate(a):
        print(i,v) 
  • 在字典循环时,关键字与对应的值可以使用
    items()
    方法同时解读出来:

    knights = {'gallahad':'the pure', 'robin':'the brave'}
    for k,v in knights.items():
        print(k,v) 
  • 同时循环两个或更多的序列,可以使用
    zip()
    整体打包:

    question = ['name', 'quest', 'favorite color']
    answers = ['lancelot', 'the holy grail', 'blue']
    for q,a in zip(question, answers):
        print('What is your {0}? It is {1}.'.format(q,a)) 
  • 需要逆向循环的话,先正向定位序列,然后调用
    reversed()
    函数:

    for i in range(9,-1,-1):
        print(i,end = ',')
    for i in reversed(range(0,10)):
        print(i,end = ',') 
  • 需要按排序后的顺序循环序列的话,使用
    sorted()
    函数,它不会改动原序列,而是生成了一个新的已排序的序列:

    basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
    for fruit in sorted(set(basket)):
        print(fruit) 
  • 3. while 语句

    a,b = 0,1
    while b < 100:
        print(b,end=',')
        a,b = b,a+b

    4. break和continue语句,以及循环中的else语句

    breakcontinue语句与C语言中使用方法类似。

    循环中可以有一个 else子句;它在循环迭代完整个列表(对于 for)或执行条件为false(对于 while)时执行,但循环被 break中止的情况下不会执行。

    for i in range(0,10):
        print(i)
    else:
        print("end loop!>") 
    >>> for n in range(2, 10):
    ...     for x in range(2, n):
    ...         if n % x == 0:
    ...             print(n, 'equals', x, '*', n//x)
    ...             break
    ...     else:
    ...         # loop fell through without finding a factor
    ...         print(n, 'is a prime number')
    ...
    2 is a prime number
    3 is a prime number
    4 equals 2 * 2
    5 is a prime number
    6 equals 2 * 3
    7 is a prime number
    8 equals 2 * 4
    9 equals 3 * 3 

    上面这是正确的代码,看仔细: else语句是属于 for循环中的代码,而不是 if语句。

    5. 条件控制

    1. 比较运算符: innot in,以及 isis not
    2. 逻辑操作符: and、or not`

    6. 序列的比较

    序列对象可以与相同类型的其它对象比较。比较操作按 字典序 进行:首先比较前两个元素,如果不同,就决定了比较的结果;如果相同,就比较后两个元素,依此类推,直到所有序列都完成比较。如果两个元素本身就是同样类 型的序列,就递归字典序比较。如果两个序列的所有子项都相等,就认为序列相等。如果一个序列是另一个序列的初始子序列,较短的一个序列就小于另一个。字符 串的字典序按照单字符的 ASCII 顺序。下面是同类型序列之间比较的一些例子:

    (1, 2, 3) < (1, 2, 4) [1, 2, 3] < [1, 2, 4] 'ABC' < 'C' < 'Pascal' < 'Python' (1, 2, 3, 4) < (1, 2, 4) (1, 2) < (1, 2, -1) (1, 2, 3) == (1.0, 2.0, 3.0) (1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4) [/code] 原文:http://www.cnblogs.com/ronny/p/4511696.html

    Python: 深入Python函数定义

    在Python中,你也可以定义包含若干参数的函数。这里有三种可用的形式,也可以混合使用。

    1. 默认参数值

    最常用的一种形式是为一个或多个参数指定默认值。这会创建一个可以使用比定义时允许的参数更少的参数调用的函数,例如:

    def ask_ok(prompt, retries = 4, complaint = "Yes or no, please!>"):
    	while True:
    		ok = input(prompt)
    		if ok in ('y', 'ye', 'yes'):
    			return True
    		if ok in ('n' ,'no', 'nop', 'nope'):
    			return False
    		retries = retries - 1
    		if retries < 0:
    			raise IOError('refusenik user')
    		print(complaint)
     &#91;/code&#93;
    <p>这个函数可以通过几种不同的方式调用:</p>
    <ul>
    <li>
    只给出必要的参数:      <b1>ask_ok('Do you really wnat to quit?')</b1></li>
    <li>
    只给出一个可选的参数:      <b1>ask_ok('Ok to overwrite the file',2)</b1></li>
    <li>
    或者给出所有的参数:      <b1>ask_ok('OK to overwrite the file?',2,'Come on, only yes or no!'),</b1></li>
    </ul>
    <p>
    这个例子还介绍了    <b1>in</b1>关键字。它测定序列中是否包含某个确定的值:    <b1>ok in ('y', 'ye', 'yes')</b1></p>
    <p>默认值在函数定义作用被解析,如下所示:</p>
    <pre><code>i = 5
    def f(arg = i):
        print(arg)
    i = 6
    f()</code></pre>
    <p>
    将会输出    <b1>5</b1></p>
    <p>
    重要警告:默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)付给它的参数:  </p>
    
    def f(a, L = []):
        L.append(a)
        return L
    print(f(1))
    print(f(2))
    print(f(3)) 

    这将输出:

    [1]
    [1, 2]
    [1, 2, 3]

    如果你不想让默认值在后续调用中累积,你可以像下面一样定义函数:

    def f(a, L=None):
        if L is None:
            L = []
        L.append(a)
        return L 

    2. 关键字参数

    函数可以通过关键字参数的形式来调用,形如 keyword = value。例如:以下的函数:

    def parrot(voltage, state = 'a stiff', action = 'voom', type = 'Norwegian Blue'): 

    接受一个必选的参数( voltage)以及三个可选参数( state, actiontype)。可以用以下的任一方法调用:

    parrot(1000)
    parrot(voltage = 1000)
    parrot(voltage = 10000, action = 'VOOOM')
    parrot(action = 'VOOOOM', voltage = 1000) # action 写在前面也是OK的!
    parrot('a million', 'bereft of life', 'jump') # voltage = 'a milion'
    parrot('a thousand', state = 'pushing up the daisies') # voltage = 'a thousand' 

    不过以下几种调用是无效的:

    parrot() # voltage必须有值
    parrot(voltage = 5.0, 'dead') # 一旦有一个参数是通过关键字指定的,后面的也必须都是
    parrot(110, voltage = 220) # 两个voltage的值
    parrot(acotr = 'Jonh Cleese') # 没有voltage的值 

    通常,参数列表必须(先书写)位置参数然后才是关键字参数,这里关键字必须来自于形参名字。形参是否有一个默认值并不重要。任何参数都不能被多次赋值——在同一个调用中,与位置参数相同的形参名字不能用作关键字。

    引入一个形如 **name的参数时,它接收一个字典,该字典包含了所有未出现的形式参数中关键字参数。这里可能还会组合使用一个形如 *name的形式参数,它接收一个元组,包含了所有没有出现在形式参数列表中的参数值( *name必须出现在 **name之前)。例如,我们这样定义一个函数:

    def cheeseshop(kind, *arguments, **keywords):
    	print("-- Do you have any>", kind, "?>")
    	print("-- I'm sorry, we're all out of>", kind)
    	for arg in arguments:
    		print(arg)
    	print("->"*40) # 打印40个’-‘
    	keys = sorted(keywords.keys()) # 按键值排序
    	for kw in keys:
    		print(kw, ":>", keywords[kw])
     

    它可以像这样调用:

    cheeseshop("Limburger>", "It's very runny, sir.>",
               "It's really very, VERY runny, sir.>",
               shopkeeper="Michael Palin>",
               client="John Cleese>",
               sketch="Cheese Shop Sketch>") 

    3. 可变参数列表

    最后,一个最不常用的选择是可以让函数调用可变个数的参数。这些参数被包装进一个元组。在这些可变个数的参数之前,可以有零到多个普通的参数:

    def write_multiple_items(file, separator, *args):
        file.write(separator.join(args)) # 用separator符号将arg里的内容连在一起 

    通常这些可变参数是参数列表的最后一个,因为它们将所有剩余的输入参数传递给函数。任何出现在 args后的参数是关键字参数,这意味着,他们只能被用作关键字,而不是位置参数:

    >>> def concat(*args, sep="/>"):
    ...    return sep.join(args)
    ...
    >>> concat("earth>", "mars>", "venus>")
    'earth/mars/venus'
    >>> concat("earth>", "mars>", "venus>", sep=".>")
    'earth.mars.venus' 

    4. 参数列表的分拆

    另有一种相反的情况:当你要传递的参数已经是一个列表,但是要调用的函数却接受分开一个个的参数值,这时候你要把已有的列表拆开来,例如内建函数 range()需要两个独立的参数 range(start, end)。你可以在调用函数时加一个 *把已有的列表拆开:

    >>>list(range(3, 6))
    [3, 4 ,5]
    >>> args = [3, 6]
    >>> list(range(*args))
    [3, 4, 5] 

    以同样的方式,可以使用 **操作符分拆关键字参数为字典:

    >>> def parrot(voltage, state='a stiff', action='voom'):
    ...     print("-- This parrot wouldn't>", action, end=' ')
    ...     print("if you put>", voltage, "volts through it.>", end=' ')
    ...     print("E's>", state, "!>")
    ...
    >>> d = {"voltage>": "four million>", "state>": "bleedin' demised>", "action>": "VOOM>"}
    >>> parrot(**d)
    -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised ! 

    5. Lambda形式

    出于实际需要,有几种通常在函数式编程语言例如 Lisp 中出现的功能加入到了 Python。通过 lambda关键字,可以创建短小的匿名函数。这里有一个函数返回它的两个参数的和: lambda a, b: a+b。 Lambda 形式可以用于任何需要的函数对象。出于语法限制,它们只能有一个单独的表达式。语义上讲,它们只是普通函数定义中的一个语法技巧。类似于嵌套函数定义,lambda 形式可以从外部作用域引用变量:

    >>> def make_incrementor(n):
    ...     return lambda x: x + n
    ...
    >>> f = make_incrementor(42)
    >>> f(0)
    42
    >>> f(1)
    43 

    原文:http://www.cnblogs.com/ronny/p/4511747.html

    Python: 当你从头开发一个Python应用时,如何迈出第一步呢?

    本文出自《Python高手之路》中的Doug Hellmann访谈。

    我曾经有幸和Doug Hellmann一起工作过数月。他在DreamHost是一位非常资深的软件开发工程师,同时他也是OpenStack项目的贡献者。他发起过关于Python的网站Python Module of the Week(http://pymotw.com/),也出版过一本很有名的Pyhton书The Python Standard Library By Example(http://doughellmann.com/python-standard-library-by-example),同时他也是Python的核心开发人员。我曾经咨询过Doug关于标准库以及库的设计与应用等方面的问题。

    当你从头开发一个Python应用时,如何迈出第一步呢?它和开发一个已有的应用程序有什么不同?

    从抽象角度看步骤都差不多,但是细节上有所不同。相对于对比开发新项目和已有项目,我个人在对应用程序和库开发的处理方式上有更多的不同。

    当我要修改已有代码时,特别是这些代码是其他人创建的时,起初我需要研究代码是如何工作的,我需要改进哪些代码。我可能会添加日志或是输出语句,或是用pdb,利用测试数据运行应用程序,以便我理解它是如何工作的。我经常会做一些修改并测试它们,并在每次提交代码前添加可能的自动化测试。

    创建一个新应用时,我会采取相同的逐步探索方法。我先创建一些代码,然后手动运行它们,在这个功能可以基本调通后,再编写测试用例确保我已经覆盖了所有的边界情况。创建测试用例也可以让代码重构更容易。

    这正是smiley(https://pypi.python.org/pypi/smiley)的情况。在开发正式应用程序前,我先尝试用Python的trace API写一些临时脚本。对于smiley我最初的设想包括一个仪表盘并从另一个运行的应用程序收集数据,另一部分用来接收通过网络发送过来的数据并将其保存。在添加几个不同的报告功能的过程中,我意识到重放已收集的数据的过程和在一开始收集数据的过程基本是一样的。于是我重构了一些类,并针对数据收集,数据库访问和报告生成器创建了基类。通过让这些类遵循同样的API使我可以很容易地创建数据收集应用的一个版本,它可以直接将数据写入数据库而无需通过网络发送数据。

    当设计一个应用程序时,我会考虑用户界面是如何工作的,但对于库,我会专注于开发人员如何使用其API。通过先写测试代码而不是库代码,可以让思考如何通过这个新库开发应用程序变得更容易一点儿。我通常会以测试的方式创建一系列示例程序,然后依照其工作方式去构建这个库。

    我还发现,在写任何库的代码之前先写文档让我可以全面考虑功能和流程的使用,而不需要提交任何实现的细节。它还让我可以记录对于设计我所做出的选择,以便读者不仅可以理解如何使用这个库,还可以了解在创建它时我的期望是什么。这就是我用在stevedore上的方法。

    我知道我想让stevedore能够提供一组类用来管理应用程序的插件。在设计阶段,我花了些时间思考我见过的使用插件的通用模式,并且写了几页粗略的文档描述这些类应该如何使用。我意识到,如果我在类的构造函数中放最复杂的参数,方法map()几乎是可互换的。这些设计笔记直接写进了stevedore官方文档的简介里,用来解释在应用程序中使用插件的不同模式和准则。

    将一个模块加入Python标准库的流程是什么?

    完整的流程和规范可以在Python Developer’s Guide(http://docs.python.org/devguide/stdlibchanges.html)中找到。

    一个模块在被加入Python标准库之前,需要被证明是稳定且广泛使用的。模块需要提供的功能要么是很难正确实现的,要么是非常有用以至于许多开发人员已经创建了他们自己不同的变种。API应该非常清晰并且它的实现不能依赖任何标准库之外的库。

    提议一个新模块的第一步是在社区通过python-ideas邮件列表非正式地了解一下大家对此的感兴趣程度。如果回应很积极,下一步就是创建一个Python增强提案(PythonEnhancement Proposal,PEP),它包括添加这个模块的动因,以及如何过渡的一些实现细节。

    因为包的管理和发现工作已经非常稳定了,尤其是pip和Python Package Index(PyPI),因此在标准库之外维护一个新的库可能更实用。单独的发布使得对于新功能和bug修复(bugfix)的更新可以更频繁,对于处理新技术或API的库来说这尤其重要。

    标准库中的哪三个模块是你最想人们深入了解并开始使用的?

    最近我做了许多关于应用程序中动态加载扩展方面的工作。我使用abc模块为那些作为抽象基类进行的扩展定义API,以帮助扩展的作者们了解API的哪些方法是必需的,哪些是可选的。抽象基类已经在其他一些语言中内置了,但我发现很多Python程序员并不知道Python也有。

    bisect模块中的二分查找算法是个很好的例子,一个广泛使用但不容易正确实现的功能,因此它非常适合放到标准库中。我特别喜欢它可以搜索稀疏列表,且搜索的值可能并不在其中。

    collections模块中有许多有用的数据结构并没有得到广泛使用。我喜欢用namedtuple来创建一些小的像类一样的数据结构来保存数据但并不需要任何关联逻辑。如果之后需要添加逻辑的话,可以很容易将namedtuple转换成一个普通的类,因为namedtuple支持通过名字访问属性。另一个有意思的数据结构是ChainMap,它可以生成良好的层级命名空间。ChainMap能够用来为模板解析创建上下文或者通过清晰的流程定义来管理不同来源的配置。

    许多项目(包括OpenStack)或者外部库,会在标准库之上封装一层自己的抽象。例如,我特别想了解对于日期/时间的处理。对此你有什么建议吗?程序员应该坚持使用标准库,还是应该写他们自己的函数,切换到其他外部库或是开始给Python提交补丁?

    所有这些都可以。我倾向于避免重复造轮子,所以我强烈主张贡献补丁和改进那些能够用来作为依赖的项目。但是,有时创建另外的抽象并单独维护代码也是合理的,不管在应用程序内还是作为一个新的库。

    你提到的例子中,OpenStack里的timeutils模块就是对Python的datetime模块的一层很薄的封装。大部分功能都简短且简单,但通过将这些最常见的操作封装为一个模块,我们可以保证它们在OpenStack项目中以一致的方式进行处理。因为许多函数都是应用相关的,某种意义上它们强化了一些问题决策,例如,字符串时间戳格式或者“现在”意味着什么,它们不太适合作为Python标准库的补丁或者作为一个通用库发布以及被其他项目采用。

    与之相反,我目前正致力于将OpenStack的API服务项目从早期创建时使用的WSGI框架转成采用一个第三方Web开发框架。在Python中开发WSGI应用有很多选择,并且当我们可能需要增强其中一个以便其可以完全适应OpenStack API服务器的需要时,将这些可重用的修改贡献对于维护一个“私有的”框架似乎更可取。

    当从标准库或其他地方导入并使用大量模块时,关于该做什么你有什么特别的建议吗?

    我没有什么硬性限制,但是如果我有过多的导入时,我会重新考虑这个模块的设计并考虑将其拆到一个包中。与上层模块或者应用程序模块相比,对底层模块的这种拆分可能会发生得更快,因为对于上层模块我期望将更多片段组织在一起。

    关于Python 3,有什么模块是值得一提而且能令开发人员有兴趣深入了解的?

    支持Python 3的第三方库的数量已经到了决定性的时刻。针对Python 3开发新库或应用程序从未如此简单过,而且幸亏有3.3中加入的兼容性功能使同时维护对Python 2.7的支持也很容易。主要的Linux发行版正在致力于将Python 3默认安装。任何人要用Python创建新项目都应该认真考虑对Python 3的支持,除非有尚未移植的依赖。目前来说,不能运行在Python 3上的库基本会被视为“不再维护”。

    许多开发人员将所有的代码都写入到应用程序中,但有些情况下可能有必要将代码封装成一个库。关于设计、规划、迁移等,做这些最好的方式是什么?

    应用程序就是“胶水代码”的集合用来将库组织在一起完成特定目的。起初设计时可以将这些功能实现为一个库,然后在构建应用程序时确保库的代码能够很好地组织到逻辑单元中,这会让测试变得更简单。这还意味着应用程序的功能可以通过库进行访问,并且能够被重新组合以构建其他应用程序。未能采用这种方法的话意味着应用程序的功能和用户界面的绑定过于紧密,导致很难修改和重用。

    对于计划开始构建自己的Python库的人们有什么样的建议呢?

    我通常建议自顶向下设计库和API,对每一层应用单一职责原则(Single Responsibility Principle,SRP)(http://en.wikipedia.org/wiki/Single_responsibility_principle)这样的设计准则。考虑调用者如何使用这个库,并创建一个API去支持这些功能。考虑什么值可以存在一个实例中被方法使用,以及每个方法每次都要传入哪些值。最后,考虑实现以及是否底层的代码的组织应该不同于公共API。

    SQLAlchemy是应用这些原则的绝好例子。声明式ORM、数据映射和表达式生成层都是单独的。开发人员可以自行决定对于API访问的正确的抽象程度,并基于他们的需求而不是被库的设计强加的约束去使用这个库。

    当你随机看Python程序员的代码时遇到的最常见的编程错误是什么?

    Python的习惯用法和其他语言的一个较大的不同在于循环和迭代。例如,我见过的最常见的反模式是使用for循环过滤一个列表并将元素加入到一个新的列表中,然后再在第二个循环中处理这个结果(可能将列表作为参数传给一个函数)。我通常建议将过滤循环改成生成器表达式,因为生成器表达式,更有效也更容易理解。列表的组合也很常见,以便它们的内容可以以某种方式一起被处理,但却没有使用itertools.chain()。

    还有一些我在代码评审时给出的更细小的建议,例如,使用dict()而不是长的if:then:else块作为查找表,确保函数总是返回相同的类型(如一个空列表而不是None),通过使用元组和新类将相关的值合并到一个对象中从而减少函数的参数,以及在公共API中定义要使用的类而不是依赖于字典。

    有没有关于选择了一个“错误”的依赖的具体的例子是你亲身经历或目睹过的?

    最近,我有个例子,pyparsing(https://pypi.python.org/pypi/pyparsing)的一个新发布取消了对Python 2的支持,这给我正在维护的一个库带来了一点儿小麻烦。对pyparsing的更新是个重大的修改,而且是明确标识成这样的,但是因为我没有在对cliff(https://pypi.python.org/pypi/cliff)的设置中限制依赖版本号,所以pyparsing的新发布给cliff的用户造成了问题。解决方案就是在cliff的依赖列表中对Python 2和Python 3提供不同的版本边界。这种情况突显了理解依赖管理和确保持续集成测试中适当的测试配置的重要性。

    你怎么看待框架?

    框架像任何工具类型一样。它们确实有帮助,但在选择框架时要特别谨慎,应确保它能够很好地完成当前的工作。

    通过抽取公共部分到一个框架中,你可以将你的开发精力专注于应用中独特的方面。通过提供许多类似运行在开发模式或者写一个测试套件这样的引导代码,它们还可以帮你让一个应用程序迅速达到一个可用的状态而不是从头开发。它们还可以激励你在应用程序开发过程中保持一致,这意味着最终你的代码将更易于理解且更可重用。

    虽然使用框架时还有其他一些潜在的缺点需要注意。决定使用某个特定框架通常能够反映应用程序本身的设计。如果设计的限制不能从根本上符合应用程序的需求,那么选择错误的框架会令应用的实现变得更难。如果你试着使用与框架建议不同的模式或惯用方式,你最终将不得不同框架做斗争。

    长按二维码可以关注公众号

    《Python高手之路》,点击阅读原文可实现购买。

    阅读原文

    原文:http://www.jianshu.com/p/6e1d130bc589

    Python: PageRank算法浅介

    PageRank算法是互联网发展过程中的一个里程碑,斯坦福大学的两个博士生凭借这一发现构建了谷歌搜索,对整个互联网产生了巨大影响。

    PageRank让链接来”投票>”

    一个页面的“得票数”由所有链向它的页面的重要性来决定,到一个页面的超链接相当于对该页投一票。一个页面的PageRank是由所有链向它的页面(“链入页面”)的重要性经过递归算法得到的。一个有较多链入的页面会有较高的等级,相反如果一个页面没有任何链入页面,那么它没有等级。

    假設一個由4個頁面組成的小團體:A,B,C和D。如果所有頁面都鏈向A,那麼A的PR(PageRank)值將是B,C及D的Pagerank總和。

    $$PR(A)= PR(B) + PR(C) + PR(D)$$繼續假設B也有連結到C,並且D也有連結到包括A的3個頁面。一個頁面不能投票2次。所以B給每個頁面半票。以同樣的邏輯,D投出的票只有三分之一算到了A的PageRank上。

    $$PR(A)= \frac{PR(B)}{2}+ \frac{PR(C)}{1}+ \frac{PR(D)}{3}$$換句話說,根據鏈出總數平分一個頁面的PR值。

    $$PR(A)= \frac{PR(B)}{L(B)}+ \frac{PR(C)}{L(C)}+ \frac{PR(D)}{L(D)}$$最後,所有這些被換算為一個百分比再乘上一個係數d。由於「沒有向外連結的頁面」傳遞出去的PageRank會是0,所以,Google通過數學系統給了每個頁面一個最小值(1 – d)/N。其逻辑是对于网页A, 用户以d的概率随机选择这个网页A浏览;而以剩下的(1 – d)/N的概率从每一个网页跳转到这个网页A,具体如下:

    $$PR(A)=\left( \frac{PR(B)}{L(B)}+ \frac{PR(C)}{L(C)}+ \frac{PR(D)}{L(D)}+\,\cdots \right) d + \frac{1 – d}{N}$$

    采用d概率来刻画两种浏览行为有着更为实际的原因:防止投票泄露现象。d称之为阻尼系数(Damping factor)。在共振时,阻尼可能限制稳定振动的振幅。d在这里也可以起到平衡两种机制的作用。

    這個方程式引入了隨機瀏覽的概念,即有人上網無聊隨機打開一些頁面,點一些連結。一個頁面的PageRank值也影響了它被隨機瀏覽的機率。為了便於理解,這裡假設上網者不斷點網頁上的連結,最終到了一個沒有任何鏈出頁面的網頁,這時候上網者會隨機到另外的網頁開始瀏覽。

    為了處理那些「沒有向外連結的頁面」(這些頁面就像「黑洞」會吞噬掉用戶繼續向下瀏覽的機率)帶來的問題,d=0.85(這裡的d被稱為阻尼係數(damping factor),其意義是,在任意時刻,用戶到達某頁面後並繼續向後瀏覽的機率。1-d=0.15(就是用戶停止點擊,隨機跳到新URL的機率)的算法被用到了所有頁面上,估算頁面可能被上網者放入書籤的機率。

    所以,這個等式如下:

    $${\rm PageRank}(p_i) = \frac{1-d}{N} + d \sum_{p_j \in M(p_i)} \frac{{\rm PageRank} (p_j)}{L(p_j)}$$

    $p_1$, $p_2$, …, $p_N$是被研究的頁面,$M(p_i)$是鏈入$p_i$頁面的集合,$L(p_j)$ 是 $p_j$ 鏈出頁面的數量,而N是所有頁面的數量。

    PageRank值是一個特殊矩陣中的特徵向量。這個特徵向量為

    python程序模拟

    首先生成一个简单地网络:

    import  networkx  as  nx
    G  =  nx . DiGraph ()
    G . add_edge ( 'A' , 'B' )
    G . add_edge ( 'A' ,  'C' )
    G . add_edge ( 'B' , 'C' )
    G . add_edge ( 'C' , 'A' )
    pos = nx . spring_layout ( G )  #设置网络的布局
    nx . draw ( G ,  pos ,  node_color  =  'orange' ,  with_labels  =  True )  

    我们用PR表示网页排名(page rank, pr)。

    PR(A) = PR(C)

    PR(B) = PR(A)/2

    PR(C) = PR(A)/2 + PR(B)

    对于整个例子可以得到:PR(A) = PR(C) = 2*PR(B)

    设A、B、C的初始的重要性均为1,通过上面的方程组进行迭代,每次迭代后会更新A、B、C的重要性。为了方面,先把方程组转换为矩阵运算。

    PR(A) = 0*PR(A) + 0*PR(B) + PR(C)

    PR(B) = 0.5*PR(A) + 0*PR(B) + 0*PR(C)

    PR(C) = 0.5*PR(A) + PR(B) + 0*PR(C)

    import  numpy  as  np
    #第一个例子:无漏洞
    M  =  np . matrix ([[ 0 ,  0 ,  1 ],[ 0.5 ,  0 ,  0 ],[ 0.5 , 1 , 0 ]])
    PR =  np . matrix ([ 1 ,  1 ,  1 ]) . transpose ()
    for  i  in  range ( 1 , 101 ):
    PR  =  M * PR
    print  str ( i ) + ' \n ' ,  PR  

    但是这种简单地迭代有一个局限,就是当流量随着迭代不断流入一些节点时,这些流量不会再流出的时候,就会出现少数节点占有所有网页排名,其它节点排名为0的情况出现。一个极端的例子是:

    PR(A) = PR(B) + PR(C)

    import  numpy  as  np
    M  =  np . matrix ([[ 0 ,  1 ,  1 ],[ 0 ,  0 ,  0 ],[ 0 , 0 , 0 ]])
    PageRank =  np . matrix ([ 1 ,  1 ,  1 ]) . transpose
    for  i  in  range ( 1 , 101 ):
    PageRank  =  M * PageRank
    print  str ( i ) + ' \n ' ,  PageRank  

    此时,最终收敛的结果是:PR(A) = PR(B) = PR(C) = 0

    如上图中,最终所有的投票都集中在ABC三个节点上,其它节点收到的投票为0。随着迭代进行全部节点的得票都是0。因而,需要有一个平衡的调节机制,将那些只索取不奉献的节点的PageRank取一部分平均分配。

    import  numpy  as  np
    M  =  np . matrix ([[ 0 ,  1 ,  1 ],[ 0.5 ,  0 ,  0 ],[ 0.5 , 0 , 0 ]])
    PR  =  np . matrix ([ 1 ,  1 ,  1 ]) . transpose ()
    for  i  in  range ( 1 , 101 ):
    PR  =  0.15 / 3  +  0.85 * M * PR
    print  str ( i ) + ' \n ' ,  b  

    参考资料

    http://www.letiantian.me/2014-06-10-pagerank/

    http://www.letiantian.me/2014-12-01-text-rank/

    http://zh.wikipedia.org/wiki/PageRank

    Using your laptop to compute PageRank for millions of webpages

    Page, Lawrence and Brin, Sergey and Motwani, Rajeev and Winograd, Terry (1999) The PageRank Citation Ranking: Bringing Order to the Web. Technical Report. Stanford InfoLab.http://ilpubs.stanford.edu:8090/422/

    Date: 2015-05-18; Category:模型算法; Tags:

    原文:http://www.computational-communication.com/post/mo-xing-suan-fa/2015-05-18-pagerank

    Python: 提高Python运行效率的六个窍门

    提高Python运行效率的六个窍门

    曾灵敏 — MAY 18, 2015 Python是一门优秀的语言,它能让你在短时间内通过极少量代码就能完成许多操作。不仅如此,它还轻松支持多任务处理,比如多进程。

    不喜欢Python的人经常会吐嘈Python运行太慢。但是,事实并非如此。尝试以下六个窍门,来为你的Python应用提速。

    窍门一:关键代码使用外部功能包

    Python简化了许多编程任务,但是对于一些时间敏感的任务,它的表现经常不尽人意。使用C/C++或机器语言的外部功能包处理时间敏感任务,可以有效提高应用的运行效率。这些功能包往往依附于特定的平台,因此你要根据自己所用的平台选择合适的功能包。简而言之,这个窍门要你牺牲应用的可移植性以换取只有通过对底层主机的直接编程才能获得的运行效率。以下是一些你可以选择用来提升效率的功能包:

    • Cython
    • Pylnlne
    • PyPy
    • Pyrex

    这些功能包的用处各有不同。比如说,使用C语言的数据类型,可以使涉及内存操作的任务更高效或者更直观。Pyrex就能帮助Python延展出这样的功能。Pylnline能使你在Python应用中直接使用C代码。内联代码是独立编译的,但是它把所有编译文件都保存在某处,并能充分利用C语言提供的高效率。

    窍门二:在排序时使用键

    Python含有许多古老的排序规则,这些规则在你创建定制的排序方法时会占用很多时间,而这些排序方法运行时也会拖延程序实际的运行速度。最佳的排序方法其实是尽可能多地使用键和内置的sort()方法。譬如,拿下面的代码来说:

    import operator
    somelist = [(1, 5, 8), (6, 2, 4), (9, 7, 5)]
    somelist.sort(key=operator.itemgetter(0))
    somelist
    #Output = [(1, 5, 8), (6, 2, 4), (9, 7, 5)]
    somelist.sort(key=operator.itemgetter(1))
    somelist
    #Output = [(6, 2, 4), (1, 5, 8), (9, 7, 5)]
    somelist.sort(key=operator.itemgetter(2))
    somelist
    #Output = [(6, 2, 4), (9, 7, 5), (1, 5, 8)],
     

    在每段例子里,list都是根据你选择的用作关键参数的索引进行排序的。这个方法不仅对数值类型有效,还同样适用于字符串类型。

    窍门三:针对循环的优化

    每一种编程语言都强调最优化的循环方案。当使用Python时,你可以借助丰富的技巧让循环程序跑得更快。然而,开发者们经常遗忘的一个技巧是:尽量避免在循环中访问变量的属性。譬如,拿下面的代码来说:

    lowerlist = ['this', 'is', 'lowercase']
    upper = str.upper
    upperlist = []
    append = upperlist.append
    for word in lowerlist:
        append(upper(word))
        print(upperlist)
        #Output = ['THIS', 'IS', 'LOWERCASE']
     

    每次你调用str.upper, Python都会计算这个式子的值。然而,如果你把这个求值赋值给一个变量,那么求值的结果就能提前知道,Python程序就能运行得更快。因此,关键就是尽可能减小Python在循环中的工作量。因为Python解释执行的特性,在上面的例子中会大大减慢它的速度。

    (注意:优化循环的方法还有很多,这只是其中之一。比如,很多程序员会认为,列表推导式是提高循环速度的最佳方法。关键在于,优化循环方案是提高应用程序运行速度的上佳选择。)

    窍门四:使用较新的Python版本

    如果你在网上搜索Python,你会发现数不尽的信息都是关于如何升级Python版本。通常,每个版本的Python都会包含优化内容,使其运行速度优于之前的版本。但是,限制因素在于,你最喜欢的函数库有没有同步更新支持新的Python版本。与其争论函数库是否应该更新,关键在于新的Python版本是否足够高效来支持这一更新。

    你要保证自己的代码在新版本里还能运行。你需要使用新的函数库才能体验新的Python版本,然后你需要在做出关键性的改动时检查自己的应用。只有当你完成必要的修正之后,你才能体会新版本的不同。

    然而,如果你只是确保自己的应用在新版本中可以运行,你很可能会错过新版本提供的新特性。一旦你决定更新,请分析你的应用在新版本下的表现,并检查可能出问题的部分,然后优先针对这些部分应用新版本的特性。只有这样,用户才能在更新之初就觉察到应用性能的改观。

    窍门五:尝试多种编码方法

    每次创建应用时都使用同一种编码方法几乎无一例外会导致应用的运行效率不尽人意。可以在程序分析时尝试一些试验性的办法。譬如说,在处理字典中的数据项时,你既可以使用安全的方法,先确保数据项已经存在再进行更新,也可以直接对数据项进行更新,把不存在的数据项作为特例分开处理。请看下面第一段代码:

    n = 16
    myDict = {}
    for i in range(0, n):
    	char = 'abcd'[i%4]
    	if char not in myDict:
    		myDict[char] = 0
    		myDict[char] += 1
    		print(myDict)
     

    当一开始myDict为空时,这段代码会跑得比较快。然而,通常情况下,myDict填满了数据,至少填有大部分数据,这时换另一种方法会更有效率。

    n = 16
    myDict = {}
    for i in range(0, n):
        char = 'abcd'[i%4]
        try:
            myDict[char] += 1
        except KeyError:
            myDict[char] = 1
        print(myDict)
     

    在两种方法中输出结果都是一样的。区别在于输出是如何获得的。跳出常规的思维模式,创建新的编程技巧能使你的应用更有效率。

    窍门六:交叉编译你的应用

    开发者有时会忘记计算机其实并不理解用来创建现代应用程序的编程语言。计算机理解的是机器语言。为了运行你的应用,你借助一个应用将你所编的人类可读的代码转换成机器可读的代码。有时,你用一种诸如Python这样的语言编写应用,再以C++这样的语言运行你的应用,这在运行的角度来说,是可行的。关键在于,你想你的应用完成什么事情,而你的主机系统能提供什么样的资源。

    Nuitka是一款有趣的交叉编译器,能将你的Python代码转化成C++代码。这样,你就可以在native模式下执行自己的应用,而无需依赖于解释器程序。你会发现自己的应用运行效率有了较大的提高,但是这会因平台和任务的差异而有所不同。

    (注意: Nuitka现在还处在测试阶段,所以在实际应用中请多加注意。实际上,当下最好还是把它用于实验。此外,关于交叉编译是否为提高运行效率的最佳方法还存在讨论的空间。开发者已经使用交叉编译多年,用来提高应用的速度。记住,每一种解决办法都有利有弊,在把它用于生产环境之前请仔细权衡。)

    在使用交叉编译器时,记得确保它支持你所用的Python版本。Nuitka支持Python2.6, 2.7, 3.2和3.3。为了让解决方案生效,你需要一个Python解释器和一个C++编译器。Nuitka支持许多C++编译器,其中包括 Microsoft Visual Studio, MinGWClang/LLVM

    交叉编译可能造成一些严重问题。比如,在使用Nuitka时,你会发现即便是一个小程序也会消耗巨大的驱动空间。因为Nuitka借助一系列的动态链接库(DDLs)来执行Python的功能。因此,如果你用的是一个资源很有限的系统,这种方法或许不太可行。

    结论

    前文所述的六个窍门都能帮助你创建运行更有效率的Python应用。但是银弹是不存在的。上述的这些窍门不一定每次都能奏效。在特定的Python的版本下,有的窍门或许比其他的表现更好,但这有时候甚至取决于平台的差异。你需要总结分析你的应用,找到它效率低下的部分,然后尝试这些窍门,找到解决问题的最佳方法。

    本文作者系 OneAPM工程师李哲 ,想阅读更多好的 技术文章,请访问OneAPM官方技术博客。

    原文:http://www.ituring.com.cn/article/198284

    Python: python 实现每天产生一个日志文件

    与java apache log4j的ConsoleAppender,RollingFileAppender类似,python也有自己的实现,分别是logging.StreamHandler(),logging.handlers.TimedRotatingFileHandler.

    下面是示例代码:

    def script_path():
    	path = os.path.realpath(sys.argv[0])
    	if os.path.isfile(path):
    	path = os.path.dirname(path)
    	return os.path.abspath(path)
    LOGGING_MSG_FORMAT  = '[%(asctime)s] [%(levelname)s] [%(module)s] [%(funcName)s] [%(lineno)d] %(message)s'
    LOGGING_DATE_FORMAT	= '%Y-%m-%d %H:%M:%S'
    logging.basicConfig(level=logging.DEBUG,format=LOGGING_MSG_FORMAT,datefmt=LOGGING_DATE_FORMAT)
    log = logging.getLogger('xxx')
    log_path = os.path.join(script_path(),'logs')
    if not os.path.exists(log_path):
    	os.makedirs(log_path)
    log_file = os.path.join(log_path,'xxx.log')
    logger = logging.handlers.TimedRotatingFileHandler(log_file,'midnight',1)
    logger.setFormatter(logging.Formatter(LOGGING_MSG_FORMAT))
    log.addHandler(logger)
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    console.setFormatter(logging.Formatter(LOGGING_MSG_FORMAT))
    log.addHandler(console)
     

    注意事项:
    不要在多线程程序中使用addHandler,removeHandler,否则可能产生一些意想不到的异常
    。建议:
    全局只初始化一次logger实例

    原文:http://ucstudio.iteye.com/blog/2212447

    Python: python模块介绍-json:json编码解码

    目录

    JSON编码和解码

    JSON(),由(取代了RFC4627)和,是一种轻量级的数据交换格式,灵感来自对象文字语法(严格来说它不是JavaScript的子集,因为它额外支持了行分割U+2028和段分割U+2029语法)。

    simplejson的API和标准库marshal及pickle模块类似。它是包含在Python2.6的JSON库的外部版本,目前仍保持兼容的Python2.5并有显著的性能优势,尽管没有使用C扩展加速。 simplejson也支持Python的3.3+。

    simplejson的的发布下载地址:, 最新代码:

    • 编码基本的python对象层次
    >>>  import  simplejson  as  json
    >>>  json. dumps([ 'foo' ,  { 'bar' :  ( 'baz' ,  None ,  1.0 ,  2 )}])
    '["foo>", {"bar>": ["baz>", null, 1.0, 2]}]'
    >>>  print ( json. dumps( " \>" foo \b ar" ))
    >" \" foo \b ar>"
    >>>  print ( json. dumps( u' \u1234 ' ))
    " \u1234 >"
    >>>  print ( json. dumps( ' \\ ' ))
    " \\ >"
    >>>  print ( json. dumps({ "c>" :  0 ,  "b>" :  0 ,  "a>" :  0 },  sort_keys= True ))
    { "a>" :  0 ,  "b>" :  0 ,  "c>" :  0 }
    >>>  from  simplejson.compat  import  StringIO
    >>>  io =  StringIO()
    >>>  json. dump([ 'streaming API' ],  io)
    >>>  io. getvalue()
    '["streaming API>"]'  
    • 紧凑编码
    >>>  import  simplejson  as  json
    >>>  obj =  [ 1 , 2 , 3 ,{ '4' :  5 ,  '6' :  7 }]
    >>>  json. dumps( obj,  separators= ( ',' ,  ':' ),  sort_keys= True )
    '[1,2,3,{"4>":5,"6>":7}]'
    >>>  json. dumps( obj,   sort_keys= True )
    '[1, 2, 3, {"4>": 5, "6>": 7}]'  
    • 更好的输出
    >>>  import  simplejson  as  json
    >>>  print ( json. dumps({ '4' :  5 ,  '6' :  7 },  sort_keys= True ,  indent= 4  *  ' ' ))
    {
    "4>" :  5 ,
    "6>" :  7
    }  
    • 解码
    >>>  import  simplejson  as  json
    >>>  obj =  [ u'foo' ,  { u'bar' :  [ u'baz' ,  None ,  1.0 ,  2 ]}]
    >>>  json. loads( '["foo>", {"bar>":["baz>", null, 1.0, 2]}]' )  ==  obj
    True
    >>>  json. loads( '" \\ >"foo \\ bar"' )  ==  u'>"foo \x08 ar'
    True
    >>>  from  simplejson.compat  import  StringIO
    >>>  io =  StringIO( '["streaming API>"]' )
    >>>  json. load( io)[ 0 ]  ==  'streaming API'
    True  
    • 使用Decimal代替浮点数
    >>>  import  simplejson  as  json
    >>>  obj =  [ u'foo' ,  { u'bar' :  [ u'baz' ,  None ,  1.0 ,  2 ]}]
    >>>  json. loads( '["foo>", {"bar>":["baz>", null, 1.0, 2]}]' )  ==  obj
    True
    >>>  json. loads( '" \\ >"foo \\ bar"' )  ==  u'>"foo \x08 ar'
    True
    >>>  from  simplejson.compat  import  StringIO
    >>>  io =  StringIO( '["streaming API>"]' )
    >>>  json. load( io)[ 0 ]  ==  'streaming API'
    True  

    本文地址

    原文:http://automationtesting.sinaapp.com/blog/m_json

    Python: 一起写一个 Web 服务器

    还记的么,在第一部分Part 1我问过一个问题,“怎样在你的刚完成的WEB服务器下运行 Django 应用、Flask 应用和 Pyramid 应用?在不单独修改服务器来适应这些不同的 WEB 框架的情况下。”

    继续读,下面将会给出答案。在过去,你选择一个python web 框架将会限制web服务器的使用,反之亦然。 如果web框架和服务器被设计的一起工作,那么他们将没问题:

    但是,当你试图组合不是被设计的一起工作的一个web框架和一个web服务器时你可能已经遇到下面的问题:

    基本上,你必须使用一起工作的而不是你想要用的组合。

    所以,你怎么能确定你能跑你的web服务器兼容多个web框架的同时而又不用写代码来改变web服务器或者web框架?答案就是**Python Web Server Gateway Interface **(或者[WSGI] (https://www.python.org/dev/peps/pep-0333/) 作为简写, 发音 “wizgy”).

    WSGI 允许开发者分别选择web框架和web服务器。现在你们混合使用匹配的web框架和服务器来满足你的需求。你能跑  Django, Flask, 或者 Pyramid, 例如, 使用 Gunicorn 或者 Nginx/uWSGI 又或者 Waitress. 真的混合且匹配这要归功于 WSGI 既支持服务器有支持框架:

    所以, WSGI  是第一部分我问的问题的答案  Part 1 也在文章最开始提到。你的web服务器必须实现WSGI的服务端接口,现在所有的python web 框架已经实现了WSGI的框架端接口 , 这允许你使用它们而不需修改代码来适配一个特殊的web框架。 现在你知道了WSGI 支持 Web servers 和 Web frameworks 允许你选择一个匹配的组合,这也得利于服务端和框架开发者因为它们能集中于它们想关注的方面.其他语言有类似的接口 : 例如Java, 有 Servlet API 同时Ruby 有 Rack. 这都没问题,你可能会说: “给我展示你的代码!”好的,看一下这个完美的最小 WSGI 服务器实现:

    # Tested with Python 2.7.9, Linux & Mac OS X

    import socket

    import StringIO

    import sys

    class WSGIServer(object):

    address_family = socket.AF_INET

    socket_type = socket.SOCK_STREAM

    request_queue_size = 1

    def __init__(self, server_address):

    # Create a listening socket

    self.listen_socket = listen_socket = socket.socket(

    self.address_family,

    self.socket_type

    )

    # Allow to reuse the same address

    listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    # Bind

    listen_socket.bind(server_address)

    # Activate

    listen_socket.listen(self.request_queue_size)

    # Get server host name and port

    host, port = self.listen_socket.getsockname()[:2]

    self.server_name = socket.getfqdn(host)

    self.server_port = port

    # Return headers set by Web framework/Web application

    self.headers_set = []

    def set_app(self, application):

    self.application = application

    def serve_forever(self):

    listen_socket = self.listen_socket

    [1]  [2] [3] [4]  下一页

    原文:http://www.myhack58.com/Article/sort099/sort0100/2015/62603.htm

    Python: Python|绝不乱入的靠谱书单

    初、中、高级的读者,都可以在这里找到满意的答案。1、2、3、4中高级阅读,5、6扩展阅读。7、8、9入门级阅读。10,思维拓展阅读。

    中、高级——Python高手之路

    [法] 朱利安•丹乔(Julien Danjou) (作者)

    王飞龙 (译者)

    书 号 978-7-115-38713-4

    出版日期 2015-05-01

    页 数 202

    本书英文原版配套网址是 https://julien.danjou.info/books/the-hacker-guide-to-python

    这不是一本常规意义上Python的入门书。这本书中没有Python关键字和for循环的使用,也没有细致入微的标准库介绍,而是完全从实战的角度出发,对构建一个完整的Python应用所需掌握的知识进行了系统而完整的介绍。更为难得的是,本书的作者是开源项目OpenStack的PTL(项目技术负责人)之一,因此本书结合了Python在OpenStack中的应用进行讲解,非常具有实战指导意义。

    中、高级——PythonCookbook(第3版)中文版

    [美]David Beazley , [美]Brian K.Jones (作者)

    陈舸 (译者)

    书 号 978-7-115-37959-7

    出版日期 2015-05-01

    页 数 684

    《Python Cookbook(第3版)中文版》介绍了Python应用在各个领域中的一些使用技巧和方法,其主题涵盖了数据结构和算法,字符串和文本,数字、日期和时间,迭代器和生成器,文件和I/O,数据编码与处理,函数,类与对象,元编程,模块和包,网络和Web编程,并发,实用脚本和系统管理,测试、调试以及异常,C语言扩展等。

    本书覆盖了Python应用中的很多常见问题,并提出了通用的解决方案。书中包含了大量实用的编程技巧和示例代码,并在Python 3.3环境下进行了测试,可以很方便地应用到实际项目中去。此外,《Python Cookbook(第3版)中文版》还详细讲解了解决方案是如何工作的,以及为什么能够工作。

    《Python Cookbook(第3版)中文版》非常适合具有一定编程基础的Python程序员阅读参考。

    进 阶——Python核心编程(第二版)

    [美]Wesley J. Chun (作者)

    宋吉广 (译者)

    书 号 978-7-115-17850-3

    出版日期 2008-07-01

    页 数 654

    本书是经典的Python指导书,在第一版的基础上进行了全面升级。全书分为两个部分:第1部分占据了大约三分之二的篇幅,阐释这门语言的“核心”内容,包括基本的概念和语句、语法和风格、Python对象、数字类型、序列类型、映射和集合类型、条件和循环、文件和输入/输出、错

    误和异常、函数和函数式编程、模块、面向对象编程、执行环境等内容:第2部分则提供了各种高级主题来展示可以使用Python做些什么,包括正则表达式、网络编程、网络客户端编程、多线程编程、图形用户界面编程、Web编程、数据库编程、扩展Python 和一些其他材料。

    进 阶——Python3程序开发指南(第2版修订版)

    [英]Mark Summerfield (作者)

    王弘博 , 孙传庆 (译者)

    书 号 978-7-115-38338-9

    出版日期 2015-01-01

    页 数 518

    《Python 3程序开发指南(第2版 修订版)》首先讲述了构成Python语言的8个关键要素,之后分章节对其进行了详尽的阐述,包括数据类型、控制结构与函数、模块、文件处理、调试、进程与线程、网络、数据库、正则表达式、GUI程序设计等各个方面,并介绍了其他一些相关主题。全书内容以实例讲解为主线,每章后面附有练习题,便于读者更好地理解和掌握所讲述的内容。

    《Python 3程序开发指南(第2版 修订版)》适合于作为Python语言教科书使用,对Python程序设计人员也有一定的参考价值。

    中、 高级——Python数据可视化编程实战

    [爱尔兰]Igor Milovanović (作者)

    颛青山 (译者)

    书 号 978-7-115-38439-3

    出版日期 2015-05-01

    页 数 242

    本书是一本使用Python实现数据可视化编程的实战指南,介绍了如何使用Python最流行的库,通过60余种方法创建美观的数据可视化效果。

    全书共8章,分别介绍了准备工作环境、了解数据、绘制并定制化图表、学习更多图表和定制化、创建3D可视化图表、用图像和地图绘制图表、使用正确的图表理解数据以及更多matplotlib知识。

    本书适合那些对Python编程有一定基础的开发人员,可以帮助读者从头开始了解数据、数据格式、数据可视化,并学会使用Python可视化数据。

    扩展阅读——Python自然语言处理

    [美]Steven Bird , [美]Ewan Klein , [美]Edward Loper

    (作者) 陈涛 , 张旭 , 崔杨 , 刘海平 (译者)

    书 号 978-7-115-33368-1

    出版日期 2014-07-01

    页 数 487

    《Python自然语言处理》是自然语言处理领域的一本实用入门指南,旨在帮助读者学习如何编写程序来分析书面语言。《Python自然语言处理》基于Python编程语言以及一个名为NLTK的自然语言工具包的开源库,但并不要求读者有Python编程的经验。全书共11章,按照难易程度顺序编排。第1章到第3章介绍了语言处理的基础,讲述如何使用小的Python程序分析感兴趣的文本信息。第4章讨论结构化程序设计,以巩固前面几章中介绍的编程要点。第5章到第7章介绍语言处理的基本原理,包括标注、分类和信息提取等。第8章到第10章介绍了句子解析、句法结构识别和句意表达方法。第11章介绍了如何有效管理语言数据。后记部分简要讨论了NLP领域的过去和未来。

    《Python自然语言处理》的实践性很强,包括上百个实际可用的例子和分级练习。《Python自然语言处理》可供读者用于自学,也可以作为自然语言处理或计算语言学课程的教科书,还可以作为人工智能、文本挖掘、语料库语言学等课程的补充读物。

    扩展阅读——贝叶斯思维统计建模的Python学习法

    [美]Allen B. Downey (作者)

    许杨毅 (译者)

    书 号 978-7-115-38428-7

    出版日期 2015-03-01

    页 数 168

    这本书帮助那些希望用数学工具解决实际问题的人们,仅有的要求可能就是懂一点概率知识和程序设计。而贝叶斯方法是一种常见的利用概率学知识去解决不确定性问题的数学方法,对于一个计算机专业的人士,应当熟悉其应用在诸如机器翻译,语音识别,垃圾邮件检测等常见的计算机问题领域。

    可是本书实际上会远远扩大你的视野,即使不是一个计算机专业的人士,你也可以看到在战争环境下(二战德军坦克问题),法律问题上(肾肿瘤的假设验证),体育博彩领域(棕熊队和加人队NFL比赛问题)贝叶斯方法的威力。怎么从有限的信息判断德军装甲部队的规模,你所支持的球队有多大可能赢得冠军,在《龙与地下城》勇士中,你应当对游戏角色属性的最大值有什么样的期望,甚至在普通的彩弹射击游戏中,拥有一些贝叶斯思维也能帮助到你提高游戏水平。

    除此以外,本书在共计15章的篇幅中讨论了怎样解决十几个现实生活中的实际问题。在这些问题的解决过程中,作者还潜移默化的帮助读者形成了建模决策的方法论,建模误差和数值误差怎么取舍,怎样为具体问题建立数学模型,如何抓住问题中的主要矛盾(模型中的关键参数),再一步一步的优化或者验证模型的有效性或者局限性。在这个意义上,这本书又是一本关于数学建模的成功样本。

    入 门——趣学Python——教孩子学编程

    [美]Jason R. Briggs (作者)

    哲 (译者)

    书 号 978-7-115-38143-9

    出版日期 2015-02-01

    页 数 280

    本书是一本轻松、快速掌握Python编程的入门读物。全书分为3部分,共18章。第1部分是第1章到第12章,介绍Python编程基础知识,包括Python的安装和配置、变量、字符串、列表、元组和字典、条件语句、循环语句函数和模块、类、内建函数和绘图,等等。第2部分是第13章和第14章,介绍如何用Python开发实例游戏弹球。第3部分包括第15章到第18章,介绍了火柴人实例游戏的开发过程。

    本书语言轻松,通俗易懂,讲解由浅入深,力求将读者阅读和学习的难度降到最低。任何对计算机编程有兴趣的人或者首次接触编程的人,不论孩子还是成人,都可以通过阅读本书来学习Python编程。

    入 门 —— “笨办法”学Python(第3版) 【Learn Python hard way】

    [美]Zed A. Shaw (作者)

    王巍巍 (译者)

    书 号 978-7-115-35054-1

    出版日期 2014-11-01

    页 数 249

    《“笨办法”学Python(第3版)》是一本Python入门书籍,适合对计算机了解不多,没有学过编程,但对编程感兴趣的读者学习使用。这本书以习题的方式引导读者一步一步学习编程,从简单的打印一直讲到完整项目的实现,让初学者从基础的编程技术入手,最终体验到软件开发的基本过程。

    《“笨办法”学Python(第3版)》结构非常简单,共包括52个习题,其中26个覆盖了输入/输出、变量和函数三个主题,另外26个覆盖了一些比较高级的话题,如条件判断、循环、类和对象、代码测试及项目的实现等。每一章的格式基本相同,以代码习题开始,按照说明编写代码,运行并检查结果,然后再做附加练习。

    入 门 —— Python入门经典

    [美]Katie Cunningham (作者)

    李军 , 李强 (译者)

    书 号 978-7-115-36209-4

    出版日期 2014-10-01

    页 数 235

    《Python入门经典》是面向Python初学者的学习指南,详细介绍了Python编程基础,以及一些高级概念,如面向对象编程。全书分为24章。第1章介绍了Python的背景和安装方法。第2章到第7章介绍了一些基本的编程概念,如变量、数学运算、字符串和获取输入。第8章到第12章介绍了更高级的主题,讨论了函数、字典和面向对象编程等。第13章到第15章介绍了如何使用库和模块,以及如何创建自己的模块。第16章到第19章介绍了使用数据,如保存到文件,使用标准格式以及使用数据库。第20章和第21章尝试了标准库以外的一些项目,在这两章中,介绍了创建动态Web站点和开发游戏。这两章并不是要成为完整的课程,而是充当学习更多知识的一个起点。第22章和第23章介绍了如何正确地保存代码,以及出错的时候如何找到解决方案。第24章介绍了读者可能会接触到哪些项目,哪些资源可以帮助读者学习更多知识,以及如何更深入地融入Python社区。

    思维拓展——像计算机科学家一样思考Python

    [美]Allen B. Downey (作者)

    赵普明 (译者)

    书 号 978-7-115-32092-6

    出版日期 2013-08-01

    页 数 328

    《像计算机科学家一样思考Python》按照培养读者像计算机科学家一样的思维方式的思路来教授Python语言编程。全书贯穿的主体是如何思考、设计、开发的方法,而具体的编程语言,只是提供一个具体场景方便介绍的媒介。《像计算机科学家一样思考Python》并不是一本介绍语言的书,而是一本介绍编程思想的书。和其他编程设计语言书籍不同,它不拘泥于语言细节,而是尝试从初学者的角度出发,用生动的示例和丰富的练习来引导读者渐入佳境。

    原文:http://www.jianshu.com/p/587442bd4522

    Python: Spark 学习笔记

    Spark 学习笔记

    Spark作为分布式系统框架的后起之秀(据说)各方面都要优于hadoop,有本地缓存,原生支持潮潮的scala, 对python的支持强大到直接可以用ipython notebook 作为交互界面。 还有几个正在开发中的分支框架分别用于机器学习和社交网络分析,简直华丽的飞起。

    安装

    根据阿帕奇基金会的尿性,应该是没有所谓的安装一说的,下载,解压就能使用了,当然不要忘了设置环境变量,具体不啰嗦.

    使用

    spark全面支持scala和java,部分支持python。好在scala也是脚本语言,所以相对比hadoop方便的多,先来看看两种交互模式。

    pyspark

    命令行使用 pyspark以后terminal中就会出现个大大SPARK图案和熟悉的python默认交互界面,这太丑了有啥更优秀的没?

    利用 PYSPARK_DRIVER_PYTHON=ipython ./bin/pyspark呼出ipython交互界面,这个比原来的好多了。

    利用

     PYSPARK_DRIVER_PYTHON=ipython PYSPARK_DRIVER_PYTHON_OPTS="notebook --pylab inline>" pyspark
     

    调用ipython notebook

    随便进去个试试示例的程序,还是用WordCount好了

    file = sc.textFile("hdfs://localhost:9000/user/huangsizhe/input/README.md>")
    count = file.flatMap(lambda line: line.split()).map(lambda word: (word, 1)).reduceByKey(lambda a, b: a+b)
    count.saveAsTextFile("hdfs://localhost:9000/user/huangsizhe/wc>")
     

    成功输出~

    对了,为了避免hadoop警告建议把native lib 屏蔽了

    spark-shell

    这个是最常用的工具了,开发语言是scala,scala的话可以用脚本也可以编译执行,我觉得还是脚本方便

    使用写的脚本方法是

    $spark-shell -i XXX.scala
    

    这样就会一条一条的执行了

    还是WordCount

    WordCount.scala放在$SPARKPATH/scala目录下

    val file = sc.textFile("hdfs://localhost:9000/user/huangsizhe/input/README.md>")
    val counts = file.flatMap(line => line.split(" >")).map(word => (word, 1)).reduceByKey(_ + _)
    counts.saveAsTextFile("hdfs://localhost:9000/user/huangsizhe/wc>")
     

    执行

    $spark-shell -i WordCount.scala
    

    成功!

    spark-submit

    这个就有点像hadoop了,一般用于写app,可以使用python,java,scala来写程序,python不用编译, java需要用maven编译成jar文件,scala也需要用sbt编译成jar文件。

    python例子:

    文件结构如下

    WordCountpy |
                |-input
                |-script|
                        |-WordCount.py
    

    WordCount.py如下

    import sys
    from operator import add
    from pyspark import SparkContext
    if __name__ == "__main__>":
    	if len(sys.argv) != 3:
    		print >> sys.stderr, "Usage: wordcount <input> <output>>"
    		exit(-1)
    	sc = SparkContext(appName="PythonWordCount>")
    	lines = sc.textFile(sys.argv[1], 1)
    	counts = lines.flatMap(lambda x: x.split(' ')) \
    				  .map(lambda x: (x, 1)) \
    				  .reduceByKey(add)
    	output = counts.collect()
    	for (word, count) in output:
    		print "%s: %i>" % (word, count)
    	counts.saveAsTextFile(sys.argv[2])
    	sc.stop()
     

    cd 到WordCount项目根目录下运行: spark-submit –master local[4] script/WordCount.py input/TheMostDistantWayInTheWorld.txt output 然后就会多出一个output文件夹,里面存有结果~

    scala例子

    java的我就不写了。。。

    scala例子文件结构如下: WordCountScala | |-input| | |-TheMostDistantWayInTheWorld.txt | |-src| | |-wordcountApp.scala | |-wordcountAPP.sbt

    wordcountApp.scala如下

    import org.apache.spark.SparkContext
    import org.apache.spark.SparkContext._
    import org.apache.spark.SparkConf
    object WordCountApp {
        def main(args: Array[String]) {
    	if (args.length < 2) {
    	  System.err.println("Usage: WordCountApp <input> <output>>")
    	  System.exit(1)
    	}
    	val conf = new SparkConf().setAppName("WordCountAPP>")
    	val sc = new SparkContext(conf)
    	val file = sc.textFile(args(0))
    	val counts = file.flatMap(line => line.split(" >")).map(word => (word,1)).reduceByKey(_+_)
    	println(counts)
    	counts.saveAsTextFile(args(1))
    	}
        }
     

    wordcountAPP.sbt如下:

    name := "wordcount>"
    version := "1.0>"
    scalaVersion := "2.10.4>"
    libraryDependencies += "org.apache.spark>" %% "spark-core>" % "1.2.0>"
     

    编译:

    cd 到 WordCountScala项目文件夹下

    $ find .
    $ sbt package
    

    编译成功你编译完的程序就在 target/scala-2.10/simple-project_2.10-1.0.jar

    运行:

    spark-submit   --class "WordCountApp>"  \
     --master local[4]   \
     target/scala-2.10/wordcount_2.10-1.0.jar input/TheMostDistantWayInTheWorld.txt output
     

    你就能看到output了

    Streaming spark的流式计算系统

    这个stream很牛,实时运算,似乎是strom的替代品,试试官方例子 Networkwordcount.py

    import sys
    from pyspark import SparkContext
    from pyspark.streaming import StreamingContext
    if __name__ == "__main__>":
    	if len(sys.argv) != 3:
    		print >> sys.stderr, "Usage: network_wordcount.py <hostname> <port>>"
    		exit(-1)
    	sc = SparkContext(appName="PythonStreamingNetworkWordCount>")
    	ssc = StreamingContext(sc, 1)
    	lines = ssc.socketTextStream(sys.argv[1], int(sys.argv[2]))
    	counts = lines.flatMap(lambda line: line.split(" >"))\
    				  .map(lambda word: (word, 1))\
    				  .reduceByKey(lambda a, b: a+b)
    	counts.pprint()
    	ssc.start()
    	ssc.awaitTermination()
     

    运行

    1. nc -lk 9999打开端口监听
    2. 新开个terminal,cd 到该脚本所在地址 spark-submit network_wordcount.py localhost 9999
    3. 在nc -lk 那个terminal下输入句子试试~ 可以在另一个terminal中看到每次回车后该行的单词次数~

    原文:http://www.ituring.com.cn/article/198895

    Python: 新浪云的基本配置

    新浪云的基本配置

    python应用基本步骤

    咱以一个helloworld来做例子部署一个flask应用

    先在新浪云上新建个app

    1. 在个人账户下新建一个app
    2. cd到希望新建app文件本地库的地方 执行 svn co https://svn.sinaapp.com/app名字 这样可以在目录下新建一个名为app名字的空文件夹。 过程中首先会要求输入本地当前账户的密码,然后输入安全邮箱作为user 安全密码作为password

    本地调试代码

    1. 可以在app本地库里面新建一个数字1到10间命名的文件夹,该数字就是这个app 的版本。默认版本为1
    2. 创建配置文件
      config.yaml
      内容如下:

      name: helloworld
      version: 1
      
    3. 创建启动文件
      index.wsgi
      内容如下:

      import sae
      from myapp import app
      application = sae.create_wsgi_app(app)
       
    4. 创建主体文件
      myapp.py
      内容如下:

      from flask import Flask,render_template
      app = Flask(__name__)
      @app.route('/')
      def index():
      	return render_template('index.html')
      @app.route('/user/<name>')
      def user(name):
      	return render_template('user.html', name=name)
      if __name__ == '__main__':
      	app.run(debug=True)
       
    5. 新建一个叫
      templates
      的文件夹,用来放两个html文件:

    其中 index.html内容如下:

        

    hello!

    user.html内容如下:

        

    hello,{{ name }}!

    于是你的文件结构如下:

    	 appname|
    			  |-1|
    				  |-config.yaml
    				  |-index.wsgi
    				  |-myapp.py
    				  |-templates|
    								 |-index.html
    								 |-user.html
     

    现在本地试下

    shell里cd到1下, python myapp.py然后打开浏览器,地址栏输入 localhost:5000看看报错不

    好了上传到sae吧~

    cd到你的项目本地库,执行

        svn add ./
    

    然后

        svn commit -m "描述的话>"
    

    这样就算完成了

    常用的svn命令

    • svn co path/ svn checkout path–用来对path目标仓库在本地建立本地库及对应working copy(wp)
    • svn add path–用来将本地库中的文件添加到wp
    • svn delete path–删除wp中的文件
    • svn commit -m “XXX>”–把你WC的更改提交到仓库
    • svn update–更新仓库版本

    原文:http://www.ituring.com.cn/article/198896

    Python: 64位Win7下编译Python3的计算机视觉库:OpenCV

    注:本文全原创,作者:ZMAN  ( http://www.cnblogs.com/zmanone/)

    OpenCV目前最新版是3.0.0 rc1,官方给出了编译好的Python2可以直接使用的cv2.pyd,可我想在Python3下用啊!只能硬着头皮自己编译了,Mingw编译到最后一步失败了,最终使用visual studio 2012编译成功,过程分享如下:

    (注①:本步骤适用于WIN7 64位操作系统,Python版本为3.4.3 64bit,OpenCV版本为 3.0.0 rc1,我的CUDA版本是5.5)

    (注②:请确保安装了numpy!!)

    1. 安装Visual Studio 2012。 (链接: http://pan.baidu.com/s/1nt65Oet 密码: asiu 序列号:YKCW6-BPFPF-BT8C9-7DCTH-QXGWC)

    2. 安装CMake。(链接: http://pan.baidu.com/s/1c0EVLfE 密码: mxqf)

    3. 下载opencv源码。解压到任意位置,比如我的是 “D:/opencvcode>”  (链接: http://pan.baidu.com/s/1gdvSHuN 密码: fabq)

    (可选)下载opencv的扩展modules包。解压到任意位置,比如我的是 “D:/opencv_contrib-master>”  (链接: http://pan.baidu.com/s/1c0tqZ9A 密码: ee71)

    4. 修改代码。

    ① 打开 “D:\opencvcode\sources\modules\python\src2\hdr_parser.py>”。

    第4行,把 codecs 库也import进来;第737行改为 “f = codecs.open(hname, >”r”, >”utf-8″)>” 。

    ② 打开 “D:\opencvcode\sources\cmake\OpenCVCompilerOptions.cmake>”。

    把第67行 “add_extra_compiler_option(-Werror=non-virtual-dtor)>”注释掉(最前面加个注释符:#) 。

    ③ 打开 “D:\opencvcode\sources\modules\python\common.cmake>”。

    在第27行”# header blacklist>”下增加一行:ocv_list_filterout(opencv_hdrs “detection_based_tracker>”) 。

    5. 编译源代码。

    ① 打开CMake(gui), “where is the source code>”定位到 “D:/opencvcode/sources>” 目录,”where to build the binaries>”定位到任意输出文件夹,比如我的是 “D:/opencv1>”。

    ② 勾选”Grouped>”和”Advanced>”。

    ③ 点击”Configure>”,确定,编译器选择”Visual Studio 2012 Win64>”。

    ④ 确保 勾选了 “BUILD -> BUILD_opencv_python3>”, 不要勾选 “WITH -> WITH_IPP>”, 请检查 “PYTHON3>”下各种PATH、DIR、LIBRARY的路径是不是正确。

    不要勾选 “BUILD_opencv_line_descriptor>” 和 “saliency>”。(暂时不清楚这两个库干嘛用的,但是我勾选了line_descriptor后总是无法成功编译)

    ⑥  “OPENCV -> OPENCV_EXTRA_MODULES_PATH>” 定位到 “D:/opencv_contrib-master/modules>”。

    ⑦ 再次点击”Configure>”,确保没有红色背景色的选项后,点击 “Generate>”。

    6. BUILD代码。

    ① 进入 “D:/opencv1>”,打开 “OpenCV.sln>”。

    ② 切换到 “Release>”模式后,右键 “解决方案’OpenCV’”选择“重新生成解决方案”,接下来是漫长的等待,如果最后显示失败个数是0,就成功啦!

    7. 设置环境变量。

    ① 把 “D:/opencv1/bin/Release>”目录加入环境变量,把 “D:/opencv1/lib/Release/cv2.pyd>”复制到你的Python目录内的 “site-packages>”文件夹下。

    8. 品尝成功的喜悦。

    ① 在Python中,运行如下代码:

    import  cv2
     import  numpy
     #  读入图像
    im = cv2.imread(' C:/Users/Public/Pictures/Sample Pictures/Koala.jpg ' )
     #  下采样
    im_lowres = cv2.pyrDown(im)
     #  转化为灰度图像
    gray = cv2.cvtColor(im_lowres, cv2.COLOR_RGB2GRAY)
     #  检测特征点
    s  = cv2.xfeatures2d.SURF_create()
     # s = cv2.SURF()
    mask = numpy.uint8(numpy.ones(gray.shape))
    keypoints  = s.detect(gray, mask)
     #  显示图像及特征点
    vis = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
     for  k in  keypoints[::10]:
    	cv2.circle(vis, (int(k.pt[0]), int(k.pt[ 1])), 2, (0, 255, 0), -1)
    	cv2.circle(vis, (int(k.pt[0]), int(k.pt[ 1])), int(k.size), (0, 255, 0), 2)
    cv2.imshow( ' local descriptors ' , vis)
    cv2.waitKey()
    cv2.imwrite( ' C:/Users/Public/Pictures/Sample Pictures/Koala2.jpg ' ,vis)
     

    ② duang~跳出来一张这样的考拉图片就说明成功啦!!

    原文:http://www.cnblogs.com/zmanone/p/4532842.html

    Python: Python中关于类和函数的初体验之"__init__"和"__str__"不是"_init_"和"_str_"

    刚刚接触Python,今天就是怎么也调试不过去了,上网上查直到晚上才查到一个有效信息,真是坑啊!原来Python中的这些“魔法”方法的命名里就有陷阱……

    上图中的那两个红圈圈,一定要记住哦,这些Python自带的方法,比如str和init前后都是两个”_>”,写一个”_>”按F5运行肯定有问题!

    拿我的同事猫脸屁做个类,因为他最烦人,所以我学习的时候也会带着他(二次元击打松尾芭蕉桑):

     1  import time
      2  def GetNowYear():
      3  return  time.strftime(" %Y >" ,time.localtime(time.time()))
      4
     5  class  PiCat:
      6      def __init__(self,name,age):
      7          self.name = name
      8          self.age = age
      9      def __str__(self):
     10          msg = " Hi, I'm  >" + self.name + " , I'm  >"  + str(self.age) +"  years old. >"
    11  return  msg
     12
    13  mlp = PiCat(" Lianpi Mao >" ,int (GetNowYear())-1990 )
     14
    15  print mlp.name
     16  print mlp 

    这个程序很简单,就是让猫脸屁说一下自己的名字,并做一下自我介绍。

    坑的就是那两个”_>”啊!!!

    是 __str__ 而不是 _str_ !!!

    是 __init__ 而不是 _init_ !!!

    原文:http://www.cnblogs.com/LanTianYou/p/4534142.html

    Python: Python 3.5.0b1 发布,面向对象编程语言

    #深圳# 6月10日 亚马逊AWSome Day云计算免费培训报名中

    Python 3.5.0b1 发布,此版本主要有以下更新:

    • PEP 448, additional unpacking generalizations
    • PEP 461, adding support for “%-formatting>” for bytes and bytearray objects
    • PEP 465, a new operator (@) for matrix multiplication
    • PEP 471, os.scandir(), a faster alternative to os.walk()
    • PEP 475, adding support for automatic retries of interrupted system calls
    • PEP 479, change StopIteration handling inside generators
    • PEP 484, the typing module, a new standard for type annotations
    • PEP 486, making the Windows Python launcher aware of virtual environments
    • PEP 488, eliminating .pyo files
    • PEP 489, multi-phase extension module initialization
    • PEP 492, coroutines with async and await syntax

    详细信息请查看 更新日志

    Python 3.5 现在 已经进入 “功能 冻结 ” 阶段。在 默认情况下, 新功能可能不再被加入到 Python 3.5 中。

    预知更多有关 Python 3.5.0b1 信息,请查看 发行页面

    Python(发音:[ ‘paiθ(ə)n; (US) ‘paiθɔn ]n.蟒蛇,巨蛇 ),是一种面向对象的解释性的计算机程序设计语言,也是一种功能强大而完善的通用型语言,已经具有十多年的发展历史,成熟且稳定。Python 具有脚本语言中最丰富和强大的类库,足以支持绝大多数日常应用。

    原文:http://www.oschina.net/news/62820/python-3-5-0b1-released

    Python: 开启Python学习之旅

    据说Python是最适合iOS开发者学习的语言没有之一,可以写一些脚本来提高开发效率。我就看到过一位朋友利用Python写了很多工具。

    来,用Python写一句代码吧!

    print “Hello world !>”

    编译一下控制台会输出:

    Hello world !

    我用的是CodeRunner,这个工具是收费的,不过在天朝你肯定能搞到免费的。如果你是在搞不到没关系,告诉你一个可以免费获取的方法:

    关注微信公众号: 猿圈 (ID: CodePush ) (←长按复制)

    关注成功之后回复:CodeRunner 即可下载CodeRunner啦!

    学习Python语法有一个不错的学习网站:https://pythonspot.com/beginner/

    来看看我写的几句Python

    x = 3

    f = 3.141529

    name = “Python>”

    big = 358315791L

    z = complex(2,3)

    print x

    print f

    print name

    print big

    print z

    x = 3

    y = 8

    sum = x + y

    print sum

    编译一下控制台会输出:

    3

    3.141529

    Python

    358315791

    (2+3j)

    11

    还可以让用户输入:

    x = int(raw_input(“Enter x :>”))

    y = int(raw_input(“Enter y :>”))

    sum = x + y

    print sum

    用户输入两个数字,然后求和。

    想学习Python的童鞋,赶紧开始行动吧!

    猿圈 (ID: CodePush ) (←长按复制)

    为程序员提供最优质的博文、最精彩的讨论、最实用的开发资源;提供最新最全的编程学习资料:PHP、Objective-C、Java、Swift、C/C++函数库、.NET Framework类库、J2SE API等等。并不定期奉送各种福利。

    (复制微信号,搜索公众号即可关注)

    原文:http://mp.weixin.qq.com/s?__biz=MzA3NzM0NzkxMQ==&mid=206502335&idx=2&sn=37d46aef2f42377afe124210de7dc9a8&3rd=MzA3MDU4NTYzMw==&scene=6#rd

    Python: python模块介绍-PyAutoGUI:PyAutoGUI中文文档

    目录

    virtualenv用来创建隔离的Python环境。python中不同模块可能以来某一模块的不同版本,此时virtualenv就可以派上用场。它创建拥有独立安装目录的隔离python环境。本文基于linux,与标准文档相比略有简化。

    安装

    建议安装的virtualenv-1.9或更高版本。1.9以下的版本,virtualenv中的pip不支持在PyPI上通过SSL下载。

    建议使用pip 1.3或更高版本安装virtualenv。pip1.3以下的版本不支持在PyPI上通过SSL下载。同样的道理,easy_install要求0.9.7或以上的版本。

    • 安装发布版本:“pip install virtualenv”
    • 源码安装:
    $  curl - O https: // pypi. python. org/ packages/ source/ v/ virtualenv/ virtualenv- X. X. tar. gz
    $  tar xvfz virtualenv- X. X. tar. gz
    $  cd virtualenv- X. X
    $  [ sudo]  python setup. py install 
    • 不安装,绿色使用:
    $  curl - O https: // pypi. python. org/ packages/ source/ v/ virtualenv/ virtualenv- X. X. tar. gz
    $  tar xvfz virtualenv- X. X. tar. gz
    $  cd virtualenv- X. X
    $  python virtualenv. py myVE 

    在已安装virtualenv的情况下,可以直接运行 virtualenv ENV 。

    该操作会创建 ENV/lib/pythonX.X/site-packages 目录 和 ENV/bin/python , 前者用来存放要安装的模块,后者就是隔离环境的Python解释器。 在virtualenv环境下使用此解释器(包括以 #!/path/to/ENV/bin/python 开头的脚本)时,使用的都是隔离环境下的模块。

    该操作还在隔离环境下安装了 Setuptools 或 distribute 。要用Distribue取代setuptools的话,只要运行:

    本文地址

    原文:http://automationtesting.sinaapp.com/blog/m_PyAutoGUI_doc

    Python: 对我影响最大的图灵书

    从大学开始正式接触计算机科学和软件开发,到现在进入工作也有6年多时间了,这期间买过、借过、蹭过的书不少。但我是个

    脑子不好

    忘性很大的人,大部分书是看过就忘,或者当时需要用到什么技术,才找针对性的书来看。所以现在回想起来,也就能记得几个常看的出版社,具体的书名,倒是遗忘得差不多了。

    不过既然本文写的就是对我影响最大的图灵书,那么就不扯废话了,直接切入主题。不过说实在,图灵出版的好书 太多,如果要只评出一本难免辜负了,况且前面也说了,很多好书我看过之后随着时间流逝也忘记了,所以一番思量,还是就从 最近看过的书里,找几本对我影响很大的分别写一写吧。

    首先是编程语言部分,基础之基础,对于本人这样立志在软件行业以开发者身份求生活的人,不掌握几门编程语言,实在难以安身立命。不得不说,进入工作之后,留给自己学习的时间是越来越少了。甚至因为工作需要,学习新语言,最多也只有一个周的时间,这时候,一本靠谱的入门书籍可以节省大量时间和精力。因为目前手上的工作是以 Python 开发为主,所以在这里要说到的是 《Python 基础教程(第2版●修订版)》这本书。说起来这本书还是在 图灵读者群里,一位朋友赠送给我的。这本书是一本非常详细的 Python 入门教材,每个知识点都配有相应的代码示例。并且在书的最后几章是几个实际的小型项目,充分利用了前面基础知识中讲解到的内容,将理论和实践结合得很好。认真吃透这本书,写 Python 如有神。在 编程语言方面,近期对我影响最大的图灵书,莫过于这本 《Python 基础教程(第2版●修订版)》

    接下来,学习了基本的语言之后,就可以投入实际的开发工作中去了。但是术业有专攻,并且对于开发者来说,自己的能力和精力也是有限的。好在有无数前辈为我们铺平了道路。根据项目需求,选择一个合适的框架进行开发是现在软件开发时的不二之选。这里既然说到的是 Python,再加上我目前的工作是进行 Web 开发,那么就有两个绕不开的框架: Django & Flask。就我个人而言,更喜欢 Flask 这样的微框架。它为开发者提供了充分的自由发挥空间——灵活——是这个框架带给我的最大感受。而相应的,一份系统又详尽的指南,能够让你再充分利用 Flask 的灵活性的同时,不至于迷失方向。 《Flask Web开发:基于Python的Web应用开发实战》就是这样一本指南性的教程。有的人推荐啃官方文档,而我自己实际经历下来,官方文档更适合做为知识点的查询,还是这本书更加适合系统的学习 Flask 框架。这本书分为三个部分:

    • 第一部分通过开发小模块、小功能来进行知识点的讲解,前后章节互相结合,即时反馈让学习过程不再枯燥无味;

    • 第二部分通过重构之前已完成的代码并加入新功能,从而实现了一个社交博客的实例项目,学习者在完成这一部分学习的过程中,也同步的完整的经历了一个实际项目从零开始到完成开发的全部流程,在这个过程中,学习者不光学习到了 Flask 的知识,也基本掌握了一个项目的规划、结构、开发流程等等一系列软件工程领域的技能;

    • 第三部分中,学习者会学习到如何针对第二部分完成的博客程序进行测试、调优、部署等工作。至此,学习者已经完成了从 Flask框架入门者到 项目开发熟练者的蜕变。

    通过这本书的学习,不光可以掌握 Flask框架 的知识,更重要的是亲历了一个项目的 完整研发过程,这样全面的收获,我相信单纯啃官方文档是无法获得的。可以说,从 工程开发的角度, 《Flask Web开发:基于Python的Web应用开发实战》这本书是这段时间对我影响最大的图灵书。

    说完了实际学习和开发的东西,咱们也不忘补一补精神食粮。这里我推荐大家阅读 《编程人生 15位软件先驱访谈录》。这本书通过采访15位业界先驱和大牛,让我们能够一窥前辈的成长之路。榜样的力量是巨大的,通过向先驱们学习,了解前辈们的成长路线,可以更好的作为自己的学习和发展乃至职业生涯规划的参考。同时,吸收他们在行业内的多年经验,提升自己,无疑好过自己花费大量时间去摸索探路。对于现在的我来说, 《编程人生 15位软件先驱访谈录》是在 自我激励和精神指引方面对我影响最大的图灵书。

    一时间也想不到更多,毕竟

    脑容量较小

    很多好书我看过就忘了,只能回忆起到最近一段时间内看过的印象深刻的几本书了。不过人生那么长,遇到更好的书,对我影响更大的书的机会还有很多,图灵出版社每年引进、翻译、出版的经典也不少。所以,这里提到几本书,其实也只是对自己阶段性学习和阅读的一个总结而已。希望未来的自己能充分吸收这些经典中的知识,在技术领域做出自己的一份成果。(完)

    原文:http://www.ituring.com.cn/article/198303

    Python: python bottle使用多个端口(多个进程)提高并发

    我的程序是用python结合bottle框架写的,但bottle自带wsgi原本只是单进程单线程运行模式(Bottle 默认运行在内置的 wsgiref 服务器上面。这个单线程的 HTTP 服务器在开发的时候特别有用,但其性能低下,在服务器负载不断增加的时候也许会是性能瓶颈, 一次只能响应一个请求)。为了提升程序的处理能力,首先要启用多线程,即在程序中使用gevent( 大多数服务器的线程池都限制了线程池中线程的数量,避免创建和切换线程的代价。尽管和进程 (fork)比起来,线程还是挺便宜的。但是也没便宜到可以接受为每一个请求创建一个线程。gevent 模块添加了 greenlet 的支持。 greenlet 和传统的线程类似,但其创建只需消耗很少的资源。基于 gevent 的服务器可以生成成千上万的 greenlet,为每个连接分配一个 greenlet 也毫无压力。阻塞greenlet,也不会影响到服务器接受新的请求。同时处理的连接数理论上是没有限制的。)。只需要在run中加上 server=’gevent’,如下:

    1 import<span> gevent
    2 from gevent import<span>  monkey.patch_all()
    3 <span>      代码段……
    4 run(host='0.0.0.0', port=8080, server='gevent')    

    尽管使用了多线程模式,但这些线程都是跑在一个进程里,所以需要开启多个进程来进一步提升并发处理能力,因此在启用脚本的时候,在run(port=)里,端口号不能写死,应该使用变量来传递,如下代码(在脚本执行时,在需带一个参数,这个参数是大于1024的整数,否则报错停止脚本):

    import<span> gevent,sys
    from gevent import<span>  monkey.patch_all()
    #获取端口号
    try<span>:
    	portnum = int(sys.argv[1<span>])
    except<span> Exception,e:
    	print "请带上整数类型的端口号启动此程序>"<span>
    	logging.error("请带上整数类型的端口号启动此程序>"<span>)
    	sys.exit(1<span>)
    if portnum <= 1024<span>:
    	print "端口号请大于1024!>"<span>
    	logging.error("端口号请大于1024!>"<span>)
    	sys.exit(1<span>)
    	  代码段……
    run(host='0.0.0.0', port=portnum , server='gevent'<span>)
     

    执行方式如下(osyw.py是我python程序名):

    python osyw.py 1124

    如果纯靠手动操作这些,在生产上,很不方便,所以我写了个shell来管理,这个shell定义了多个端口号,然后去循环启用或停止python进程,脚本大概如下(是用httpd改写的):

    #!/bin/bash
    #
    # osyw	Startup script for the osyw HTTP Server
    #
    # chkconfig: - 88 18
    # description: osyw
    # processname: osyw
    # config:
    # config: /home/bottle/osyw/
    # pidfile: /var/run/osyw.pid
    #
    ### BEGIN INIT INFO
    # Provides: osyw
    # Short-Description: start and stop osyw HTTP Server
    # Description: The osyw HTTP Server is an extensible server
    #  implementing the current HTTP standards.
    ### END INIT INFO
    # Source function library.
    . /etc/rc.d/init.d/<span>functions
    # Path to the apachectl script, server binary, and short-form for messages.
    port_list=(8811 8812 8813)     #设置了3个端口
    #pidfile='/var/run/osyw.pid'
    pro_path='/var/www/osyw/osyw.py'    #程序路径
    log_path='/var/www/osyw/log/access.log'    #访问日志路径
    RETVAL=<span>0
    start() {
    	for i in ${port_list[*<span>]}
    	do
    		p=`/usr/sbin/lsof -i :${i} |wc -<span>l`
    		if [ ${p} -ge 2<span> ]
    		then
    			action "osyw ${i} already exists !>" /bin/<span>false
    		else
    			/usr/bin/python ${pro_path} ${i} &>><span> ${log_path}
    		RETVAL=<span>$?
    			if [ ${RETVAL} ==<span> 0 ]
    			then
    				action "osyw ${i} start ...>" /bin/<span>true
    			else<span>
    				action "osyw ${i} start ...>" /bin/<span>false
    			fi
    		fi
    	done
        return<span> $RETVAL
    }
    stop() {
    	for i in ${port_list[*<span>]}
    	do
    		pidfile="/var/run/osyw_${i}.pid>"
    		if [ -<span>f ${pidfile} ]
    		then
    			pid=<span>`cat ${pidfile}`
    			kill -9<span> ${pid}
    			RETVAL=<span>$?
    			if [ ${RETVAL} ==<span> 0 ]
    		    then
    		    action  "osyw ${i} stop ...>" /bin/<span>true
    		    else<span>
    		    action  "osyw ${i} stop ...>" /bin/<span>false
    			fi
    			rm -<span>f ${pidfile}
    		else<span>
    			action  "osyw ${i} Has stopped !>" /bin/<span>false
    		fi
    	done
    }
    # See how we were called.
    case "$1>" in<span>
      start)
    	start
    	;;
      stop)
    	stop
    	;;
      status)
    	status -p ${pidfile} 'osyw'<span>
    	RETVAL=<span>$?
    	;;
      restart)
    	stop
    	sleep 2<span>
    	start
    	;;
      condrestart|try-<span>restart)
    	if status -p ${pidfile} 'osyw' >&/dev/<span>null; then
    		stop
    		start
    	fi
    	;;
      force-reload|<span>reload)
    	reload
    	;;
      *<span>)
    	echo $"Usage: $prog {start|stop|restart|condrestart|try-restart|force-reload|reload|status|fullstatus|graceful|help|configtest}>"<span>
    	RETVAL=2<span>
    esac
    exit $RETVAL
     

    效果图:

    本人的代码是用svn管理的,所以上传代码后,SVN钩子会调用shell脚本来重启这些程序,以下是SVN钩子代码:

    export LANG=en_US.UTF-8
    /usr/bin/svn update --username xxxx --password xxxxxxxx /var/<span>bottle
    /bin/bash /etc/init.d/osyw restart  

    当然,为了结合shell,python程序里也要做一些处理,如自动把程序转为后台守护进程,然后把进程ID写入文件,以下是关键的python代码:

    #定义PID路径
    pid_path = '/var/run/osyw_%s.pid' %<span> portnum
    def<span> daemonize():
    	">""把本脚本转为守护进程>"">"
    	try<span>:
    		pid=<span>os.fork()
    		if pid><span>0:
    			sys.exit(0)
    	except<span> Exception,e:
    		logging.error(e)
    		sys.exit(1<span>)
    	os.chdir('/'<span>)
    	os.umask(0)
    	os.setsid()
    	try<span>:
    		pid=<span>os.fork()
    		if pid><span>0:
    			sys.exit(0)
    	except<span> Exception,e:
    		logging.error(e)
    		sys.exit(1<span>)
    	PID =<span> str(os.getpid())
    	with open(pid_path,'w'<span>) as f:
    		f.write(PID)
    其它代码段……
    if __name__ == '__main__'<span>:
    	try<span>:
    		from oscore import setting	#导入配置文件
    		if setting.status == 'online':	#如果配置中是线上的,则程序转入后台运行
    <span>			daemonize()
    	except<span> Exception:
    		pass<span>
    	app =<span> default_app()
    	app = SessionMiddleware(app, session_opts)	  #sessionMiddleware是session插件
    	run(app=app,host='0.0.0.0', port=portnum,server='gevent')
     

    最好,用nginx代理来负载这些端口,我nginx和python程序是安装在同一台服务器上的:

    以上是nginx反向代理的部分代码:

    <span>upstream myweb {
    #ip_hash;
    server 192.168.1.240:8811 weight=4 max_fails=2 fail_timeout=<span>30s;
    server 192.168.1.240:8812 weight=4 max_fails=2 fail_timeout=<span>30s;
    server 192.168.1.240:8813 weight=4 max_fails=2 fail_timeout=<span>30s;
    }
    server {
    	listen	   80<span>;
    		server_name  192.168.1.240<span>;
    	location /<span>
    		{
    		proxy_pass http://<span>myweb;
    		proxy_set_header Host  $host;
    		proxy_set_header X-Forwarded-<span>For  $remote_addr;
    		proxy_cache_key $host$uri$is_args$args;
    		}
    		access_log  off;
    		}
     

    做完这些后,当访问80端口时,nginx就会平均轮洵分配到每个端口上去,实现了多进程,多线程的运行模式,更有效的提升了并发处理能力

    原文:http://www.cnblogs.com/drfdai/p/4518121.html

    Python: 使用python将json存入数据库

    任务描述:

    需要将python的json字符串存到数据库中,还要保证读取出来后,能解析成字典,中间不会发生任何转义或者改变。

    而对于pickle生成的序列化对象,操作过程是一样的。

    使用到的python库有 json, MySQLdb

    要点1:

    我们要保证,存储格式json的类型是BLOB类型的

    1  ` json `  blob  NOT  NULL  COMMENT  'json' ,  

    要点2:

    使用”包裹此字段,format成insert语句,我没试过不包裹的后果是啥,一般而言字符串都是需要引号包裹的,反正我包起来是没问题的。

    1  tsql  =  "INSERT INTO xxx(`json`, ...)VALUES('{json}', ....)>"  

    要点3:

    要使用MySQLdb.escape_string函数,来对json字符串进行escape

    1  sql  =  tsql . format ( json = MySQLdb . escape_string ( json ),  .... )  

    要点4:

    查询出来的结果使用json.loads()就ok了。 for .. , data in cursor.fetchall(): print …, json.loads(data)

    原文:http://www.pulpcode.cn/program-language/2015/05/21/insert-json-to-mysql-with-python/

    Python: RabbitMQ(python实现)学习之一:简单两点传输“Hello World”的实现

    一.基本配置

    注意 RabbitMQ支持python、Java、Ruby、PHP、C#等语言的支持,本博客主要是针对python讲解。本博客安装配置是基于ubuntu系统的。

    1.1安装配置epel源

    $ rpm -Uvh http://dl.fedoraproject.org/pub/ ... ease-6 -8 .noarch.rpm 

    1.2安装erlang

    $: yum -y install erlang  或者
    $:sudo apt -get install erlang 

    1.3安装rabbitmq-server

    $: yum -y install rabbitmq-server 或者
    $: sudo apt -get install rabbitmq-server 

    1.4启动/停止rabbitmq-server

    $: sudo service rabbitmq-server start
    $: sudo service rabbitmq -server stop 

    1.5安装RabbitMQ libraries

    RabbitMQ遵循AMQP协议,为了使用rabbitmq,你需要一个库来解读这个协议,对于python来说,你需要安装下面库函数中的任意一个即可:

    >py-amqplib
     >txAMQP
     >pika 

    本博文以pika库为例,安装如下:

    $:sudo pip install pika==0.9.8 或者
    $:sudo apt-get install pika==0.9.8

    注意:以下内容是在rabbitmq-server启动,运行在标准端口5672的前提下进行的。

    二.对 英文版 的翻译

    2.1简介

    RabbitMQ相当于一个消息代理,他完成接收和转发消息的功能,你可以把它想成一个邮局,起到中转作用。RabbitMQ会用到一些专业术语,如下:

    >Producer:用来发送消息的程序被称为一个producer,我们用‘P’表示:

    >Queue:队列,相当于邮箱的作用,他在创建后一直存活与RabbitMQ中,虽然消息可以在你的程序之间流动,但是在这中间的过程中,消息必须存在queue中,一下queue没有大小限制,你可以存无数的消息, (前提你必须预留1GB的硬盘空间) ,他就相当于一个没有限制的缓存。多个Producer可以发送消息到同一个queue,多个Consumer也可以从同一个queue中接收消息。一个queue可以用下面的图表示,图的上面是queue的名字。

    >Consumer:一个用来接收消息的程序称之为Consumer,我们用下面的图表示:

    注意,对于Producer和Consumer可以不在同一台host上面,后续博文会做介绍。

    2.2两点传输“Hello World!”

    需要两个程序,一个用来发送“Hello World!”,一个程序用来接收“Hello World!”并打印到屏幕上面。模型如下:

    我们创建一个名字为hello的queue。Producer发送消息到hello的queue,Consumer从名为hello的queue中接收消息。

    2.3sending(发送代码实现)

    模型如下:

    首先我们需要编写一个send.py程序,这个程序将向queue中发送一个消息,第一件事,我们要做的就是与rabbitmq-server建立连接,代码如下:

    import  pika
    connection  = pika.BlockingConnection(pika.ConnectionParameters(host=' localhost ' ))
    channel  = connection.channel() 

    如果我们想与不同的host建立连接,只需将‘localhost’换成IP地址。

    接下来,我们需要确定接纳消息的queue的存在,如果我们把消息发送给不存在的queue,那么rabbitmq自动将消息丢弃,让我们创建一个消息队列queue,命名为‘hello’

    channel.queue_declare(queue=' hello ' ) 

    在Rabbitmq中,一个消息不能直接发送给queue, 需要经过一个exchange,后续博文会讲到 ,现在我们只需将exchange设置为空字符串。

    exchange很特别,他会识别我们的消息要发送给哪个消息队列queue,queue的名字需要用routing_key来标识,exchange通过routing_key确定消息发送至哪个消息队列queue。代码如下:

    channel.basic_publish(exchange='' ,routing_key=' hello ' ,body=' Hello World! ' )
     print  " [X] Sent 'Hello World!' >"  

    在退出程序之前,我们需要清理缓存,并且确定我们的消息“Hello World!”真的发送给RabbitMQ了,我们可以通过关闭连接来完成,代码如下:

    connection.close()

    完整的send.py的代码如下:

    import  pika
    connection  = pika.BlockingConnection(pika.ConnectionParameters(
    	host =' localhost ' ))
    channel  = connection.channel()
    channel.queue_declare(queue =' hello ' )
    channel.basic_publish(exchange ='' ,
    		      routing_key =' hello ' ,
    		      body =' Hello World! ' )
     print  "  [x] Sent 'Hello World!' >"
    connection.close()
     

    2.4Receiving(接收代码实现)

    模型如下所示:

    我们的接收程序receive.py将接收消息,并将它打印在屏幕上。

    同样首先,我们需要与rabbitmq-server建立连接,代码和send.py基本一致,代码如下:

    import  pika
    connection  = pika.BlockingConnection(pika.ConnectionParameters(host=' localhost ' ))
    channel =connection.channel() 

    接下来,和前面一样,要确定去队列queue的存在,用queue_declare()创建队列,对于这个命令我们可以运行很多次,但只有一个名字为hello的queue存在。代码如下:

    channel.queue_declare(queue=' hello ' ) 

    或许你会问,为什么我们要再次创建名字为hello的queue,前面我们已经建立了啊,当然,如果我们确定队列queue已经存在了,我们可以不加这段代码。例如,如果send.py程序在之前已经运行过了,但是我们不确定哪个程序时先运行的,这时候,我们在两个程序中同时声明queue就是必须的。

    对于receive.py,我们要定义一个callback函数,在我们接受到消息的时候,pika库会调用callback函数,在我们的程序里,callback函数就是将接收到的消息打印在屏幕上。函数代码如下:

    def  callback(ch,method,properties,body):
         print " [x] Received %r >"  %(body) 

    接下来我们需要告诉Rabbitmq,这个特殊的函数callback()的功能,就是从hello的queue中接收消息,代码如下:

    channel.basic_consume(callback,queue=' hello ' ,no_ack=True) 

    对于代码中的 no_ack,后续的博客会提到。

    最后,我们开启一个永不停止的线程来等待消息,在需要的时候运行callback()函数。代码如下:

    print  ' [*] Waiting for message. To exit press CTRL+C '
    channel.start_consuming()
      

    完整的receive.py的代码如下:

    import  pika
    connection  = pika.BlockingConnection(pika.ConnectionParameters(
    	host =' localhost ' ))
    channel  = connection.channel()
    channel.queue_declare(queue =' hello ' )
     print  '  [*] Waiting for messages. To exit press CTRL+C '
    def  callback(ch, method, properties, body):
         print  "  [x] Received %r >"  % (body,)
    channel.basic_consume(callback,
    		      queue =' hello ' ,
    		      no_ack =True)
    channel.start_consuming()
     

    2.5代码测试

    首先打开一个命令行窗口,运行send.py代码,运行及结果如下:

    $ :python send.py
     [x] Sent  ' Hello World! '  

    send.py每次运行完就停止,接下来让我们运行接收的代码receive.py,运行及结果如下:

     $: python receive.py
     [ *] Waiting for  messages. To exit press CTRL+C
     [x] Received  ' Hello World! '  

    你会看到,received.py运行起来后,不会停止,一直在那等待消息的传入,如果想停止,CTRL+C。

    在一个新命令行窗口中继续运行send.py,运行receive.py的命令行窗口会继续输出相应信息。

    2.6部分rabbitmq-server的命令行操作命令

    1)查看各个queue的名称以及queue中的消息数

    $: sudo rabbitmqctl list_queues

    例如

    $: sudo rabbitmqctl list_queues
    Listing queues ...
    hello    0
    ...done.  

    2)查看各exchange的名称

    $: sudo rabbitmqctl list_exchanges

    原文:http://www.cnblogs.com/likailiche/p/4509209.html

    Python: 深入Python模块的使用

    1. 模块的导入

    import file_name可以导入当前目录上file_name.py这个模块,但是里面的内容,必须通过file_name.func/file_name.var 来访问。

    另外一种导入方式为 import func/var from file_name。这样func/var直接可用,但是file_name是没有定义的。

    从file_name中导入所有: import * from file_name。这样会导入所有除了以下划线开头的命名。实际代码中这样做往往是不被鼓励的。

    如果你一直在某个环境,比如解释器下面,你已经导入过某个模块 ,现在你对模块进行了修改,这里你需要用reload(modulename)来重新载入。

    模块中的主函数:

    if __name__ == "__main__>":
        import sys
        fib(int(sys.argv[1])) 

    2. 模块的搜索路径

    首先会搜索解析器的当前目录。然后会到sys.path变量中给出的目录列表中查找。

    >>> import sys
    >>> sys.path
    ['', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages'] 
    1. 输入脚 本的目录(当前目录)
    2. 环境变量 PYTHONPATH表示的目录列表中搜索
    3. Ptyon的默认安装路径中搜索。

    3. 内置模块

    dir()函数返回模块内的所有定义,无参数时, dir()返回当前解释器中定义的命名。

    >>> import fibo
    >>> dir(fibo)
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fib', 'fib2']
    >>> dir()
    ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'fibo'] 

    dir()并不会列出内置函数和变量名。如果你想列出这些内容,它们在标准模块 __builtin__中定义。

    4. 包

    当不同作的模块进行按文件夹分类后再组成一个整体的库,可以称为包。

    sound/			  Top-level package
    __init__.py	       Initialize the sound package
    formats/		  Subpackage for file format conversions
    	__init__.py
    	wavread.py
    	wavwrite.py
    	aiffread.py
    	aiffwrite.py
    	auread.py
    	auwrite.py
    	...
    effects/		  Subpackage for sound effects
    	__init__.py
    	echo.py
    	surround.py
    	reverse.py
    	...
    filters/		  Subpackage for filters
    	__init__.py
    	equalizer.py
    	vocoder.py
    	karaoke.py
    	...
     

    为了让Python将目录当做内容包,目录中必须包含 __init__.py文件。最简单的情况下,只需要一个空的 __init__.py文件即可。

    包有两种导入模块或模块内函数的/变量的方式:

    from package import item  # 这种方式,item可以是包中的一个子模块或子包,也可以是包中定义的其他命名,像函数、类、变量。
    import item.subitem.subsubitem # 这些子项必须是包,最后的子项是包或模块。但不能为函数、类或变量。 

    5. 从 * 导入包

    那么当用户写下 from sound.Effects import *时会发生什么事?理想中,总是希望在文件系统中找出包中所有的子模块,然后导入它们。这可能会花掉委有长时间,并且出现期待之外的边界效应,导出了希望只能显式导入的包。

    对于包的作者来说唯一的解决方案就是给提供一个明确的包索引。import 语句按如下条件进行转换:执行 from package import *时,如果包中的 __init__.py代码定义了一个名为 __all__的列表,就会按照列表中给出的模块名进行导入。新版本的包发布时作者可以任意更新这个列表。如果包作者不想 import * 的时候导入他们的包中所有模块,那么也可能会决定不支持它( import * )。例如, sounds/effects/__init__.py这个文件可能包括如下代码:

    __all__ = ["echo>", "surround>", "reverse>"] 

    这意味着 from Sound.Effects import *语句会从 sound 包中导入以上三个已命名的子模块。

    如果没有定义 __all__from Sound.Effects import *语句 不会 从 sound.effects 包中导入所有的子模块。无论包中定义多少命名,只能确定的是导入了 sound.effects 包(可能会运行 __init__.py中的初始化代码)以及包中定义的所有命名会随之导入。这样就从 __init__.py中导入了每一个命名(以及明确导入的子模块)。同样也包括了前述的 import 语句从包中明确导入的子模块,考虑以下代码:

    import sound.effects.echo
    import sound.effects.surround
    from sound.effects import * 

    在这个例子中,echo 和 surround 模块导入了当前的命名空间,这是因为执行 from…import 语句时它们已经定义在 sound.effects 包中了(定义了 __all__时也会同样工作)。

    尽管某些模块设计为使用 import * 时它只导出符全某种模式的命名,仍然不建议在生产代码中使用这种写法。

    记住,from Package import specific_submodule 没有错误!事实上,除非导入的模块需要使用其它包中的同名子模块,否则这是推荐的写法。

    原文:http://www.cnblogs.com/ronny/p/4519516.html

    Python: 深入Python的输入与输出

    1. 将任意值转化为字符串

    str()用于将值转换为适于人阅读的形式。

    repr()转化为供解释器读取的形式。

    s = "hello,world\n>"
    >>> s1 = str(s) # 因为s原来为字符串,所以s只是保留了原样式
    >>> s2 = repr(s) # repr保证了s的输出形式
    >>> print(s1)
    hello,world # s1 = 'hello,world\n'
    >>> print(s2)
    'hello,world\n' # s2 = "'hello,world\\n'>"
    >>> x,y = 0,1
    >>> list = [x,y,('ronny','young')]
    >>> repr(list)
    "[0,1,('ronny','young')]>" 

    2. 输出格式控制

    str.rjust()保证输出右对齐,如果字符串位数不够,则左边补空白

    str.ljust()保证输出左对齐,如果字符串位数不够,则右边补空白

    str.center()输出两端对齐,左右两边被空白

    如果字符串长超过了指定的宽度,则会原样输出, str.ljust(n)[:n]可以保证字符串的对齐,对字符串进行了截断。

    str.zfill(n)向字符串左右补0,以使整字符串长度达到n。如果原本有正负号,则0加在正负号的后面。

    >>> '-3.14'.zfill(7)
    '-003.14'

    str.format()的用法

    >>> print('We are the {} who say "{}!>"'.format('knights', 'Ni')) # 基本用法
    We are the knights who say "Ni!>"
    >>> print('{1} and {0}'.format('spam', 'eggs')) #大括号内的数值指明传入str.fomat()方法的对象中的哪一个,前面的索引值小于后面给出参数的个数。
    eggs and spam 

    如果在 str.format() 调用时使用关键字参数,可以通过参数名来引用值:

    >>> print('This {food} is {adjective}.'.format(
    ...       food='spam', adjective='absolutely horrible'))
    This spam is absolutely horrible.
    # 定位与关键字参数可以组合使用
    >>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
                                                           other='Georg'))
    The story of Bill, Manfred, and Georg. 

    上面中format里的参数都是字符中,实际上也可以是其他类型,这时要进行转换

    >>> import math
    >>> print('The value of PI is approximately {}.'.format(math.pi))
    The value of PI is approximately 3.14159265359.
    >>> print('The value of PI is approximately {!r}.'.format(math.pi))
    The value of PI is approximately 3.141592653589793. 

    字段名后允许可选的 ‘:’和格式指令。

    # 控制浮点数显示的精度
    >>> import math
    >>> print('The value of PI is approximately {0:.3f}.'.format(math.pi))
    The value of PI is approximately 3.142.
    # 控制显示格式
    >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
    >>> for name, phone in table.items():
    ...     print('{0:10} ==> {1:10d}'.format(name, phone))
    ...
    Jack       ==>       4098
    Dcab       ==>       7678
    Sjoerd     ==>       4127
    # 用命名来引用被格式化的变量
    >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
    >>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
    	'Dcab: {0[Dcab]:d}'.format(table))
    Jack: 4098; Sjoerd: 4127; Dcab: 8637678
    # 也可以用 ‘**’ 标志将这个字典以关键字参数的方式传入
    >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
    >>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
    Jack: 4098; Sjoerd: 4127; Dcab: 8637678
     

    3. 文件的读写

    3.1 打开文件

    >>> f  = open('~/python/somefile','w') #以写的方式打开文件 

    r以只读的方式打开文件

    w以写的方式打开文件,该方式会把原来的同名文件清空

    a以追加的方式打开文件

    r+以读写的方式打开文件

    ‘rb’ 以二进制方式打开文件,并且只读。

    3.2 从文件中读取字符串

    f.read(size) # 从打开的f中读取若干数量的数据并以字符串形式返回其内容,size为字符串长度。如果没有指定size或为负数,则返回整个文件。 

    执行 f.read()后,f读到了哪个位置是有记忆的,再次使用f.read()会从上一次的结尾开始读。

    f.readline() # 读取一行,字符串结束有换行符。文件结尾时 没有换行符。
    f.readlines() # 返回一个列表,包含了文件中所有的数据行。 

    一种替代的方法是通过遍历文件对象来读取文件行。这是一种内存高效,快速,并且代码简洁的方法:

    for line in f:
        printf(line, end=' ') #防止换二行

    f.write(string)将string的内容写入文件,并返回写入字符的长度,如果要写入其他非字符串内容,需要先将它转换为字符串:

    >>> value = ('the answer', 42)
    >>> s = str(value)
    >>> f.write(s)
    18 

    3.3 流的定位

    f.tell()返回一个整数,代表文件对象在文件中的指针位置,该数值计量了自文件开头到指针处的比特数。

    需要改变文件指针的话,使用 f.seek(offset, from_what)。指针在该操作中从指定的引用位置移动offset比特,引用位置from_what参数指定,值为0表示自文件起始位置,1表示自当前文件指针位置开始,2表示自文件末尾开始。from_what可以忽略,其默认值为0,此时从文件头开始。

    f.close()用于关闭文件流。

    用关键字 with处理文件对象是一个好习惯,它的先进之处在于文件用完后会自动关闭,就算发生异常也没有关系。

    with open('~/work/python/file', 'r')  as f:
    ...    read_data = f.read()
    >>> f.closed
    True 

    原文:http://www.cnblogs.com/ronny/p/4519533.html

    Python: Python学习(一) Python安装配置

    我本身是Java程序猿,听说Python很强大,所以准备学习一下Python,虽说语言都是相同的,但java跟python肯定还是有区别的。希望在此记录一下自己的学习过程。

    目前,Python分2.X版本和3.X版本。我选择的是Python2.x版本。为了快速学习Python的WEB开发,我选择的Python的WEB开发框架是Django。Django有个好处就是自带了后台管理系统。

    第一步,下载:

    因本人使用的电脑操作系统是Windows7 64位,所以选择下载Python的windows安装包。

    Python安装包下载地址: https://www.python.org/downloads/windows/,截止目前2.x的最新版本是Python 2.7.10。

    安装下一步下一步就完事了。

    第二步,配置环境变量:

    计算机–右键–属性–高级系统设置–环境变量,在系统变量里找到Path,在其后面加上刚才Python安装的根目录,我的安装目录是”D:\Python27”,前后最好都要加上>”;"号。

    第三步,验证Python是否安装成功:

    Winows键+R,打开命令窗口,输入cmd进入命令行模式,输入python,如果没有错误提示则说明Python安装并配置成功。下面就可以进行Python的代码编写了。

    原文:http://www.cnblogs.com/nihousheng/p/4532080.html

    Python: 【Python实现数据可视化】创建3D柱状图

    虽然matplotlib主要专注于绘图,并且主要是二维的图形,但是它也有一些不同的扩展,能让我们在地理图上绘图,让我们把Excel和3D图表结合起来。在matplotlib的世界里,这些扩展叫做工具包(toolkits)。工具包是一些关注在某个话题(如3D绘图)的特定函数的集合。

    比较流行的工具包有Basemap、GTK 工具、Excel工具、Natgrid、AxesGrid和mplot3d。

    本节将探索关于mplot3d的更多功能。 mpl_toolkits.mplot3工具包提供了一些基本的3D绘图功能,其支持的图表类型包括散点图(scatter)、曲面图(surf)、线图(line)和网格图(mesh)。虽然mplot3d不是一个最好的3D图形绘制库,但是它是伴随着matplotlib产生的,因此我们对其接口已经很熟悉了。

    准备工作

    基本来讲,我们仍然需要创建一个图表并把想要的坐标轴添加到上面。但不同的是我们为图表指定的是3D视图,并且添加的坐标轴是 Axes3D。

    现在,我们可以使用几乎相同的函数来绘图了。当然,函数的参数是不同的,需要为3个坐标轴提供数据。

    例如,我们要为函数 mpl_toolkits.mplot3d.Axes3D.plot指定 xsyszszdir参数。其他的参数则直接传给 matplotlib.axes.Axes.plot。下面来解释一下这些特定的参数。

    1. xsys:x轴和y轴坐标。

    2.zs:这是z轴的坐标值,可以是所有点对应一个值,或者是每个点对应一个值。

    3. zdir:决定哪个坐标轴作为z轴的维度(通常是 zs,但是也可以是 xs或者 ys)。

    提示:模块 mpl_toolkits.mplot3d.art3d包含了3D artist代码和将2D artists转化为3D版本的函数。在该模块中有一个 rotate_axes方法,该方法可以被添加到Axes3D中来对坐标重新排序,这样坐标轴就与 zdir一起旋转了。 zdir默认值为 z。在坐标轴前加一个 ‘“-“’会进行反转转换,这样一来, zdir的值就可以是 x-xy-yz或者 -z

    操作步骤

    以下代码演示了我们所解释的概念。

    import random
    import numpy as np
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    from mpl_toolkits.mplot3d import Axes3D
    mpl.rcParams['font.size'] = 10
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    for z in [2011, 2012, 2013, 2014]:
    	xs = xrange(1,13)
    	ys = 1000 * np.random.rand(12)
    	color =plt.cm.Set2(random.choice(xrange(plt.cm.Set2.N)))
    	ax.bar(xs, ys, zs=z, zdir='y', color=color, alpha=0.8)
    ax.xaxis.set_major_locator(mpl.ticker.FixedLocator(xs))
    ax.yaxis.set_major_locator(mpl.ticker.FixedLocator(ys))
    ax.set_xlabel('Month')
    ax.set_ylabel('Year')
    ax.set_zlabel('Sales Net [usd]')
    plt.show()
     

    上述代码生成如图5-1所示的图表。

    图5-1

    工作原理

    我们需要像在2D世界中那样做相同的准备工作。不同的是,在这里需要指定后端(backend)的种类。然后生成了一些随机数据,例如4年的销售额(2011-2014)。

    我们需要为3D坐标轴指定相同的Z值。

    从颜色映射集合中随机选择一种颜色,然后把它和每一个Z-order集合的 xsys对关联起来。最后,用 xsys对渲染出柱状条序列。

    补充说明

    其他的一些matplotlib的2D绘图函数在这里也是可以用的,例如 scatter()plot()有着相似的接口,但有额外的点标记大小参数。我们对 contourcontourfbar也非常熟悉。

    仅在3D中出现的新图表类型有线框图(wireframe)、曲面图(surface)和三翼面图(tri-surface)。

    在下面的示例代码中,我们绘制了著名的Pringle函数的三翼面图,数学专业上的叫法是双曲面抛物线(hyperbolic paraboloid)。

    from mpl_toolkits.mplot3d import Axes3D
    from matplotlib import cm
    import matplotlib.pyplot as plt
    import numpy as np
    n_angles = 36
    n_radii = 8
    # An array of radii
    # Does not include radius r=0, this is to eliminate duplicate points
    radii = np.linspace(0.125, 1.0, n_radii)
    # An array of angles
    angles = np.linspace(0, 2 * np.pi, n_angles, endpoint=False)
    # Repeat all angles for each radius
    angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
    # Convert polar (radii, angles) coords to cartesian (x, y) coords
    # (0, 0) is added here. There are no duplicate points in the (x, y)
    plane
    x = np.append(0, (radii * np.cos(angles)).flatten())
    y = np.append(0, (radii * np.sin(angles)).flatten())
    # Pringle surface
    z = np.sin(-x * y)
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.2)
    plt.show() 

    上面的代码生成如图5-2所示的图形。

    图5-2

    本文摘自《Python数据可视化编程实战》

    Python数据可视化编程实战

    内容简介:

    本书是一本使用Python实现数据可视化编程的实战指南,介绍了如何使用Python最流行的库,通过60余种方法创建美观的数据可视化效果。

    全书共8章,分别介绍了准备工作环境、了解数据、绘制并定制化图表、学习更多图表和定制化、创建3D可视化图表、用图像和地图绘制图表、使用正确的图表理解数据以及更多的matplotlib知识。

    本书适合那些对Python编程有一定基础的开发人员阅读,可以帮助读者从头开始了解数据、数据格式、数据可视化,并学会使用Python可视化数据。

    点此购买: http://item.jd.com/11676691.html

    原文:http://www.jianshu.com/p/bb8b25096df4