Skip navigation.

Posts tagged with "python"

数值蟒

, , ,

因作课题的需要,使用python作为粘合剂连接多个程序,包括商业的、开源的和自己写的。其中需要对中间数据进行处理作一些数值计算,这个工作可以在fortran中完成的,但是需要将数据从python程序流中导出导入,显得麻烦。所以还是选择SciPy, NumPy来做,它们已经把矩阵这种数值计算常用的对象包装完整,并在此基础上封装了多个开源的数值计算包比如blas, linalg, fitpack 等等,对付一般的计算足够用了。

之前对于 NumPy, Numeric, Numarray, Scipy 之间的关系非常困惑,在看了History of Scipy 之后,有了一些大致的了解,看来 NumPy+SciPy 将是数值蟒的首选了。

Scipy和Numpy的前世今生

,

关于numpy, numeric, numarray, scipy 复杂的演化历史在scipy的网站上有相关解释,随手翻译了一下


:heart: Numeric的诞生

故事开始于1995年。Jim Hugunin在Jim Fulton, David Ascher, Paul DuBois, Konrad Hinsen等众人的帮助下开发了Numeric。 不过当时Numeric就有了很多名字:Numerical Python, Numerical, NumPy。 比如 SourceForge 上的名字是 numpy,而CVS中的名字是 Numerical。另外Konrad Hinsen 开发了 ScientificPython 程序包,他把它也称为 Numerical Python。

:heart: SciPy的诞生

一些人在他们的科研代码中使用 Numeric 并开发了自己的模块。2001左右, Travis Oliphant, Eric Jones 和 Pearu Peterson 将他们的模块整合到一起,释放出一个超级程序包,SciPy 就此诞生。

:heart: numarray的诞生

Numeric的开发进度渐渐缓慢下来,人们想扩展它的功能,而且希望 Numeric可以进入python标准库,但是Guido van Rossum 指出根据Numeric当时的开发情况根本无法维护下去。

于是,Space Science Telescope Institute 的 Perry Greenfield, Todd Miller和Rick White开发了numarray来替代Numeric。numarray的代码质量基本达到python的水平,具有相当的灵活性,在与其他的替代品的比较中也显示出了优势。而且操作大型矩阵速度很快。

:heart: 分裂: Numeric vs. numarray

遗憾的是,numarray对于小型矩阵的操作相当慢。而且numarray用于创建ufuncs的C API没有Numeric的方便。导致SciPy从Numeric转向numarray遇到很大困难。整个社区因此产生分裂:一些人只为numarray写代码,把它看作下一代的Numeric,而其他人为Numeric写代码,因为他们需要SciPy。

:heart: 合并,NumPy的诞生

2005初,Travis Oliphant想把社区重新联合回归到单个数组(array)程序包。 他重构了Numeric的代码,使其更易维护,能够灵活的实现numarray的特性。他把这个新的多维数组项目命名为 SciPy core,试图将它用于SciPy。

问题是,人们错误的认为Numeric已经被SciPy包容了,他们必须安装SciPy才能使用数组对象。于是这个多维数组项目被赋予一个全新的名字 'NumPy'。

做一个书签 II

, ,

上一次完成的功能只限于:通过javascript把页面的信息发送到服务器上。现在要处理这个信息了(用数据库sqlite存储)。

因为对sqlite一窍不通,所以只是在它的tutorial里面找一些例子,依葫芦画瓢,向数据库里写内容。

这是PostRemote的doPost方法,处理信息。
    @cherrypy.expose
    def doPost(self, url="", title="", notes="", tags=""):
        con = cherrypy.thread_data.db.cursor()
        user = ""
        info = (title, url, notes, user, tags, time.time())
        con.execute("insert into bookmark (title, url, notes, user, tags, time) values (?,?,?,?,?,?)", info)
        cherrypy.thread_data.db.commit()
        con.close()
        yield '...... done!<br>'
        yield 'go back to <a href="%s">%s</a>' % (url, title)


传入的信息包括url, title, notes,tags。其中tags只是一个摆设,我也不清楚以后怎么处理它。而user则是为以后可能要添加的用户功能作准备,目前是空值。

数据库每次打开,写入,关闭,当然很费时费事,不过自己使用无所谓了。

另外,保存数据以后如何立刻转会到原来的页面?不太清楚,只好加一个链接,再次链接回去完事。

做一个书签 I

, ,

美味书签是一个社会化书签系统,在网络上非常流行,国内已经有365key之类的网站进行模仿了。当然,这些都是旧闻了。

我用了一段时间美味书签,觉得很方便,特别是它提供的post to del.icio.us按钮,可以在浏览网页的时候随时保存,另外加上一些tag,使得归类是如此的简单。比起在Opera、FireFox、IE等浏览器上的书签系统要方便很多(难以想象在本地对几百个书签进行分类、查找)。

可能美味书签的很多用户和我一样并不太关心它所提供的其他社会化功能,只是做了一个网上的书签保存而已。而且服务器在国外,偶尔会有速度慢、无法访问的问题,这是比较恼人的。所以我想到自己做一个书签如何?

对于个人的书签来说,这是非常简单的任务。在客户端的浏览器上,只需要仿照post to del.icio.us,自己做一个按钮,指向自己的服务器。在服务器上,通过特定的URL处理接收到的数据,保存。当然,其他显示、搜索的功能也是需要的,但那是之后的任务了。

做一个post按钮,链接如下 ( 服务器的网址 http://localhost:8000 )
javascript:location.href='http://localhost:8000/?url='+encodeURIComponent(location.href)+';title='+encodeURIComponent(document.title)


完成这种任务对于python来说简直是小菜一碟。除了内置的CGIHTTPServer,还有其他极其丰富的网络框架。看了啄木鸟社区上面的Web应用平台系列,试了试CherryPy感觉很有意思。

于是写下这样一段代码

import os, time
import cherrypy
from cherrytemplate import renderTemplate
from pysqlite2 import dbapi2 as sqlite

# add this before cherrypy server start
def connect(thread_index):
    cherrypy.thread_data.db = sqlite.connect("contact.db")

cherrypy.server.on_start_thread_list.append(connect)

class BasePage:
    def __init__(self, title=None):
        self.title = 'Bookmark'
        if title:
            self.title  += ' : %s' % title
            
    @cherrypy.expose
    def default(self, *args):
        return '%s not available <a href="/">go back home</a>' % repr(args)
        
    def header(self):
        return renderTemplate(file='./template/header.html')

    def navibar(self):
        return renderTemplate(file='./template/navibar.html')
    
    def footer(self):
        yield '<p><font color="grey"> %s </font></p>' % repr(cherrypy.request.headers)
        yield renderTemplate(file='./template/footer.html')


class PostRemote(BasePage):
    """ supply remote post
    you can make a button on youre bowser, whose URL should be:
    
    javascript:location.href='http://localhost:8000/post?url='+
    encodeURIComponent(location.href)+';title='+encodeURIComponent(document.title)

    where 'http://localhost:8000/post' is the url of instance of PostRemote mounted on.
    """
    def __init__(self):
        BasePage.__init__(self, "post")

    @cherrypy.expose
    def index(self, url="", title=""):
        return renderTemplate(file='./template/form_postremote.html')

    @cherrypy.expose
    def doPost(self, url="", title="", notes="", tags=""):
        return "gotcha"
    
cherrypy.root = PostRemote()

if __name__=="__main__":
    cherrypy.config.update(file = 'tutorial.conf')
    cherrypy.server.start()


使用了CherryTemplate 作简单的模板, 把html都塞过去。

在doPost方法中应该对数据处理之后存入数据库的,不过我不会用数据库,只好搁置啦 ...

Model View Controller [MVC]

,

原文 wxPython wiki :: ModelViewController


模型-视图-控制器

ModelViewController 简称为 MVC

简介

本页介绍 MVC (ModelViewController) 模式并演示其在Python中的实现方法
http://c2.com/cgi/wiki?ModelViewController 可以了解更多关于MVC的信息, 你也可以察看MVC的一种演化模式 ModelViewPresenter

原理

(原文出处 http://mail.python.org/pipermail/python-list/2006-January/319314.html by has)

MVC模式关注于内容的分离。

Model(模型)负责管理程序中的数据(私有数据和客户数据)。View/Controller(视图/控制器)负责为外界提供与程序中的客户数据进行交互的手段。

模型提供了内部接口(API),允许程序的其他部分与之交互。视图/控制器提供外部接口(GUI/CLI/web form/high-level IPC/等等),允许程序外部的世界与程序进行交互。

模型负责保持数据的完整性,因为数据一旦被破坏,所有的东西就 game over 了。视图/控制器负责保持UI的完整性, 确保所有的文字视图显示的都是最新的数据,使不适用于当前焦点的菜单失效,等等。

模型不包含视图/控制器代码;没有GUI窗口类,没有对话框布置代码,不接受用户输入。视图/控制器不包含模型代码;没有URLs验证和SQL查询代码,也不包含数据原始状态: 窗口中的任何数据仅仅是为显示目的而存在,而且也仅仅是模型中数据的真实反映。

如何验证真正的MVC设计呢?如果程序不存在视图/控制器部分,它也应该具有完整的功能。当然,这种情况下外部世界与它进行交互会存在困难,但是 只要知道适当的模型API,程序应该能够正常的保持和操作数据。

为什么能够达到这种效果?最简单的答案:都是因为模型与视图/控制器层之间的弱耦合关系。但是这并不是它的全部内容。MVC模式的关键是 '''这些连接的走向''':所有的指令都是从视图/控制器指向模型的。模型从不告诉视图/控制器去做什么。

为什么呢?因为在MVC中,允许视图/控制器对模型有一些了解(特别是模型的API),但是不允许模型了解视图/控制器的任何情况。

为什么呢?因为MVC就是要建立一个内容上完整分离的结构。

为什么呢?是为了防止无法控制程序的复杂性,导致你这位程序开发者精疲力尽。程序越大,其部件数量越多。这些部件之间的连接越多,开发人员就越难以控制/扩展/替换各个部件,甚至于无法搞清整个系统如何工作。问问你自己:当你看到程序结构图时,你愿意看到一颗树还是猫爪印?MVC模式拒绝回环连接(B可以连接A,但A不能连接B。在这里,A是模型,B是视图/控制器),从而避免了后者的产生。

另外,如果你够聪明,你会意识到刚才描述的单向约束中有一个问题:在模型根本不知道视图/控制器的情况下,如何通知视图/控制器其用户数据的变化呢?不要担心,这里有一个解决方案,虽然刚开始看起来有一些绕圈子,但实际上它相当的简洁,我们待会儿会讲到它。

在实际项目中,视图/控制器对象会通过模型的API,1. 让模型做一些事情(执行命令),2. 让模型给它一些东西(返回数据)。视图/控制器层向模型层'''发出指令'''并从模型层中'''获取信息'''。

例如一个 MyCoolListControl 类,应该在需要时能够从下层获取所需的数据。对于list widget的情况,一般意味着询问有多少个值,然后返回每一个值,因为这是完成这种操作最简单最宽松的方式,同时将耦合保持到最低限度。而如果 widget 想向用户展示按照字母排序的结果,那就是它自己的工作,当然要它自己负责完成。

现在,最后一个迷题(也就是我们之前提到的): 在基于MVC的系统中如何保持UI的显示同步于模型的状态呢?

这就是问题所在:很多的视图对象都是状态性的,比如 checkbox 可能处于选择或者未选择状态,文字框可能包含一些可以编辑的文字。但是,MVC规定所有的用户数据保存在模型层中,所以其他层中的为了显示目的而存在的任何数据(checkbox的状态,文字框中的当前文字)必须是模型数据的辅助副本。但如果模型状态改变了,视图中的副本就不再准确而应该被刷新。

但是如何操作呢?MVC模式禁止模型向视图层发出相关信息的最新副本,甚至不允许模型向视图发出消息,表明其状态的变化。

是的,几乎就是这样。Ok,不允许模型层与其他层直接对话,因为这就要求它知道其他层的信息,而且MVC的规定也不允许这样做。但是,如果森林中的一颗树倒下了,而没有人听到,那么它发出声音了吗?

答案就是建立一套通告系统,为模型层提供一个空间,让它可以发出通告,说它已经完成了一些有趣的事情。其他层可以向通告系统发出监听器,监听它们所感兴趣的的通告。模型层根本不需要知道谁在监听(甚至是否有人在监听);它仅仅发出通告,然后就把它抛在了脑后。如果有人听到了这个通告,并且想随之做一些事情 - 比如向模型询问一些新的数据以便更新显示 - 这样就搞定了。模型只是将它所发出的通告列表作为它的API定义的一部分;其他人想拿这个知识做什么事的话,随便。

MVC is preserved,and everyone is happy. 你的应用程序框架可能已经提供了内置的通告系统,你也可以自己写一个(参考 ObserverPattern)。

示例代码

(originally posted by Brian Kelly at http://www.techietwo.com/detail-6332577.html)


import wx

# an observable calls callback functions when the data has
# changed
#o = Observable()
#def func(data):
# print "hello", data
#o.addCallback(func)
#o.set(1)
# --| "hello", 1

class Observable:
def __init__(self, initialValue=None):
self.data = initialValue
self.callbacks = {}

def addCallback(self, func):
self.callbacks[func] = 1

def delCallback(self, func):
del self.callback[func]

def _docallbacks(self):
for func in self.callbacks:
func(self.data)

def set(self, data):
self.data = data
self._docallbacks()

def get(self):
return self.data

def unset(self):
self.data = None

class Model:
def __init__(self):
self.myMoney = Observable(0)

def addMoney(self, value):
self.myMoney.set(self.myMoney.get() + value)

def removeMoney(self, value):
self.myMoney.set(self.myMoney.get() - value)


class View(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Main View")
sizer = wx.BoxSizer(wx.VERTICAL)
text = wx.StaticText(self, -1, "My Money")
ctrl = wx.TextCtrl(self, -1, "")
sizer.Add(text, 0, wx.EXPAND|wx.ALL)
sizer.Add(ctrl, 0, wx.EXPAND|wx.ALL)
self.moneyCtrl = ctrl
ctrl.SetEditable(False)
self.SetSizer(sizer)
self.moneyCtrl = ctrl

def SetMoney(self, money):
self.moneyCtrl.SetValue(str(money))

class ChangerWidget(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Main View")
sizer = wx.BoxSizer(wx.VERTICAL)
self.add = wx.Button(self, -1, "Add Money")
self.remove = wx.Button(self, -1, "Remove Money")
sizer.Add(self.add, 0, wx.EXPAND|wx.ALL)
sizer.Add(self.remove, 0, wx.EXPAND|wx.ALL)
self.SetSizer(sizer)

class Controller:
def __init__(self, app):
self.model = Model()
self.view1 = View(None)
self.view2 = ChangerWidget(self.view1)
self.MoneyChanged(self.model.myMoney.get())
self.view2.add.Bind(wx.EVT_BUTTON, self.AddMoney)
self.view2.remove.Bind(wx.EVT_BUTTON, self.RemoveMoney)

self.model.myMoney.addCallback(self.MoneyChanged)
self.view1.Show()
self.view2.Show()

def AddMoney(self, evt):
self.model.addMoney(10)

def RemoveMoney(self, evt):
self.model.removeMoney(10)

def MoneyChanged(self, money):
self.view1.SetMoney(money)


app = wx.PySimpleApp()
Controller(app)
app.MainLoop()