2010年6月30日星期三

ClearSilver

1. 什么是ClearSilver

Clearsilver is a fast, powerful, and language-neutral HTML template system. In both static content sites and dynamic HTML applications, it provides a separation between presentation code and application logic which makes working with your project easier. The design of Clearsilver began in 1999, and evolved during its use at onelist.com, egroups.com, and Yahoo! Groups. Today many other projects and websites using it.
2. 为什么使用ClearSilver

High Performance and Language Neutral. Because Clearsilver is written as a C-library, and exported to scripting languages like Python, Perl, Java and Ruby via modules, it is extremely fast. This also means you can work with the same template system independent of the language your project is in.
Pluggable Look and Feel. Clearsilver makes it easy to face lift a site by providing a new set of templates. It is possible to easily run more than one look and feel at once, and share components with a base look and feel to reduce maintenance.
Internationalization Support. Clearsilver makes it trivial to support internationlization. You write your templates in your native language and included tools automatically extract and catalog language strings for translation.
Advanced features. Built in support for advanced features such as gzip compression, smart whitespace stripping, parametric macros, online debugging mode, url and javascript string escaping, and more.
3. 文档

http://www.clearsilver.net/docs/

4. 下载

http://www.clearsilver.net/downloads/

5. 教程

一切从Hello World开始

::-- ZoomQuiet [2005-08-23 03:52:16]

5.1. 快速体验

clearsilver是一个高性能的模版系统,让我们看看他的使用网站,就知道他的表现有多好。

Bloglines
Google Groups
Yahoo Groups
其他的应用请到这里http://www.clearsilver.net/examples.hdf

clearsilver由3各部分组成:hdf数据描述,cst模版文件,py逻辑处理向hdf赋值



编写hdf文件:hello.hdf

# This is my static data for Hello World (and this is a comment)

Hello = Hello World!

WeekDays {
0 = Sunday
1 = Monday
2 = Tuesday
3 = Wednesday
4 = Thursday
5 = Friday
6 = Saturday
}
编写模版文件:hello.cst






On ,




On ,



Hey ,
这个模版文件唯一要注意的就是cs if:?Query.day,是用来处理链接参数的:cgi-bin/hello.py?day=1

模版语法详见: http://www.clearsilver.net/docs/

然后将这两部分合二为一:

切换行号显示
1 #!/usr/bin/python
2 #
3 # Hello World using the ClearSilver CGI Kit and Python
4
5 import neo_cgi
6
7 # create a CGI handler context
8 ncgi = neo_cgi.CGI()
9
10 # parse the form data (and post upload data)
11 ncgi.parse()
12
13 # Load our static data
14 ncgi.hdf.readFile("hello.hdf")
15
16 ncgi.display("hello.cst")
17
P.S: 测试环境winXP+IIS5(懒得装apache了)

6. 讨论

感觉clesarsilver很像zope的dtml,都有循环、判断语句什么的。 --tomz
因为都是模版系统,所以肯定有类似的地方,clesarsilver的优势在于:语言无关,性能好,模版语言丰富,逻辑界面分离。--清风

转载自:
http://wiki.woodpecker.org.cn/moin/ClearSilver

软件配置管理工具CVS vs. STARTEAM

CVS 是开放源码的一个奇迹,亦是开放源码得以延续和发展的推动者,是版本控制的经典。CVS 是常用的版本控制工具。

Starteam 是一个集合了版本控制和缺陷控制两种功能的软件,并且具有 CVS 没有的强大的图形界面,易学易用。2002年底被Borland公司收购,发展前景未知,它是我是用的第一个大型商用版本控制软件(真的付了Money的呦)。


评价 CVS、STARTEAM 孰优孰劣,是一个仁者见仁,智者见智的问题。

Starteam 的图形化界面,能够使初学者易于接收,而且其缺陷控制功能的功能(基于数据库的Change Request),是CVS 不具有的,更是相应工具中独树一帜的。

CVS的优秀跨平台能力、强大的命令行、清晰的服务器端数据结构更便于数据的备份、灾难恢复和可靠性。Simple is Butiful 送给 CVS 一定没错。

侧重不同

CVS专注于配置管理软件范畴中的版本管理系统。而配置管理系统除了包括版本管理外,还包括构建管理(Build Management)和缺陷跟踪系统。而Starteam包括了这三项。本文档也就只比较其版本管理系统的异同。

权限控制

一般来说,CVS的权限设置单一,通常只能通过CVSROOT/passwd, CVSROOT/readers, CVSROOT/writers 文件,同时还要设置CVS REPOS的物理目录权限来完成权限设置,无法完成复杂的权限控制;而STARTEAM无需通过物理路径的权限设置,而是通过自己的数据库管理,实现了类似WINDOWS NT的域用户管理和目录文件ACL控制。

但是CVS通过CVSROOT目录下的脚本,提供了相应功能扩充的接口,不但可以完成精细的权限控制,还能完成更加个性化的功能。

易用性

Starteam的图形界面功能强大,但其命令行功能较CVS弱,需要自己编写shell脚本加强。而随着WINCVS作为图形客户端的可用性的增强,Starteam的强项正在被削弱。

Label的管理

CVS 的 label 建立在文件上,难以确定到底有多少存在的 label ,而STARTEAM(图形界面)可以很方便知道有哪些 View Label及Revision Label。

CVS的版本分支, label是建立在文件上,工作在其他分支的程序同样会看到其它分支的label;而Starteam的label只在同一个视图内有效,有独立的命名空间。

STARTEAM具有Promotion states,可以看作是label的标签。在label上又封装一层的 Promotion State 便于记录版本的提升,和建立自动编译;而CVS 没有浮动 label 的概念,只能通过文件记录方式实现(如我们使用 .promotion 文件记录当前稳定的 label)。

文件缓存

Starteam 存在CACHE目录,缓存了所有 Checkout的版本的文件,因此 Checkout速度快。而CVS没有缓存,check out过程较慢,尤其是分支的 Checkout。


但我对此表示怀疑。尤其是Starteam Unix客户端基于JAVA技术,速度明显比CVS要慢。


操作文件名和目录名

CVS的REPOSITORY的物理存储结构即为项目的组织结构,使得文件名修改和目录的重新组织成为难题,往往需要管理员权限去手动操作Repository;而STARTEAM的Repository的文件结构和视图的文件结构可以完全不同,目录、文件名修改和移动非常方便,基于数据库的文件名管理还可以方便地在不同工程之间共享文件,协同工作。

CVS是程序员的工具,STARTEAM还是管理项目的工具

个人文件管理或小项目的组织,需要轻量级的管理,和灵活的文件导入、导出,以及和自由代码的交互,则CVS,Perforce,PVCS,SourceSafe等面向文件的版本控制占优势。对于公司、大项目,需要独立的测试、QA等分工,还要更多的考虑多样的用户权限控制,易用性(图形界面),缺陷控制,则需要面向工程的STARTEAM来进行版本控制和开发。

CVS的优势

CVS的优势:项目文件可以方便的组合和移植,这是因为CVS以文件为核心,即面向文件的管理方式。而且目前网络上很多开放源码都采用CVS,可以很好沟通。

CVS配置简单、健壮、可以很容易地移植;STARTEAM集成度较高,移植过程复杂,需要的管理负担大,需要完善的备份计划。

CVS是开发源码,服务器端存储易于理解,便于控制;而Starteam为商业软件,服务器端存储方式封闭,难以管理。但是 CVS 不提供图形界面,有较长的学习曲线。

Starteam 的劣势

不支持分支的合并,需要过多的手动干预。而CVS可以自动完成。

速度慢,一定程度上影响开发效率。

不支持并行开发,不能很好解决Merge的问题。而CVS可以智能 Merge。

故障恢复困难,需要有专职管理员维护。而CVS易于维护。

评价优劣,不如先用先得

不用刻意去取舍哪一个,只要用好,即可。况且,已经有了完美的CVS、STARTEAM互相转换的方法。(参见:《CVS, Starteam互相转换》)

转载自:
http://se.csai.cn/casepanel/CM/No101.htm

2010年6月29日星期二

使用pyExcelerator创建自定义分页的Excel文件

项目中要用Python创建自定义报表,其中要求每个事务占excel的一页,需要抛弃默认的分页选项,自定义分页。

excel分页其实就是在excel文件中的适当位置插入page breaks(分页符)。pyExcelerator 中有相关的借口允许用户调用并自定义分页符位置。

分页符记录在biff8中的记录块分别是HorizontalPageBreaksRecord和VerticalPageBreaksRecord:

class HorizontalPageBreaksRecord(BiffRecord):
"""
This record is part of the Page Settings Block. It contains all
horizontal manual page breaks.

Record HORIZONTALPAGEBREAKS, BIFF8:
Offset Size Contents
0 2 Number of following row index structures (nm)
2 6nm List of nm row index structures. Each row index
structure contains:
Offset Size Contents
0 2 Index to first row below the page break
2 2 Index to first column of this page break
4 2 Index to last column of this page break

The row indexes in the lists must be ordered ascending.
If in BIFF8 a row contains several page breaks, they must be ordered
ascending by start column index.
"""

class VerticalPageBreaksRecord(BiffRecord):
"""
This record is part of the Page Settings Block. It contains all
vertical manual page breaks.

Record VERTICALPAGEBREAKS, BIFF8:
Offset Size Contents
0 2 Number of following column index structures (nm)
2 6nm List of nm column index structures. Each column index
structure contains:
Offset Size Contents
0 2 Index to first column following the page
break
2 2 Index to first row of this page break
4 2 Index to last row of this page break

The column indexes in the lists must be ordered ascending.
If in BIFF8 a column contains several page breaks, they must be ordered
ascending by start row index.
"""

具体的接口就是在worksheet中set_vert_page_breaks和set_horz_page_breaks。先上程序:


from pyExcelerator import *

wb = Workbook()
ws = wb.add_sheet('0')
horz_page_breaks_list=[]

for i in range (200):
for j in range (20):
ws.write(i,j,'BIG')
else:
for i in range(39):
#5 rows each page
horz_page_breaks_list.append([(i+1)*5,0,0])

ws.set_horz_page_breaks(horz_page_breaks_list)

wb.save('page_breaks.xls')
print 'successful set page breaks!'


这个是设置5行一页,每页列数按照默认值。

2010年6月28日星期一

Python 绝对简明手册

1. 阅读须知

文中使用

>>>
作为会命令行中的输出信息的前缀

对于不清楚用用途的函数可以在解释器下面输入

help(函数名)
来获取相关信息

另外,自带的文档和google也是不可少的

2. 基本语法

2.1. if / elif / else


x=int(raw_input("Please enter an integer:"))#获取行输入

if x>0:
print '正数'
elif x==0:
print '零'
else:
print '负数'
此外C语言中类似"xxx?xxx:xxx"在Python中可以这样写

>>>number=8
>>>print "good" if 8==number else "bad" #当满足if条件时返回"good",否则返回"bad"
good
2.2. in

in判断 一个数 是否在 一个集合(如:元组,列表等) 中


if 'yes' in ('y','ye','yes'):print 'ok'
2.3. for ... in

python中没有类似C中的for循环,而是使用for...in来对集合中的每一个元素进行操作

a=['cat','door','example']
for x in a:
print x
如果要修改a的内容,请用a的副本循环(否则不安全),如:

a=["cat","zsp007@gmail.com"]
for x in a[:]:
if len(x)>6:a.insert(0,x)
>>>a
['zsp007@gmail.com', 'cat', 'zsp007@gmail.com']
若需要得到循环的次数,参见 函数 range 的用法

2.4. break / continue

这两个的用法和C中相同

for i in range(10):
if 2==i:continue #结束当前循环,进入下一步循环
if 6==i:break #跳出循环
print i
输出

0
1
3
4
5
2.5. while / pass


while True:
pass #什么也不做
2.6. is

用来比较两个变量是否指向同一内存地址(也就是两个变量是否等价) 而 == 是用来比较两个变量是否逻辑相等

a=[1,2]
b=[1,2]
>>> a is b
False
>>> a == b
True
2.7. del

用于删除元素

a=[1,2,3,4,5,6]

del a[0]
a
>>>[2,3,4,5,6]

del a[2:4]
a
>>>[2,3,6]

del a[:]
a
>>>[]

del a
a
#抛出异常
>>>NameError: name 'a' is not defined
2.8. try ... except ... finally / raise

try ... except用于异常处理

try:
x=int(raw_input("请输入数字:"))
except ValueError: #可以同时捕获多个异常,写法如except(RuntimeError,ValueError):
#当输入非数字时
print"您输入不是数字"
except: #省略异常名,可以匹配所有异常,慎用
pass
else:#当没有异常时
print 'result=',result
finally:#和Java中类似。一般用于释放资源,如文件,网络连接。
print 'finish'
raise用于抛出异常,可以为自定义的异常类

惯例是以Error结尾的类,同类的异常一般派生自同一个基类(如Exception)

class MyError(Exception):
def __init__(self,value):
self.value=value
def __str__(self):
return reper(self.value)
基类异常可以匹配派生类异常


try:
raise Exception("spam","egg")
except Exception,inst:#inst为该异常类的实例,为可选项
print type(inst) #异常的类型
print inst
3. 内建类型

3.1. None

None 表示该值不存在,比如 没有定义返回值 的函数就 返回None

3.2. Ture / False

布尔类型,Ture等价于1,False等价于0

3.3. List


>>>test=[1,2,"yes"]
3.3.1. 内建函数

append(x) 追加到链尾

extend(L) 追加一个列表,等价于+=

insert(i,x) 在位置i插入x

remove(x) 删除第一个值为x的元素,如果不存在会抛出异常

reverse() 反转序列

pop([i]) 返回并删除位置为i的元素,i默认为最后一个元素(i两边的[]表示i为可选的,实际不用输入)

index(x) 返回第一个值为x的元素,不存在则抛出异常

count(x) 返回x出现的次数

sort() 排序

例子:

>>>test=[1,2,"yes"]

>>>test.append(1) #追加到链尾
>>>test
[1, 2, 'yes', 1]

>>>test.extend([ 'no','maybe']) #追加一个列表
>>>test
[1, 2, 'yes', 1, 'no', 'maybe']

>>> test.insert(0,'never') #在位置0插入'never'
>>> test
['never', 1, 2, 'yes', 1, 'no', 'maybe']

>>> test.remove('no') #删除第一个值为"no"的元素,如果不存在会抛出异常
>>> test
['never', 1, 2, 'yes', 1, 'maybe']

>>> test.reverse() #反转序列
>>> test
['maybe', 1, 'yes', 2, 1, 'never']

>>> test.pop() #返回并删除位置为i的元素,i默认为最后一个元素
'never'
>>> test
['maybe', 1, 'yes', 2, 1]

>>> test.index('yes') #返回第一个值为'yes'的元素,不存在则抛出异常
2

>>> test.count(1) #返回1出现的次数
2

>>>test.sort() #排序
>>> test
[1, 1, 2, 'maybe', 'yes']
3.3.2. 切片

从序列中抽取一部分

>>> test=['never', 1, 2, 'yes', 1, 'no', 'maybe']

>>> test[0:3] #包括test[0],不包括test[3]
['never', 1, 2]

>>> test[0:6:2] #包括test[0],不包括test[6],而且步长为2
['never', 2, 1]

>>> test[:-1] #包括开始,不包括最后一个
['never', 1, 2, 'yes', 1, 'no']

>>> test[-3:] #抽取最后3个
[1, 'no', 'maybe']

>>>test[::-1] #倒序排列
['maybe', 'no', 1, 'yes', 2, 1, 'never']
3.3.3. 列表推导式

可以直接通过for循环生成一个list


>>>freshfruit=[' banana ',' loganberry ']
>>>[weapon.strip() for weapon in freshfruit]
['banana', 'loganberry']
说明:strip()是去除字符串两端多于空格,该句是去除序列中的所有字串两端多余的空格


>>>vec=[2,4,6]
>>>[3*x for x in vec if x>3]
[12, 18]

>>>[(x,x**2) for x in vec]
#循环变量要是一个sequence,而[x,x**2 for x in vec]是错误的
[(2,4),(4,16),(6,36)]

>>>vec2=[4,3,-9]

>>>[x*y for x in vec for y in vec2]
[8, 6, -18, 16, 12, -36, 24, 18, -54]

>>>[vec[i]+vec2[i] for i in range(len(vec))]
[6, 7, -3]

>>>[str(round(355/113.0,i)) for i in range(1,6)]
#str()是转换类型为可以打印的字符
#round(x,n)表示对x保留n位小数(四舍五入)
['3.1', '3.14', '3.142', '3.1416', '3.14159']
3.4. 元组

一旦初始化便不能更改的数据结构,速度比list快


>>>t=1234,5567,'hello' #t=(1234,5567,'hello')的简写

>>>x,y,z=t #拆分操作可以应用于所有sequence
>>>x
1234

>>>u=t,(1,2,3)
>>>u
((1234,5567,'hello'),(1,2,3))

>>>empty=() #空元组
>>>singleton='hi', #单个元素的元组,注意逗号
通过元组可以很简单的进行数据交换. 比如:

a=1
b=2
a,b=b,a
3.5. set

set(集合):无序不重复的元素集


>>>basket = ['apple','orange','apple','pear','apple','banana']

>>>fruit=set(basket)

>>>fruit
set(['orange', 'pear', 'apple', 'banana'])

>>>'orange' in fruit
True

>>>a=set('abracadabew')
>>>a
set(['a', 'c', 'b', 'e', 'd', 'r', 'w'])

>>>b=set('wajgwaoihwb')
>>>b
set(['a', 'b', 'g', 'i', 'h', 'j', 'o', 'w'])

>>>a-b #差
set(['c', 'r', 'e', 'd'])

>>>a|b #并
set(['a', 'c', 'b', 'e', 'd', 'g', 'i', 'h', 'j', 'o', 'r', 'w'])

>>>a&b #交
set(['a', 'b', 'w'])

>>>a^b #(并-交)
set(['c', 'e', 'd', 'g', 'i', 'h', 'j', 'o', 'r'])
3.6. dict

字典:关键字为不可变类型,如字符串,整数,只包含不可变对象的元组.

列表等不可以作为关键字.

如果列表中存在关键字对,可以用dict()直接构造字典.而这样的列表对通常是由列表推导式生成的.


>>>tel={'jack':4098,'sape':4139}

>>>tel['guido']=4127

>>>tel
{'sape': 4139, 'jack': 4098, 'guido': 4127}

>>>tel['jack'] #如果jack不存在,会抛出KeyError
4098
>>>a.get("zsp",5000) #如果"zsp"为tel的键则返回其值,否则返回5000

>>>del tel['sape'] #删除键'sape'和其对应的值
>>>tel.keys() #复制一份键的副本,同理tel.items()为值的副本
['jack', 'guido']

>>>"jack" in tel #判断"jack"是否tel的键
True
>>>"zsp" not in tel
True

>>>for k,v in tel.iteritems():print k,v #同理tel.iterkeys()为键的迭代器,tel.itervalues()为值的迭代器
jack 4098
guido 4127

>>>tel.copy() #复制一份tel
{'jack': 4098, 'guido': 4127}

>>> tel.fromkeys([1,2],0) #从序列生成并返回一个字典,其值为第二个参数(默认为None),不改变当前字典
{1: 0, 2: 0}

>>>tel.popitem() #弹出一项
('jack', 4098)
4. 函数相关

4.1. 函数定义 / 参数默认值


def fib(n=2,a=1):#参数可以有默认值
"""这里给函数写文档注释"""
for i in range(n):
print a


>>>f=fib #可以用一个变量表示函数
>>>f(3)
1
1
1

>>>fib(a=2) #多个可选参数赋值可以直接写"参数变量名=值"来快速赋值
2
2
4.2. Lambda函数

一种无名函数的速写法

def make_incrementor(n):
return lambda x: x+n

f=make_incrementor(n)
#f等价于
#def f(x):
# return x+n
4.3. 不定长参数 *para,**para

参数格式为 *para 表示接受一个元组

为 **para 表示接受一个字典

*para要在**para之前


def test(*args,**dic):
for arg in args :
print arg
for k,v in dic.iteritems():
print k ,':',v

>>> test("yes",1,2,me="张沈鹏",where="中国") #"yes",1,2传递给元组;me="张沈鹏",where="中国"传递给字典
yes
1
2
me : 张沈鹏
where : 中国
4.4. @ 装饰器

@A def B:pass 等价于 def B:pass B=A(B) 即将函数B作为参数传给参数A

from time import time
#测试运行时间
def cost_time(func):
def result(*args,**dic):
beign=time()
func(*args,**dic)
print "cost time : ",time()-beign
return result

@cost_time
def show(n):
for x in range(n):print x

>>> show(10)
0
1
2
3
4
5
6
7
8
9
cost time : 0.0469999313354
4.5. 生成器表达式

生成器表达式:类似于没有中括号的列表推导式,可用在参数中

>>>sum(i*i for i in range(10))
285

>>>unique_words=set(word for line in page for word in line.split())#page为打开的文件

>>>data='golf'

>>>list(data[i] for i in range(len (data)-1,-1,-1))
['f','l','o','g']
4.6. yield

每次调用返回一个值,并记录当前执行位置所有的变量

def reverse(data):
for index in range(len(data)-1,-1,-1):
yield data[index]

for char in reverse("golf"):
print char,
输出

f l o g
5. 常用函数

5.1. eval

对字符串参数运算,求值

>>> eval("1 + 2*3") #可以方便的用来做四则运算
7
>>> a=1
>>> eval('a+1') #可以访问变量
2
5.2. exec

将字符串参数作为python脚本执行

>>> exec('a="Zsp"')
>>> a
'Zsp'
5.3. execfile

和exec类似,不过是用来打开一个文件,并作为python脚本执行

5.4. dir

显示对象的所有属性(即可以用"."操作直接访问)

>>> dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
5.5. help

help(类/函数) 返回相应对象的文档字符串

>>> help(vars)
Help on built-in function vars in module __builtin__:

vars(...)
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
5.6. len

返回序列/字典的长度

>>> len([1,2,3])
3
5.7. print

输出字符串 用法演示:

print "Today ", #加逗号,输出后不换行

name="ZSP"

print name,"cost $",10 #输出多个变量

print "hello,%s!"%name #%s 表示用str转化为字符串

for x in xrange(1,11):
print '%2d %3d' % (x,x*x) #小数输出如 %5.3f
对于字典可以用变量名来直接格式化,如:

>>>table={'Sjoerd':4127,'Jack':4098,'Dcab':8637678}
>>>print 'Jack:%(Jack)d; Sjoerd:%(Sjoerd)d; Dcab:%(Dcab)d' %
table
Jack:4098; Sjoerd:4127; Dcab:8637678
同时,函数vars()返回包含所有变量的字典,配合使用,无坚不摧!

5.8. raw_input


x=raw_input("Please enter an sentence:") #将输入的内容赋值给x
5.9. range


range(10,0,-3)#参数的含义为起点(默认为0),终点(不含终点),步长(默认为1)
>>>[10,7,4,1]
和for...in配合使用

a=['cat','door','example']
for i in range(len(a)):#len()函数为求序列的长度
print i,a[i]
5.10. filter

filter(function , sequence) 返回序列,为原序列中能使function返回true的值

>>>a=[1,2,3,4]
>>>filter(lambda x:x%2,a)
[1, 3]
5.11. map

map(function,sequence,[sequence...])

返回序列,为对原序列每个元素分别调用function获得的值.

可以传入多个序列,但function也要有相应多的参数,如

map(lambda x,y,z:x+y+z,range(1,3),range(3,5),range(5,7))

计算过程为

1+3+5=9

2+4+6=12

返回[9,12]

5.12. reduce

reduce(function,sequence,[init])

返回一个单值为,计算步骤为 :

第1个结果=function(sequence[0],sequence[1])
第2个结果=function(第1个结果,sequence[2])
返回最后一个计算得值
如果有init,则先调用function(init,sequence[0])
sequence只有一个元素时,返回该元素,为空时抛出异常.
如 reduce(lambda x,y:x+y,range(3),99) 的计算为

99+0=99 => 99+1=100 => 100+2=102

返回102

注:实际使用中用内建函数sum来完成这个累加更合适,如这里等价sum(range(3),99)

5.13. zip

zip用于多个sequence的循环

questions=['name','quest','favorite color']
answers=['lancelot','the holy grail','blue']

for q,a in zip(questions,answers):
print 'What is your %s ? It is %s.'%(q,a)
输出:

What is your name ? It is lancelot.
What is your quest ? It is the holy grail.
What is your favorite color ? It is blue.
5.14. reversed反向循环


for i in reversed(range(1,4)):
print i
输出:

3
2
1
5.15. sorted排序

返回一个有序的新序列

>>>sorted([2,5,1,4])
[1, 2, 4, 5]
5.16. enumerate 返回索引位置和对应的值


for i,v in enumerate(['tic','tac','toe'])
print i,v
输出:

0 tic
1 tac
2 toe
5.17. open/文件操作

f=open('/tmp/hello','w')

#open(路径+文件名,读写模式)

#读写模式:r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件.常用模式

如:'rb','wb','r+b'等等

f.read([size]) size未指定则返回整个文件,如果文件大小>2倍内存则有问题.f.read()读到文件尾时返回""(空字串)

file.readline() 返回一行

file.readline([size]) 返回包含size行的列表,size 未指定则返回全部行

for line in f: print line #通过迭代器访问

f.write("hello\n") #如果要写入字符串以外的数据,先将他转换为字符串.

f.tell() 返回一个整数,表示当前文件指针的位置(就是到文件头的比特数).

f.seek(偏移量,[起始位置])

用来移动文件指针

偏移量:单位:比特,可正可负

起始位置:0-文件头,默认值;1-当前位置;2-文件尾

f.close() 关闭文件

6. 模块化

6.1. 导入模块

模块的查找路径

1.当前的目录

2.环境变量PYTHONPATH所指的目录列表

3.python解释器的安装目录

如将代码保存上述的一个目录中的的fibo.py文件中,便可以


import fibo
fibo.function()
如果想直接使用fibo.function可以重命名这个函数,如


f=fibo.function
f()
也可以


form fibo import function
function()
甚至可以form fibo import *

可以 form 包.子包.模块 imort 函数

然后就直接使用该函数,不需要加前缀

6.2. 包

引用推荐写法为

form 包 import 模块

几个功能类似的模块可以组合成一个包,

比如一个可以处理.wav,.mp3,.wma等音频文件的有类似如下结构:


Sound/
__init__.py
Formats/
__init__.py
wavread.py
wavwrite.py
mp3read.py
mp3write.py
wmaread.py
wmawrite.py
Effects/
__init__.py
echo.py
surround.py
reverse.py
只有当init.py存在时python才将该文件夹视为一个包.

该文件可以为空文件 一般在init.py文件中定义一个all列表,包含要import *时要导入的模块. 如Sound/Effects/init.py可以有如下内容

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

包的作者在发布包时可以更新这个列表,也可以根据需要让某个模块不支持import *

对于包中同一个文件夹下的模块可以把

form 包.子包 imort 模块

简写为 imort 模块

6.3. 面向对象

6.3.1. 概要


class ClassName:
"类文档,可以通过类名.__doc__访问"
def f(self):#self为每个类函数的必要的一个参数,可以通过它来访问当前实例
return self.content

def __init__(self,word=''):#构造函数
#构造函数,可以初始化变量,可以有参数"
self.content=word
self.__name=word #私有变量,以"__"开头,不以"__"结尾的变量
创建类实例 x=ClassName("good")

6.3.2. 类继承

class DerivedClassName(BassClassName):

pass
如果基类定义在另一个模块中, 要写成

modname.BaseClassName

派生类的函数会覆盖基类的同名函数

如果想扩充而不是改写基类的函数,可以这样调用基类函数

BaseClassName.methodname(self,arguments)

注意:该基类要在当前全局域或被导入

class A:
def hi(self):
print "A"
class B:
def hi(self):
A.hi(self)
super(B).hi() #通过super关键字可以获得当前类的基类
print "B"

B().hi()
输出

A
B
6.3.3. 多重继承

类多继承

class DerivedClassName(Base1,Base2,Base3):
pass
对于该类函数的解析规则是深度优先,先是Base1,然后是Base1的基类,诸如此类.

class A:
def hi(self):
print "A"

class B:
def hi(self):
print "B"

class C(A,B):
pass

C().hi()
输出:

A
6.4. 操作符重载

通过定义类的一些约定的以""开头并结尾的函数,可以到达重载一些特定操作的目的,下面是是一些常用的重载

6.4.1. __str__ / __unicode__

当print一个对象实例时,实际是print该实例str()函数的返回值.

class A:
def __str__(self):
return "A"
def __unicode__(self):
return "uA"

print A()
print unicode(A())
输出

A
uA
unicode和str类似,不过返回Unicode字符串.

6.4.2. 比较操作

x
x<=y x.le(y)

x==y x.eq(y)

x!=y 或 x<>y x.ne(y)

x>y x.gt(y)

x>=y x.ge(y)

cmp( self, other) 用来简化比较函数的定义 self < other返回负数,相等时返回0,self>other时返回正数


class A:
def __init__(self,i):
self.i=i
def __cmp__(self,other):
return self.i-other.i

print A(1)>A(2)
输出

False
6.4.3. __iter__

for ... in 循环即就是通过这个函数遍历当前容器的对象实例 可配合yield方便的编写这个函数(参见基本语法yield)

class A:
def __init__(self,n):
self.n=n
def __iter__(self):
n=self.n
while n:
m=n%2
n/=2
yield m

for i in A(5):
print i,
输出

1 0 1
另有一种繁琐的实现: 返回一个可以通过next()函数遍历的对象,当结束时抛出StopIteration异常

6.5. 类相关函数

6.5.1. type

返回对象的类型

>>> type("")

>>> type("")==str
True

>>> type([])

>>> type([])==list
True

>>> type({})


>>> type(())


>>> class A:pass

>>> type(A)


>>> type(A())


>>> import types #在types模块中有许多类型的定义

>>> type(A)==types.ClassType
True
6.5.2. getattr / hasattr /delattr

getattr:通过类实例和一个字符串动态的调用类函数/属性

class A:
def name(self):
return "ZSP"
def hello(self):
return "nice to meet me ."

def say(obj,attr):
print getattr(obj,attr)()

a=A()
say(a,"name")
say(a,"hello")
输出

ZSP
nice to meet me .
hasattr 用来判断实例有无该函数/属性

delattr 用来删除实例的函数/属性

6.5.3. property

通过值的方式调用实例无参函数

class A(object):
def __init__(self): self._x = None
def getx(self): return self._x
def setx(self, value): self._x = value
def delx(self): self._x=None
x = property(getx, setx, delx, "I'm the 'x' property.")
a=A()
print a.x

a.x="ZSP"
print a.x

del a.x
print a.x
输出

None
ZSP
None
可以方便的定义一个只读属性

class A(object):
@property
def x(self): return "Property"
调用

>>>a=A()

>>>print a.x
Property

>>>a.x="ZSP" #只读属性,不能更改
Traceback (most recent call last):
File "D:\Profile\Untitled 2.py", line 9, in
a.x="ZSP"
AttributeError: can't set attribute
6.5.4. isinstance( object, classinfo)

判断一个对象是否是一个类的实例

>>>class A:pass

>>>class B:pass

>>>a=A()

>>>isinstance(a,A)
True

>>>isinstance(a,B)
False
Python 常用模块体验 ::-- ZoomQuiet [2007-11-10 06:37:48]

目录
Py常用模块汇编
zshelve 对象持久模块
发布
补丁::
fast UserDict
CPUG联盟::
CPUG::门户plone
BPUG
SPUG
ZPUG
SpreadPython Python宣传
7. Py常用模块汇编

'Python 标准库2.0 整理者

Python 江湖 QQ 群: 43680167
Feather (校对) gt: andelf@gmail.com
一些有用的Python函式庫列表 » 程式設計 遇上 小提琴

::-- ZoomQuiet [2007-11-10 07:39:01]


CPUG联盟::
CPUG::门户plone
BPUG
SPUG
ZPUG
SpreadPython Python宣传
7.1. zshelve 对象持久模块

{{{Jiahua Huang reply-to python-cn@googlegroups.com, to "python. cn" , date Nov 8, 2007 5:41 PM subject [CPyUG:34726] 贴个 zlib 压缩的 zshelve 对象持久模块 }}} 这个给 Python 标准库的 shelve.py 添加了 zlib 压缩, 减小数据库文件体积,以改善磁盘 io 性能

7.1.1. 发布

http://zshelve.googlecode.com/svn/trunk/

加了个命令行工具:

huahua@huahua:tmp$ zshelve
commandline tool for zshelve databases

Usage: zshelve FILE dump Dump the data tree
zshelve FILE keys List of keys
zshelve FILE get KEY Dump value for key
zshelve FILE set KEY VALUE Set db[key] = value
zshelve FILE has_key KEY True if database has the key
zshelve FILE search_key KEY Search key
zshelve FILE search_value VALUE Search value

huahua@huahua:tmp$ zshelve set tes.db a 1
huahua@huahua:tmp$ zshelve dump tes.db
|- a
| | - 1
huahua@huahua:tmp$ zshelve set tes.db b "dict(a=1,b=2,c=3,d={'s':'4'})"
huahua@huahua:tmp$ zshelve dump tes.db
|- a
| |- 1
|- b
| |- a
| | |- 1
| |- c
| | |- 3
| |- b
| | |- 2
| |- d
| | |- s
| | | |- 4
对比::

>>> import zshelve
>>> import shelve
>>> zdb = zshelve.open('/tmp/zshelve.db')
>>> db = shelve.open('/tmp/shelve.db')
>>> zdb['1'] = dict(a='0123456789'*10000000)
>>> db['1'] = dict(a='0123456789'*10000000)
>>> zdb.sync()
>>> db.sync()
看看文件大小差异::

huahua@huahua:zshelve$ ll /tmp/*shelve.db
-rw-r--r-- 1 huahua huahua 96M 2007-11-08 17:36 /tmp/shelve.db
-rw-r--r-- 1 huahua huahua 204K 2007-11-08 17:36 /tmp/zshelve.db
7.1.2. 补丁::


--- shelve.py 2007-05-03 00:56:36.000000000 +0800
+++ zshelve.py 2007-11-08 17:25:59.000000000 +0800
@@ -70,6 +70,7 @@ except ImportError:

import UserDict
import warnings
+import zlib ## use zlib to compress dbfile

__all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"]

@@ -80,13 +81,14 @@ class Shelf(UserDict.DictMixin):
See the module's __doc__ string for an overview of the interface.
"""

- def __init__(self, dict, protocol=None, writeback=False):
+ def __init__(self, dict, protocol=None, writeback=False, compresslevel=2):
self.dict = dict
if protocol is None:
protocol = 0
self._protocol = protocol
self.writeback = writeback
self.cache = {}
+ self.compresslevel = compresslevel

def keys(self):
return self.dict.keys()
@@ -109,7 +111,7 @@ class Shelf(UserDict.DictMixin):
try:
value = self.cache[key]
except KeyError:
- f = StringIO(self.dict[key])
+ f = StringIO(zlib.decompress(self.dict[key]))
value = Unpickler(f).load()
if self.writeback:
self.cache[key] = value
@@ -121,7 +123,7 @@ class Shelf(UserDict.DictMixin):
f = StringIO()
p = Pickler(f, self._protocol)
p.dump(value)
- self.dict[key] = f.getvalue()
+ self.dict[key] = zlib.compress(f.getvalue(), self.compresslevel)

def __delitem__(self, key):
del self.dict[key]
@@ -168,32 +170,32 @@ class BsdDbShelf(Shelf):
See the module's __doc__ string for an overview of the interface.
"""

- def __init__(self, dict, protocol=None, writeback=False):
- Shelf.__init__(self, dict, protocol, writeback)
+ def __init__(self, dict, protocol=None, writeback=False, compresslevel=2):
+ Shelf.__init__(self, dict, protocol, writeback, compresslevel)

def set_location(self, key):
(key, value) = self.dict.set_location(key)
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())

def next(self):
(key, value) = self.dict.next()
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())

def previous(self):
(key, value) = self.dict.previous()
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())

def first(self):
(key, value) = self.dict.first()
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())

def last(self):
(key, value) = self.dict.last()
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())


@@ -204,12 +206,12 @@ class DbfilenameShelf(Shelf):
See the module's __doc__ string for an overview of the interface.
"""

- def __init__(self, filename, flag='c', protocol=None, writeback=False):
+ def __init__(self, filename, flag='c', protocol=None,
writeback=False, compresslevel=2):
import anydbm
- Shelf.__init__(self, anydbm.open(filename, flag), protocol, writeback)
+ Shelf.__init__(self, anydbm.open(filename, flag), protocol,
writeback, compresslevel)


-def open(filename, flag='c', protocol=None, writeback=False):
+def open(filename, flag='c', protocol=None, writeback=False, compresslevel=2):
"""Open a persistent dictionary for reading and writing.

The filename parameter is the base filename for the underlying
@@ -222,4 +224,4 @@ def open(filename, flag='c', protocol=No
See the module's __doc__ string for an overview of the interface.
"""

- return DbfilenameShelf(filename, flag, protocol, writeback)
+ return DbfilenameShelf(filename, flag, protocol, writeback, compresslevel)

一行代码让 UserDict.UserDict 的类加速 4 倍
::-- ZoomQuiet [2007-11-10 07:34:49]

目录
fast UserDict

7.2. fast UserDict

{{{Jiahua Huang reply-to python-cn@googlegroups.com, to "python. cn" , date Nov 10, 2007 3:28 PM subject [CPyUG:34791] 一行代码让 UserDict.UserDict 的类加速 4 倍 }}} 发现 Python 标准库里好些字典类从 UserDict.UserDict 派生, 而不是从 dict 派生, 是因为 旧版 python 内建类型不能派生子类,

那么这会不会影响速度呢,

先给两个分别继承 UserDict.UserDict 和 dict 的类 URdict, Rdict

>>> import UserDict
>>> class URdict(UserDict.UserDict):
... '''dict can search key by value
... '''
... def indexkey4value(self, value):
... '''search key by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.indexkey4value('Other')
... 'b'
... '''
... try:
... ind = self.values().index(value)
... return self.keys()[ind]
... except:
... return None
... def key4value(self, svalue):
... '''search key by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.key4value('Other')
... 'b'
... '''
... for key, value in self.iteritems():
... if value == svalue:
... return key
... def keys4value(self, svalue):
... '''search keys by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.keys4value('Other')
... ['b', 'e']
... '''
... keys=[]
... for key, value in self.iteritems():
... if value == svalue:
... keys.append(key)
... return keys
...
>>>
>>> class Rdict(dict):
... '''dict can search key by value
... '''
... def indexkey4value(self, value):
... '''search key by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.indexkey4value('Other')
... 'b'
... '''
... try:
... ind = self.values().index(value)
... return self.keys()[ind]
... except:
... return None
... def key4value(self, svalue):
... '''search key by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.key4value('Other')
... 'b'
... '''
... for key, value in self.iteritems():
... if value == svalue:
... return key
... def keys4value(self, svalue):
... '''search keys by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.keys4value('Other')
... ['b', 'e']
... '''
... keys=[]
... for key, value in self.iteritems():
... if value == svalue:
... keys.append(key)
... return keys
...
>>>

>>> import time
>>> def _timeit(_src):
... exec('''
... _t0 = time.time()
... %s
... _t1 = time.time()
... _t3 = _t1 - _t0
... '''%_src)
... return _t3
...
>>> ran = range(100000)

再弄俩实例
>>> u = URdict()
>>> r = Rdict()

看看插入速度
>>> _timeit("for i in ran: u[i]=i")
0.1777961254119873
>>> _timeit("for i in ran: r[i]=i")
0.048948049545288086

看看原始 dict 的速度
>>> _timeit("for i in ran: d[i]=i")
0.041368961334228516
可以看到, UserDict.UserDict 确实严重影响速度,

python 标准库里边好多 UserDict 的都应该换成 dict , 以提高性能

不过,一个个修改 Python 标准库似乎又不合适,

再次使用一招鲜,直接干掉 UserDict

在使用/导入那些模块前先来一行

>>> import UserDict; UserDict.UserDict = dict
完了再导入模块来试试

>>> u = URdict()
>>> _timeit("for i in ran: u[i]=i")
0.042366981506347656
一行代码让速度提高 4 倍.

转载自:
http://wiki.woodpecker.org.cn/moin/PyAbsolutelyZipManual

Apache手动安装成Windows的服务

将Apache2手动安装成Windows的服务

如果在安装时没有将Apache安装成Windows的服务,那么安装结束后,也可以通过命令行来实现。在目录下的bin文件夹中,有Apache.exe文件。具有以下执行的参数:

  安装为Windows服务
  apache -k install -n "服务名"
  要安装一个使用特定配置的服务,安装时指定配置文件:
  apache -k install -n "服务名" -f "\my server\conf\my.conf"
  要移除一个Apache服务,使用:
  apache -k uninstall -n "服务名"

  如果没有指定服务名,缺省地,将使用"Apache2"。
  更多的命令可以用 apache -h 命令来查看。

将Apache2.2.8手动安装成Windows的服务

Apache仅能够在Windows NT上作为服务运行。
你可以选择在安装Apache时自动将其安装为一个服务。如果你选择"for all users",那么Apache将会被安装为服务。如果你选择了"only for the Current User",你可以在安装后手动将Apache注册为服务。注意,你必须是Administrators组的成员才能成功注册服务。
使用Apache Service Monitor工具,可以查看和管理你所在网络上的所有机器上安装的Apache服务的状态。为了能够使用这个工具管理Apache服务,你必须首先自动或手动安装Apache服务。
你可以在Apache安装目录的bin子目录下,使用如下命令将Apache安装为Windows NT服务:
httpd -k install
如果你想指定服务的名称,可以使用下面的命令。当你在同一机器上安装多个Apache服务时,你必须为它们指定不同的名字。
httpd -k install -n "服务名"
如果你想为不同名称的服务使用不同的配置文件,则安装时需要指定配置文件:
httpd -k install -n "服务名" -f "c:\files\my.conf"
如果你使用的是第一个命令,也就是除 -k install 外没有其它命令行参数,那么被安装的服务名称将是:Apache2.2 ,配置文件将使用conf\httpd.conf 。
要移除一个Apache服务很简单:
httpd -k uninstall
或者使用下述命令移除特定名称的Apache服务:
httpd -k uninstall -n "服务名"
通常,启动、重启、关闭Apache服务的方法是使用Apache Service Monitor工具,另外也可以使用控制台命令:NET START Apache2.2 和 NET STOP Apache2.2 或者通过Windows服务控制面板。在启动Apache服务之前,你应当使用下面的命令检查一下配置文件的正确性:
httpd -n "服务名" -t
你可以通过命令行开关来控制Apache服务。要启动一个已经安装的Apache服务,可以使用:
httpd -k start
要停止一个已经安装的Apache服务,可以使用:
httpd -k stop

httpd -k shutdown
要重启一个运行中的Apache服务,强制它重新读取配置文件,可以使用:
httpd -k restart
默认情况下,Apache服务将被注册为以本地系统用户(LocalSystem帐号)身份运行。LocalSystem帐号没有网络权限,不能通过任何Windows安全机制访问网络,包括文件系统、命名管道、DCOM或secure RPC ,但是它对于本地资源却拥有广泛的特权。

转载自:
http://chenergan.javaeye.com/blog/184470

怎么查看端口占用情况?

开始--运行--cmd 进入命令提示符 输入netstat -ano 即可看到所有连接的PID 之后在任务管理器中找到这个PID所对应的程序如果任务管理器中没有PID这一项,可以在任务管理器中选"查看"-"选择列"

经常,我们在启动应用的时候发现系统需要的端口被别的程序占用,如何知道谁占有了我们需要的端口,很多人都比较头疼,下面就介绍一种非常简单的方法,希望对大家有用

假如我们需要确定谁占用了我们的9050端口

1、Windows平台
在windows命令行窗口下执行:

C:\>netstat -aon|findstr "9050"

TCP 127.0.0.1:9050 0.0.0.0:0 LISTENING 2016

看到了吗,端口被进程号为2016的进程占用,继续执行下面命令:

C:\>tasklist|findstr "2016"

tor.exe 2016 Console 0 16,064 K
很清楚吧,tor占用了你的端口。

转载自:
http://www.blogjava.net/rabbit/archive/2008/03/12/185559.html

日语“谢谢”的几种说法

日语的“谢谢”有几种说法:

1.一般口语说法:ありがどう。谢谢!(a li ga do u。“u”是不发音的,用以拉长前面“do”的读音。以下几句的“u”都一样。这一句式属于简体,多用于文章和日常对话。)

2.平辈之间比较尊敬对方的说法:ありがどうございます。很感谢(你)啊!(a li ga do u go za i ma su。“ma su”是敬体,表示对听话人尊敬,显得客气,有礼貌。多用于演讲、广播、电视、书信。)

3.平辈或与长辈之间更尊敬和强调的说法:どうもありがどうございます。真的非常感谢(你)啊!(do mo a li ga do u go za i ma su。“do mo”有强调之意。)

4.对过去的帮助表示谢谢的说法(更尊敬和强调):どうもありがどうございました。(今天/昨天)真的非常感谢(你)啊!(do mo a li ga do u go za i ma xi ta。对讲话以前已经发生的动作/事情表示由衷的感谢。)

2010年6月24日星期四

银行家算法

简介

  银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源,但系
银行家算法
统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。为实现银行家算法,系统必须设置若干数据结构。
  要解释银行家算法,必须先解释操作系统安全状态和不安全状态。
  安全序列是指一个进程序列{P1,…,Pn}是安全的,如果对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源量之和。
安全状态

  如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。
不安全状态

  不存在一个安全序列。不安全状态不一定导致死锁。
[编辑本段]银行家算法的数据结构

  1)可利用资源向量Available
  是个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j]=K,则表示系统中现有Rj类资源K个。
  2)最大需求矩阵Max
  这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。
  3)分配矩阵Allocation
  这也是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的 数目为K。
  4)需求矩阵Need。
  这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个,方能完成其任务。
  Need[i,j]=Max[i,j]-Allocation[i,j]
[编辑本段]银行家算法原理:

  我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
  为保证资金的安全,银行家规定:
  (1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
  (2) 顾客可以分歧贷款,但贷款的总数不能超过最大需求量;
  (3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
  (4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金.
  操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请的资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源,若没有超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配。
  运行平台:Windows XP VS2005
  编程语言:C#
[编辑本段]算法的实现

初始化

  由用户输入数据,分别对可利用资源向量矩阵AVAILABLE、最大需求矩阵MAX、分配矩阵ALLOCATION、需求矩阵NEED赋值。
银行家算法

  在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统性能。在该方法中把系统的状态分为安全状态和不安全状态,只要能使系统始终都处于安全状态,便可以避免发生死锁。
  银行家算法的基本思想是分配资源之前,判断系统是否是安全的;若是,才分配。它是最具有代表性的避免死锁的算法。
  设进程cusneed提出请求REQUEST [i],则银行家算法按如下规则进行判断。
  (1)如果REQUEST [cusneed] [i]<= NEED[cusneed][i],则转(2);否则,出错。
  (2)如果REQUEST [cusneed] [i]<= AVAILABLE[cusneed][i],则转(3);否则,出错。
  (3)系统试探分配资源,修改相关数据:
  AVAILABLE[i]-=REQUEST[cusneed][i];
  ALLOCATION[cusneed][i]+=REQUEST[cusneed][i];
  NEED[cusneed][i]-=REQUEST[cusneed][i];
  (4)系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。
安全性检查算法

  (1)设置两个工作向量Work=AVAILABLE;FINISH
  (2)从进程集合中找到一个满足下述条件的进程,
  FINISH==false;
  NEED<=Work;
  如找到,执行(3);否则,执行(4)
  (3)设进程获得资源,可顺利执行,直至完成,从而释放资源。
  Work+=ALLOCATION;
  Finish=true;
  GOTO 2
  (4)如所有的进程Finish= true,则表示安全;否则系统不安全。
[编辑本段]算法

  /// 资源数
  public static int resourceNumber;
  /// 进程数
  public static int processNumber;
  /// 可用资源数组
  public static int[] Available;
  /// 工作向量
  public static int[] work;
  /// 它表示系统是否有足够的资源分配给进程
  public static bool[] Finish;
  /// 最大需求矩阵
  public static int[][] Max;
  /// 分配矩阵
  public static int[][] Allocation;
  /// 需求矩阵
  public static int[][] Need;
  /// 安全序列
  public static int[] SafeSequence;
  /// 资源请求向量
  public static int[] Request;
  算法思想:
  主要是:递归+深度优先搜寻+回溯
  算法源代码如下:
  /// 深搜+回溯实现银行家算法
  /// 已完成的进程数
  public void DFS_searchSafeSequence(int n)
  {
  if (n == processNumber)
  {
  //找到一个安全序列,可以显示所有安全序列
  //显示在richTextBoxshow.Text上
  for (int i = 0; i < processNumber; i++)
  {
  richTextBoxshow.Text += SafeSequence[i] + " ";
  }
  richTextBoxshow.Text += "\n";
  return;
  }
  for (int i = 0; i < processNumber; i++)
  {
  if (Finish[i] == false)//进程尚未完成
  {
  //判断现有资源是否可以满足这个进程
  bool isOK = true;
  for (int j = 0; j < resourceNumber; j++)
  {
  if (Need[i][j] > work[j])
  {
  isOK = false;
  break;
  }
  }
  //可以满足
  if (isOK)
  {
  //先试探的将资源分配给这个进程
  for (int j = 0; j < resourceNumber; j++)
  {
  work[j] += Allocation[i][j];
  }
  //已经完成
  Finish[i] = true;
  //加入安全序列
  SafeSequence[n] = i;
  //继续搜索
  DFS_searchSafeSequence(n+1);
  //回溯
  Finish[i] = false;
  SafeSequence[n] = -1;
  for (int j = 0; j < resourceNumber; j++)
  {
  work[j] -= Allocation[i][j];
  }
  }
  }
  }
  }


转载自:
http://baike.baidu.com/view/93075.htm

中断处理过程

一个完整的中断处理过程应该包括:中断请求、中断排队或中断判优、中断响应、中断处理和中断返回等环节,下面分别进行讨论。
  1.中断请求
  中断请求是由中断源向CPU发出中断请求信号。外部设备发出中断请求信号要具备以下两个条件:
  (1)外部设备的工作已经告一段落。例如输入设备只有在启动后,将要输入的数据送到接口电路的数据寄存器(即准备好要输入的数据)之后,才可以向CPU发出中断请求。
  (2)系统允许该外设发出中断请求。如果系统不允许该外设发出中断请求,可以将这个外设的请求屏蔽。当这个外设中断请求被屏蔽,虽然这个外设准备工作已经完成,也不能发出中断请求。
  2.中断排队
  中民申请是随机的,有时会出现多个中断源同时提出中断申请。但CPU每次只能响应一断源的请求,那么究竟先响应哪一个中断源的请求呢?这就必须根据各中断源工作性质的轻重缓急,预先安排一个优先级顺序,当多个中断源同时申请中断时,即按此优先级顺序进行排队,等候CPU处理。一般是把最紧迫和速度最高的设备排在最优先的位置上。CPU首先响应优先级别最高的中断源。当中断处理完毕,再响应级别低的中断申请。
  中断排队可以采用硬件的方法,也可以采用软件的方法。前者速度快,但需要增加硬设备;后者无需增加硬设备,但速度慢,特别是中断源很多时尤为突出。
  软件优用查询技术。当CPU响应中断后,就用软件查询以确定是哪些外设申请中断,并判断它们的优先权。一个典型的软件优先权排队接口电路如图6-10所示,图中把8个外设的中断请求触发器组合起来,作为一具端口,并赋以设备号。把各个外设的中断请求信号相“或”后,作为INTR信号,故其中任一外设有中断请求,都可向CPU送出INTR信号。当CPU响应中断后,把中断寄存器的状态作为一个外设读入CPU,逐位检测它们的状态,若哪一位为1,则该位对应的外设有中断请求,应转到相应的服务程序的入口。其流程如图6-11所示。
相应的查询程序如下:

  XOR AL,AL ;CF清0
  IN AL,20H ;输入中断请求触发器的状态
  RCL AL,1 ;左移一位,检测最高位是否有请求
  JC POW ;有,转相应服务程序
  RCL AL,1 ;否,检测下一位
  JC DISS
  …
  查询方法的优点是:
  (1)询问的次序,即优先权的次序。显然,最先询问的,优先权的级别最高。
  (2)省硬件。不需要有判断与确定优先权的硬件排队电路。
  缺点是:由询问转至相应的服务程序入口的时间长,尤其是在中断源较多的情况下。
  硬件优先权排队电路,目前均采用专用中断管理接口芯片如8259A等。
  3.中断响应
  经中断排队后,CPU收到一个当前申请中断的中断源中优先级别最高的中断请求信号,如果允许CPU响应中断(IF=1),在执行完一条指令后,就中止执行现行程序,而响应中断申请。此时首先由硬件电路保护断点,即将当前正在执行的程序的段地址(CS)和偏移地址(IP)以及标志寄存器(FR)压入堆栈;然后关闭CPU内的允许中断触发器IF(可屏蔽中断时);接下来就是寻找中断服务程序的入口地址。
  寻找中断服务程序入口地址的方法分软件和硬件两种。软件方法即为上述的查询方式。在硬件方式中,目前均采用矢量中断方式。所谓矢量中民即当CPU响应中断后,由提出中断请求的中断源向CPU发去一个中断矢量,CPU根据这个中断矢量找到中断程序的入口地址,而转到相应的中断服务程序。以Intel为CPU的PC系列微型计算机系统就采用矢量中断方式。
  4.中断处理
  中断响应后,进入中断处理,即执行中断服务程序。在中断服务程序中,首先要保护现场,把中断服务程序中所要使用到的寄存器内容保护起来,如将经们的内容压入堆栈,然后才进行与此次中断有关的相应服务处理。处理完毕要恢复现用到的寄存器内容保护起来,如将经们的内容压入堆栈,然后才进行与此次中断有关的相应服务处理。处理完毕要恢复现场,即恢复中断前各寄存器的内容。如果在中断服务程序中允许嵌套(可屏蔽中断方式时),还应用STI指令将IF=1(即开中断)。
  5.中断返回
  通常,中断服务程序的最后一条指令是一条中断返回指令。当CPU执行这条指令时,把原来程序被中断的断点地址从堆栈中弹回CS和IP中,原来的FR弹回FR。这样,实中断的程序就可以从断点处继续执行下去。CPU从中断服务程序又回到了被中断的主程序。
  在实际应用系统中,中断可以嵌套,即可以有多重中断。所谓多重中断,就是在CPU执行某一中断服务程序时,又有优先级别更高的中断源申请断,此时,CPU应当暂停止这个中断服务,而去处理优先级别比它高的中断申请。处理完毕再返回中断占,继续处理较低优先级别的中断。这种在低级中断中还嵌套有高级中断的多重中断方式,对实时处理系统是很有用的。

转载自:
http://202.116.0.161/wjyl/site/text/chapter6/6.3.2.htm

“操作系统概论”习题解答之引言

1.计算机系统由哪两大部分组成?

  答:计算机系统是能按照人的要求接受和存储信息,自动进行数据处理和计算,并输出结果信息的机器系统。计算机系统由两大部分组成:硬件(子)系统和软件(子)系统,其中硬件子系统是系统赖以工作的实体,它是有关的各种物理部件的有机的结合。软件子系统由各种程序以及程序所处理的数据组成,这些程序的主要作用是协调各个硬件部件,使整个计算机系统能够按照指定的要求进行工作。

  硬件子系统包括中央处理器、主存存储器、输人输出控制系统和各种外围设备。

  软件子系统包括系统软件、支援软件和应用软件三个部分。

  2.什么是计算机的操作系统?

  答:操作系统(Operating System缩写 OS)是一种系统软件。它对程序的执行进行控制,还使用户能方便地使用硬件提供的计算机功能,也使硬件的功能发挥得更好。它是一种用于管理计算机系统资源和控制程序执行的系统软件,它扩充系统的功能,为用户提供方便的使用接口和良好的运行环境。

  3.操作系统管理哪些资源?

  答:操作系统管理计算机系统的资源,其中硬件资源主要包括中央处理器、主存储器和各种外围设备;软件资源包括了程序和数据,通常这些程序和数据是以文件的方式存储和使用的。它说明资源的使用情况,实现多用户共享计算机系统的各种资源。

  4.为什么要把“I/O指令”等定义为特权指令?

  答:若用户程序中直接使用 I/O指令,则可能引起冲突或由于某些意外而造成错误。例如,用户程序中要启动磁带后取磁带上的信息,但可能操作员错拿了另一用户的磁带,把它以磁带机上,这时用户程序启动磁带机后从磁带上得到的信息实际上不是自己需要的,就可能造成程序执行后得到结果不正确。更糟糕的是当用户程序启动磁带机的目的是要把一些信息记到磁带上,将可能覆盖已在磁带上的信息,即把另一用户磁带上的信息破坏了。为了防止类似于这样一类的错误启动外围设备的工作不是用户程序直接做,而是由操作系统来做。

  5.操作系统是如何防止用户使用特权指令的?

  答:为了防止用户程序中使用特权指令,计算机硬件结构区分两种操作模式:目态和管态,其中目态下只能使用除特权指令以外的指令,管态下可以使用全部指令。当在目态下使用特权指令时,硬件就发出信号:“程序使用非法指令”,且不允许程序继续执行下去。所以可以把用户程序置在目态下运行,而操作系统中必须使用特权指令的那部分程序可在管态下运行,这样可保证计算机系统的安全可靠。

  6.操作系统为什么要提供“系统调用”?

  答:系统调用是操作系统为用户程序提供的一种服务界面,也可以说是操作系统保证程序设计语言能正常工作的一种支持。在源程序一级,用户用程序设计语言描述算题任务的逻辑要求(如读文件、写文件等)。而这些要求的实现只通过调用操作系统提供的不同功能的子程序,即系统调用。

  7.批处理操作系统、实时操作系统和分时操作系统各有什么特点?

  答:批处理操作系统是将一批作业的程序和数据交给系统后,系统顺序控制作业的执行,当一个作业执行结束后自动转入下一个作业的执行。多道批处理操作系统,允许若干个作业同时装入主存储器,处理器轮流地执行各个作业,各个作业同时使用各自所需的外围设备。

  实时操作系统接收到外部信号后及时进行处理,并且要在严格的时限内处理完接收的事件。实时操作系统要求要有比分时操作系统更强的及时性。可靠性是实时系统最重要的设计目标之一。

  分时操作系统的主要特点是:①交互性。用户能够直接与计算机系统交互。②及时性。由于支持人机交互,所以主机应该尽快地对用户的要求给予响应。③独立性。这主要是指多个用户虽然在同时使用主机系统,但是他们相互之间是不干扰的。④多路性。分时操作系统在宏观上看,整个系统同时在为多个用户服务。

  8.从资源管理的观点来看,操作系统有哪些基本功能?

  答:从资源管理的观点看,操作系统的功能可分成五大部分,即:

  ①处理器管理。操作系统按照一定的调度算法分配处理机。

  ②存储管理。负责分配、回收和保护存储单元。

  ③文件管理。涉及到文件存储空间的分配与回收、文件目录管理、文件读写与保护。

  ④设备管理。对设备进行分配、回收与控制。

  ⑤作业管理。负责作业的调度和作业控制。

转载自:
http://www.zikao365.com/html/4_21_89_175/2007_4_27_sh8841275617247002654_0.htm

“操作系统概论”习题解答之存储管理

1.解释下列术语

  逻辑地址;绝对地址;地址转换

  答:逻辑地址:对于用户来说,他无须知道自己的作业究竟是在主存的什么位置,他们可以认为自己的程序和数据就是放在从0地址开始一组连续的地址空间中,这个地址空间是程序用来访问信息所用的一系列连续地址单元的集合,该地址空间就是逻辑地址空间。逻辑地址空间中,地址单元的编号称为逻辑地址。

  绝对地址:主存也被按照连续的存储单元进行编号,绝对地址空间就是主存中一系列连续存储信息的物理单元的集合,也称绝对地址空间为存储地址空间或物理地址空间。绝对地址空间中物理单元的编号称为绝对地址。 地址转换:由于一个作业装入到与其逻辑地址空间不一致的绝对地址空间,使得逻辑地址与绝对地址不同,而引起的对有关地址部分的调整,即逻辑地址转换成绝对地址的过程称为重定位,也称为地址转换。

  2.存储保护的目的是什么?怎样实现存储保护?

  答:存储保护的目的就是为了保护主存中各区域内的信息不被破坏,它包括存储的权限,存储不可跨越区域等等。为实现存储保护,必须由硬件和软件配合实现。比如在页式管理中,要由操作系统提供页表,硬件机构确定页的使用必须是安全的,如不能访问不属于自己的页等。

  3.什么叫重定位?重定位的方式有哪两种?比较它们的不同。

  答:由于一个作业装入到与其逻辑地址空间不一致的绝对地址空间,使得逻辑地址与绝对地址不同,而引起的对有关地址部分的调整,即逻辑地址转换成绝对地址的过程称为重定位,也称为地址转换。

  重定位有静态和动态两种情况。

  所谓静态重定位是在装入一个作业的时候,把作业中的指令地址和数据地址全部一次性地转换成绝对地址。

  所谓动态重定位是由软件和硬件相配合来实现的。地址重定位不再是装入的时候一次完成了,而是设置一个基址寄存器,装入作业的时候,将作业在主存区域的首地址放入到基址寄存器中。作业执行的时候,由硬件的地址转换机构动态地对地址进行转换,执行指令的时候,只要将逻辑地址加上基址寄存器的内容,就得到了绝对地址。

  静态重定位和动态重定位的不同在于:①静态重定位是在作业装入的时候一次完成,动态重定位是在作业执行时再实现的。②静态重定位是软件支持的,动态重定位是硬件和软件合作实现的。③静态重定位不能实现主存的移动,而动态重定位可以。④动态重定位还可能提供虚拟存储空间。

  4.比较固定分区、可变分区和页式存储管理的优缺点。

  答:固定分区优点:

  ①能支持多道程序设计。

  ②无需专门的硬件地址转换机构。

  缺点:

  ①主存利用率不算太高,分配中出现内部零头问题。

  ②分区大小固定不灵活,不能为程序动态申请内存。

  ③不具备虚拟存储能力。

  可变分区优点:

  ①支持多道程序设计。

  ②没有内部零头问题,主存利用率比固定分区高。

  ③采用移动技术后可以满足正在执行的作业的主存扩充的要求。

  缺点:

  ①动态重定位和保护措施需要硬件机构支持,成本高。

  ②由于有外部零头,所以主存利用率依然不算很高。

  ③移动技术开销很大。

  ④每次必须将作业完整调入并连续存放,主存利用率不高。

  ⑤不具备虚拟存储能力。

  页式存储管理优点:

  ①支持多道程序设计

  ②解决了外部零头问题,内部零头大大减少(一个作业平均只有50%页面大小的内部零头)主存利用率比较高。

  ③用户作业无需在主存中连续存放,提高主存的利用率。

  ④如果是分页虚拟存储管理,可以提供大容量的多个虚拟存储器,主存利用率更高了。

  缺点:

  ①动态重定位和保护措施需要硬件机构支持,成本高;

  ②采用页表,占用了一部分主存空间和处理机时间。

  ③分页虚拟存储管理中,增加了缺页中断的处理,增加了系统开销。

  5.采用可变分区方式管理主存时,为什么要引人移动技术?

  答:采用移动技术可以使分散的主存空闲区集中以满足分配要求,采用移动技术后可允许作业执行时动态扩充主存区域。

  6.页式存储管理中为什么要设置页表?

  答:因为页式管理时把作业分散在主存中的不连续块中存放,必须通过页表来建立逻辑地址中的页号到绝对地址中的块号的映射,作为硬件进行地址转换的依据。

  7.页式存储管理中页面大小是根据什么决定的?页表的长度又是根据什么决定的?

  答:页面的大小是由地址结构决定的。页表的长度是由作业的信息量决定的,作业有多少页,页表中就有多少个记录项。

  8.叙述页式存储管理中地址转换过程。

  答:首先,操作系统为每个作业创建一张页表,它建立了逻辑地址中的页号到绝对地址中的块号的映射。然后,借助于硬件地址转换机构,在作业执行过程中,每执行一条指令时,按逻辑地址中的页号查页表得到对应的块号,再根据公式“绝对地址=块号×块长+页内地址”换算出欲访问的主存单元的绝对地址。

  9.什么叫虚拟存储器?

  答:根据程序执行的互斥性和局部性两个特点,我们允许作业装入的时候只装入一部分,另一部分放在磁盘上,当需要的时候再装入到主存,这样以来,在一个小的主存空间就可以运行一个比它大的作业。同时,用户编程的时候也摆脱了一定要编写小于主存容量的作业的限制。也就是说,用户的逻辑地址空间可以比主存的绝对地址空间要大。对用户来说,好象计算机系统具有一个容量很大的主存储器,称为“虚拟存储器”。

  10.叙述页式存储管理实现虚拟存储器的基本思想。

  答:基本思想是:只需将作业的全部信息作为副本存放在磁盘上,作业被调度投入到运行时,至少把第一页信息装入主存储器,在作业执行过程中访问到不在主存储器的页的时候,再把它们装入到主存。

  11.采用可变分区方式管理主存时,能实现虚拟存储器吗?为什么?

  答:不可以,因为可变分区每次必须将作业完整调入并连续存放,这不适合虚拟存储的要求。同时,可变分区的硬件地址转换机构把绝对地址超出限定范围时作地址错处理,而不是产生“缺分区中断”。

  12.什么叫“抖动”?怎样衡量页面调度算法的好坏?

  答:如果选用了一个不合适的调度算法,就会出现这样的现象:刚被淘汰了的页面又立即要用,又要把它调入进来,而调入不久又被调出,调出不久再次被调入,如此反复,使得调度非常频繁,以至于大部分时间都花费在来回调度上。这种现象叫“抖动”。一个好的调度算法应减少和避免抖动现象。

  13.假定某计算机系统的主存容量为32K,对主存采用动态定位可变分区分配算法。现在已经有3个作业在主存储器中(如图),当作业J2执行时,要求扩充3K作业,为了满足作业J2这一要求,应移动几道作业的信息?写出它们的次序、方向和距离。

  答:因为采用可变分区的管理方式,要求作业的逻辑地址空间是连续的,并且主存空间也是连续的。因此,作业J2要求扩充的主存区域应该在原占有区域之后,于是必须通过移动来集中空闲区以供J2扩充之需。移动的方法有两种:

  ①先把J1向上移动1K再把J2向上移动2K.

  ②J3向下移动2K.

  显然,第二种方法只要进行一次移动,明显比第一种方法好。

  14.某采用页式存储管理的系统,接收了一共7页的作业,作业执行时依次访问的页为:l、2、3、4、2、1、5、6、2、1、2、3、7.若把开始4页先装入主存,若分别用先进先出(FIFO)调度算法和最近最少用(LRU)调度算法,作业执行时回产生多少次缺页中断?写出依次产生缺页中断后应淘汰的页。

  答:采用先进先出调度算法会产生 6次缺页中断,依次淘汰的页是 1、2、3、4、5、6.

  采用最近最少用调度算法会产生4次缺页中断,依次淘汰的页是3、4、5、6.

  15.某采用页式存储管理的系统,把主页分成大小为128的相等长度的块。有一个用户要把一个 128 × 128的数组置成初值“0”,在分页时把数组中的元素每一行放在一页中,假定分给用户可用来存放数组信息的工作区只有一块(既只能放数组中的一行元素)。用户编制了如下两个不同的程序来实现数组的初始化:

  l)var A:array[ 1.。128]of array[l.。128」of integer;

  for j :=1 to 128

  do for i:=1 to 128

  do A[j:]=0;

  2)var A:array[1.。128」of array[1.。128」Of integer;

  for i:=1 to 128

  do for j:=1 to 128

  do A[j]:=0;

  当分别运行这两个程序时,在实现数组初始化的过程中各会产生多少次缺页中断?

  答:假定数组的第一行元素已经存放在了一个主存块中,由于分页进把数组中的元数每一行放在一页中,所以每次i+1的时候都会产生缺页中断。这样一来,按1)编制的程序,每执行一次A[j]:=0 就会产生一次缺页中 断,于是总共产生(128×128-1)次缺页中断。而2)编制的程序执行时产生(128-1)次缺页中断。

转载自:
http://www.zikao365.com/html/4_21_89_175/2007_4_27_sh9613385971724700210730_0.htm

2010年6月23日星期三

使用pyExcelerator来读写Excel文件

在发现 xlrd 之后不久就发现了 pyExcelerator(可用新立得安装) ,它与 xlrd 不同,它主要是用来写 Excel 文件,当然读也是没有问题的。下面就它的使用简单地介绍一下。

一、Excel文件读取

安装: python setup.py install

from pyExcelerator import *
sheets = parse_xls('d:/a.xls')

很简单,与 xlrd 不同。xlrd 需要先调用book = xlrd.open_workbook(filename)打开文档,然后再调用sh = book.sheet_by_index(i)来得到第几个sheet,然后再使用sh.cell_value(i, j)得到i行j列的单元格的值。操作多了一点。而上面的parse_xls(filename)则直接返回一个列表,每一项就是一个sheet的数据。每 项是一个二元组(表名,单元格数据)。其中单元格数据为一个字典,键值就是单元格的索引(i,j)。如果某个单元格无数据,那么就不存在这个值。看似简 单,但从处理上不象 xlrd 一样,可以知道每个sheet的最大行数和列数,然后进行循环。而使用 pyExcelerator 好象没有最大行数和列数,再加上空数据又不存在,因此在处理上相对麻烦一些。这样在处理上还需要注意。它与 xlrd 一样都支持 unicode ,但好象没有 xlrd 一样方便地判断单元格的类型的方法,感觉还是 xlrd 在功能上可能要强一些。当然这只是个人感觉,再加上只是看了看例子,并没有怎么使用。

二、Excel文件写入

这个才是重头。那么安装好 pyExcelerator 之后,读了 Readme.txt 之后了解到它的文档正在进行当中,因此想多了解如何使用它需要看它所带的例子,甚至看源程序。下面是我从例子中了解的如何写一个 Excel 文档需要了解的。

为了方便,在导入这个模块中使用了import *的方式。

from pyExcelerator import *

首先导入模块,然后是生成工作薄。

w = Workbook()

接着是加入一个工作表(sheet)。

ws = w.add_sheet('Hey, Dude')

然后就可以保存了。

w.save('mini.xls')

上面的代码加在一起就是:

from pyExcelerator import *

w = Workbook()
ws = w.add_sheet('Hey, Dude')
w.save('mini.xls')

这就是最小的一个例子了,在例子中叫mini.py。你可以在例子目录下运行mini.py看一看是不是生成了一个空的Excel文件。

如果想加入中文很简单,改为:

#coding=cp936
from pyExcelerator import *

w = Workbook()
ws = w.add_sheet(u'这是中文')
w.save('mini.xls')

这样上面的执行结果是生成一个空Excel文件,但它的第一个sheet的名字为“这是中文”。就这样,只要保证你写入时使用unicode就行了。

空文件可以生成,那么如何插入单元格呢?

ws.write(i, j, value)

其中value为值,可以是unicode。

接着,我们可能想改变单元格的样式,如字体:

font0 = Font()
font0.name = 'Times New Roman'
font0.struck_out = True
font0.bold = True

style0 = XFStyle()
style0.font = font0

这样我们创建了一个字体,然后又生成了一个样式。注意,真正起作用的是样式,字体不过是样式中的一种效果。

这样在写入单元格时带着这个样式就行了,还是使用上面的write()方法:

ws.write(1, 1, 'Test', style0)

这是在名为ws的sheet中的第(1,1)单元格写入了值为"Test"的内容,并且它的样式为style0。

然后我们还可以设置单元格的边框:

borders = Borders()
borders.left = 5
style.borders = borders

上面创建了一个边框效果,设置了左边框,至于5是什么意思,我也不清楚,随便写的。然后放到样式中。上面的例子可以参考format.py程序。

转载自:
http://www.cublog.cn/u2/68938/showart_1095073.html

python time模块详解

python 的内嵌time模板翻译及说明

一、简介
time模块提供各种操作时间的函数
说明:一般有两种表示时间的方式:
第一种是时间戳的方式(相对于1970.1.1 00:00:00以秒计算的偏移量),时间戳是惟一的
第二种以数组的形式表示即(struct_time),共有九个元素,分别表示,同一个时间戳的struct_time会因为时区不同而不同
year (four digits, e.g. 1998)
month (1-12)
day (1-31)
hours (0-23)
minutes (0-59)
seconds (0-59)
weekday (0-6, Monday is 0)
Julian day (day in the year, 1-366)
DST (Daylight Savings Time) flag (-1, 0 or 1) 是否是夏令时
If the DST flag is 0, the time is given in the regular time zone;
if it is 1, the time is given in the DST time zone;
if it is -1, mktime() should guess based on the date and time.
夏令时介绍:http://baike.baidu.com/view/100246.htm
UTC介绍:http://wenda.tianya.cn/wenda/thread?tid=283921a9da7c5aef&clk=wttpcts

二、函数介绍
1.asctime()
asctime([tuple]) -> string
将一个struct_time(默认为当时时间),转换成字符串
Convert a time tuple to a string, e.g. 'Sat Jun 06 16:26:11 1998'.
When the time tuple is not present, current time as returned by localtime()
is used.

2.clock()
clock() -> floating point number
该函数有两个功能,
在第一次调用的时候,返回的是程序运行的实际时间;
以第二次之后的调用,返回的是自第一次调用后,到这次调用的时间间隔

示例:

view plaincopy to clipboardprint?
import time
if __name__ == '__main__':
time.sleep(1)
print "clock1:%s" % time.clock()
time.sleep(1)
print "clock2:%s" % time.clock()
time.sleep(1)
print "clock3:%s" % time.clock()

输出:
clock1:3.35238137808e-006
clock2:1.00004944763
clock3:2.00012040636
其中第一个clock输出的是程序运行时间
第二、三个clock输出的都是与第一个clock的时间间隔

3.sleep(...)
sleep(seconds)
线程推迟指定的时间运行,经过测试,单位为秒,但是在帮助文档中有以下这样一句话,这关是看不懂
“The argument may be a floating point number for subsecond precision.”

4.ctime(...)
ctime(seconds) -> string
将一个时间戳(默认为当前时间)转换成一个时间字符串
例如:
time.ctime()
输出为:'Sat Mar 28 22:24:24 2009'

5.gmtime(...)
gmtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min,tm_sec, tm_wday, tm_yday, tm_isdst)
将一个时间戳转换成一个UTC时区(0时区)的struct_time,如果seconds参数未输入,则以当前时间为转换标准


6.localtime(...)
localtime([seconds]) -> (tm_year,tm_mon,tm_day,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)
将一个时间戳转换成一个当前时区的struct_time,如果seconds参数未输入,则以当前时间为转换标准


7.mktime(...)
mktime(tuple) -> floating point number
将一个以struct_time转换为时间戳

8.strftime(...)
strftime(format[, tuple]) -> string
将指定的struct_time(默认为当前时间),根据指定的格式化字符串输出
python中时间日期格式化符号:
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)

%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身

9.strptime(...)
strptime(string, format) -> struct_time
将时间字符串根据指定的格式化符转换成数组形式的时间
例如:
2009-03-20 11:45:39 对应的格式化字符串为:%Y-%m-%d %H:%M:%S
Sat Mar 28 22:24:24 2009 对应的格式化字符串为:%a %b %d %H:%M:%S %Y

10.time(...)
time() -> floating point number
返回当前时间的时间戳

三、疑点
1.夏令时
在struct_time中,夏令时好像没有用,例如
a = (2009, 6, 28, 23, 8, 34, 5, 87, 1)
b = (2009, 6, 28, 23, 8, 34, 5, 87, 0)
a和b分别表示的是夏令时和标准时间,它们之间转换为时间戳应该相关3600,但是转换后输出都为646585714.0

四、小应用
1.python获取当前时间
time.time() 获取当前时间戳
time.localtime() 当前时间的struct_time形式
time.ctime() 当前时间的字符串形式

2.python格式化字符串
格式化成2009-03-20 11:45:39形式
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

格式化成Sat Mar 28 22:24:24 2009形式
time.strftime("%a %b %d %H:%M:%S %Y", time.localtime())

3.将格式字符串转换为时间戳
a = "Sat Mar 28 22:24:24 2009"
b = time.mktime(time.strptime(a,"%a %b %d %H:%M:%S %Y"))

转载自:
http://blog.csdn.net/kiki113/archive/2009/03/28/4033017.aspx

python 网络编程 (2)

一、套接字

套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象。它们允许程序接受并进行连接,如发送和接受数据。为了建立通信通道,网络通信的每个端点拥有一个套接字对象极为重要。

套接字为BSD UNIX系统核心的一部分,而且他们也被许多其他类似UNIX的操作系统包括Linux所采纳。许多非BSD UNIX系统(如ms-dos,windows,os/2,mac os及大部分主机环境)都以库形式提供对套接字的支持。

三种最流行的套接字类型是:stream,datagram和raw。stream和datagram套接字可以直接与TCP协议进行接口,而raw套接字则接口到IP协议。但套接字并不限于TCP/IP。

二、套接字模块

套接字模块是一个非常简单的基于对象的接口,它提供对低层BSD套接字样式网络的访问。使用该模块可以实现客户机和服务器套接字。要在python 中建立具有TCP和流套接字的简单服务器,需要使用socket模块。利用该模块包含的函数和类定义,可生成通过网络通信的程序。一般来说,建立服务器连 接需要六个步骤。

第1步是创建socket对象。调用socket构造函数。

socket=socket.socket(familly,type)

family的值可以是AF_UNIX(Unix域,用于同一台机器上的进程间通讯),也可以是AF_INET(对于IPV4协议的TCP和 UDP),至于type参数,SOCK_STREAM(流套接字)或者 SOCK_DGRAM(数据报文套接字),SOCK_RAW(raw套接字)。

第2步则是将socket绑定(指派)到指定地址上,socket.bind(address)

address必须是一个双元素元组,((host,port)),主机名或者ip地址+端口号。如果端口号正在被使用或者保留,或者主机名或ip地址错误,则引发socke.error异常。

第3步,绑定后,必须准备好套接字,以便接受连接请求。

socket.listen(backlog)

backlog指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求。

第4步,服务器套接字通过socket的accept方法等待客户请求一个连接:

connection,address=socket.accept()

调用accept方法时,socket会进入'waiting'(或阻塞)状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回 一个含有俩个元素的元组,形如(connection,address)。第一个元素(connection)是新的socket对象,服务器通过它与客 户通信;第二个元素(address)是客户的internet地址。

第5步是处理阶段,服务器和客户通过send和recv方法通信(传输数据)。服务器调用send,并采用字符串形式向客户发送信息。send方法 返回已发送的字符个数。服务器使用recv方法从客户接受信息。调用recv时,必须指定一个整数来控制本次调用所接受的最大数据量。recv方法在接受 数据时会进入'blocket'状态,最后返回一个字符串,用它来表示收到的数据。如果发送的量超过recv所允许,数据会被截断。多余的数据将缓冲于接 受端。以后调用recv时,多余的数据会从缓冲区删除。

第6步,传输结束,服务器调用socket的close方法以关闭连接。

建立一个简单客户连接则需要4个步骤。

第1步,创建一个socket以连接服务器 socket=socket.socket(family,type)

第2步,使用socket的connect方法连接服务器 socket.connect((host,port))

第3步,客户和服务器通过send和recv方法通信。

第4步,结束后,客户通过调用socket的close方法来关闭连接。

三、一个简单的服务器和客户端通信的例子

服务器:

import socket
s=socket.socket()
s.bind(('xxx.xxx.xxx.xxx',xxxx)) #ip地址和端口号
s.listen(5)
cs,address = s.accept()
print 'got connected from',address
cs.send('byebye')
ra=cs.recv(512)
print ra
cs.close()



客户端:

import socket
s=socket.socket()
s.connect(('xxx.xxx.xxx.xxx',xxxx)) #与服务器程序ip地址和端口号相同
data=s.recv(512)
s.send('hihi')
s.close()
print 'the data received is',data



运行:

在本机测试(windows环境下,可以将ip地址改为本机ip,端口号在1024以上,windows将1024以下的为保留),运行--CMD--进入命令行模式

先python 服务器程序,后python 客户端程序即可。

或者启动服务器程序后,用telnet ip地址 端口号,也可以得到同样结果。

让server持续接受连接
server.py

import socket
s=socket.socket()
s.bind(('192.168.43.137',2000))
s.listen(5)

while 1:
cs,address = s.accept()
print 'got connected from',address
cs.send('hello I am server,welcome')
ra=cs.recv(512)
print ra
cs.close()

测试两个一个程序中两个socket并存是否可行

client.py
import socket
s=socket.socket()
s.connect(('192.168.43.137',2000))
data=s.recv(512)
print 'the data received is\n ',data
s.send('hihi I am client')

sock2 = socket.socket()
sock2.connect(('192.168.43.137',2000))
data2=sock2.recv(512)
print 'the data received from server is\n ',data2
sock2.send('client send use sock2')
sock2.close()

s.close()

python 网络编程

前言

python实在是太方便,太易用了,三方库的支持又全,语法又简单,对开发人员来说,实在是居家旅行,XXXX的必备利器。周末研究了下python的网络支持,做一下记录,以备随后翻阅。

python支持BSD的socket进行网络编程,其API跟C中的大同小异,先看看TCP方式的,说到网络编程,肯定会设计到server和client,分别来看下
TCP方式

server端

server端的socket一般流程是这样:
建立一个socket(可以选择socket类型INET,UNIX等,以及连接方式TCP/UDP)
使用bind公开一个端口,使得client可以方便连接
设置一个listen队列的大小
进入一个无限循环,在此无限循环中,使用accept函数来等待客户连接,此函数返回一个新的socket, 对应于客户端的socket,建立通信信道。对socket的处理一般放在外部单独的函数中(并发)
通过send()/recv()来对socket进行读写操作
好了,下面看一下例子:
Python代码
def tcpServer():
srvsock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
srvsock.bind(('', 9527))
srvsock.listen(5)

while True:
clisock, (remoteHost, remotePort) = srvsock.accept()
print "[%s:%s] connected" % (remoteHost, remotePort)
#do something on the clisock
clisock.close()


if __name__ == "__main__":
tcpServer()

client端

建立一个新的socket
使用connect函数与远程主机获得连接
在此socket上进行I/O操作
Python代码
def tcpClient():
clisock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clisock.connect(('localhost', 9527))

#I/O on this clisock
#clisock.send("")
#dat = clisock.recv(len)

print dat

if __name__ == "__main__":
tcpClient()
由代码量可见python之简单,想要将这个例子改造成一个文件传输器,估计只需要增加不到20行代码即可。
UDP方式

UDP号称无连接传输,全然没有TCP那么复杂,三次握手,错误重传之类的机制都没有,发的只管发,收得只管收,收到没有?不知道,顺序不对怎么办?不管!就是这样,但是速度就要比TCP高得多了。在对数据帧要求不是很高的地方,这确实是很好用的,比如网络上的视频传输,音频传输等。
server端

建立数据报形式的socket
公开一个端口,一边客户端连接
开始接收数据
Python代码
def udpServer():
address = ('', 9527)
srvsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
srvsock.bind(address)
#data,addr = srvsock.recvfrom(2048)

if __name__ == "__main__":
udpServer()
需要注意的是,server中address元组中的引号表示可以接受任何地址来的数据报,TCP例子中的则表示可以接受任意地址发起的连接。
client端

新建一个数据报socket
收发数据
Python代码
def udpClient():
address = ('localhost', 9527)
clisock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#clisock.sendto(data, address)

if __name__ == "__main__":
udpClient()
文中给出的例子已经具有网络程序的基本结构,在实际应用中,应该自行扩展对socket的处理,socket说到底跟文件句柄,文件描述符,管道描述符等都是一个概念,可以对其进行I/O处理,事实上,在UNIX类系统中,对socket的操作跟对文件句柄的操作没有任何形式上的差异。

转载自:
http://www.javaeye.com/topic/401391

EXCEL的文件格式

Excel的文件格式是BIFF(Binary Interchange File Format)。从Excel97 - Excel2003使用的是BIFF version 8,可是说BIFF8是目前最广泛使用的Excel版本。BIFF8基于微软的复合文档格式。Excel文档的内容存放在一个Stream里。一个新建的空白Excel文件,一般包含Root Storge,Workbook Stream,<05h>SummaryInformation Stream,<05h>DocumentSummaryInformation Stream。Workbook Stream就存储了Excel的内容。把整个Excel文件叫Workbook,Workbook里至少有一个Worksheet。Excel文件不仅存放Excel的文本内容,还存放一些格式,比如字体信息,颜色。Excel的逻辑结构可以用下图表示:

Workbook globals里就记录了整个Workbook公用的东西,比如格式,字符串常量,文档保护等。worksheets,workbook globals都是存储在Workbook Stream里,可以把它们看做是substream。各个substream按一定顺序出现在Workbook Stream里,如下图所示:

图中所示,Globals Substream是必须的,而且至少保护一个Sheet Substream。那么这些Substream是如何区分开的,如何知道一个Substream从文件的哪个位置开始,哪里结束呢?这得从BIFF8描述信息所采用的格式来说。这里说的"信息",包含很多,比如格式信息,位置信息,文本信息,图片信息,宏代码信息,等等。这么多信息要记录,BIFF8是采用Record的方式来记录的。一个Record描述一个信息。因此有很多种Record。因此Record Type肯定是Record数据结构的组成部分。Record是不定长的,种类非常多,各个种类的内容格式千差万别。但是基本遵循如下的结构:

结构包含两部分,Record Header和Record Data。Record Header部分的前2字节是Record Type,然后是2字节描述Record Data的长度。文档给出了几乎所有的Record Type,针对每种Record,描述了Record Data里各字节的含义。Substream的开始和结束,就是采用BOF和EOF这两个Record Type。也就是说在Workbook Stream是Record序列,一个Record接着一个Record,有些BOF的record表示接下来要描述一个Substream了。因此处理程序可以一个Record一个Record的读取,先检查读入的Record的Type,如果不认识,那么就不处理Record data部分,如果认识就解析Record data部分的含义。Excel的版本是不断升级的,补丁是不断更新的,新的版本,新的build就可能有新的Record Type。因此旧版本的Excel打开高版本的xls文件,有些Record就无法识别,但是不影响基本数据的读取。FastExcel就是根据这个原理,只处理一些和文本内容相关的必需的Record Type,像格式之类的Record就不处理了,因此就Fast了。
当一个Cell的内容为字符串常量时,BIFF8一般把这个字符串常量用SST这种Record记录在Global Substream,然后在Sheet Substream里使用LabelSST这种Record引用这个字符串。LabelSST这种Record的Record Data部分就包含了行号,列号,字符串索引号(index)等信息。查看文档,可知LabelSST类型的Record Header的Identifier是00FD(hex),size是10,Record data结构如下图所示:

FastExcel的项目主页也说了它们只实现了如下的Parser来处理一些Record,仅仅是针对文本内容,BIFF8的Record类型可是几百个。这里的BOFParser就是处理BOF类型的Record,LabelSSTParser处理LabelSST类型的Record。
* BOFParser
* EOFParser
* BoundSheetParser
* SSTParser
* IndexParser
* DimensionParser
* RowParser
* LabelSSTParser
* RKParser
* MulRKParser
* LabelParser
* BoolerrParser
* XFParser
* FormatParser
* DateModeParser
* StyleParser
* MulBlankParser
* NumberParser
* RStringParser
BIFF8里多字节数据,比如4字节整数,2字节整数,Unicode都是采用Little-Endian的存储方式。

以上内容,转载自:

大端(Big Endian)与小端(Little Endian)详解

【大端(Big Endian)与小端(Little Endian)简介】
Byte Endian是指字节在内存中的组织,所以也称它为Byte Ordering,或Byte Order。
对于数据中跨越多个字节的对象, 我们必须为它建立这样的约定:
(1) 它的地址是多少?
(2) 它的字节在内存中是如何组织的?
针对第一个问题,有这样的解释:
对于跨越多个字节的对象,一般它所占的字节都是连续的,它的地址等于它所占字节最低地址。(链表可能是个例外, 但链表的地址可看作链表头的地址)。
比如: int x, 它的地址为0x100。 那么它占据了内存中的Ox100, 0x101, 0x102, 0x103这四个字节(32位系统,所以int占用4个字节)。
上面只是内存字节组织的一种情况: 多字节对象在内存中的组织有一般有两种约定。 考虑一个W位的整数。
它的各位表达如下:[Xw-1, Xw-2, ... , X1, X0],它的
MSB (Most Significant Byte, 最高有效字节)为 [Xw-1, Xw-2, ... Xw-8];
LSB (Least Significant Byte, 最低有效字节)为 [X7,X6,..., X0]。
其余的字节位于MSB, LSB之间。

LSB和MSB谁位于内存的最低地址, 即谁代表该对象的地址?
这就引出了大端(Big Endian)与小端(Little Endian)的问题。
如果LSB在MSB前面, 既LSB是低地址, 则该机器是小端; 反之则是大端。
DEC (Digital Equipment Corporation,现在是Compaq公司的一部分)和Intel的机器(X86平台)一般采用小端。
IBM, Motorola(Power PC), Sun的机器一般采用大端。
当然,这不代表所有情况。有的CPU即能工作于小端, 又能工作于大端, 比如ARM, Alpha,摩托罗拉的PowerPC。 具体情形参考处理器手册。

具体这类CPU是大端还是小端,应该和具体设置有关。
(如,Power PC支持little-endian字节序,但在默认配置时是big-endian字节序)
一般来说,大部分用户的操作系统(如windows, FreeBsd,Linux)是Little Endian的。少部分,如MAC OS ,是Big Endian 的。
所以说,Little Endian还是Big Endian与操作系统和芯片类型都有关系。

Linux系统中,你可以在/usr/include/中(包括子目录)查找字符串BYTE_ORDER(或
_BYTE_ORDER, __BYTE_ORDER),确定其值。BYTE_ORDER中文称为字节序。这个值一般在endian.h或machine/endian.h文件中可以找到,有时在feature.h中,不同的操作系统可能有所不同。

对于一个数0x1122
使用Little Endian方式时,低字节存储0x22,高字节存储0x11
而使用Big Endian方式时, 低字节存储0x11, 高字节存储0x22

经一网友指正,才知道,上面的描述,是不准确的.

想了下,觉得如下描述可能更合适:

使用Little Endian方式存储数据时,数据的LSB相对最没意义的数据位,存放在低地址位置,这里的LSB也就是22了.也即,

低地址存储0x22, 高地址存储0x11

而使用Big Endian方式存储数据时,数据的MSB最有意义的数据位,存放在低地址位置,这里的MSB也就是11了.也即

低地址存储0x11, 高地址存储0x22

助记:

1)所谓MSB (Most Significant Byte),名字很复杂,不知是否有人没搞懂,反正我开始看到这个词时候,就很糊涂,有点不完全理解.其实简单说MSB就是,一个数字中,最重要的那位,

举例来说,12004,中文读作,一万两千零四,那最高位的1,就表示了一万,此处就称作MSB,最有意义的位.

2)一般常见的数据存储,用文字写出来的时候,其内容书写格式,多数是从低地址到高地址.

举例,一个16进制数是 0x11 22 33, 而存放的位置是

地址0x3000 中存放11

地址0x3001 中存放22

地址0x3002 中存放33

连起来就写成地址0x3000-0x3002中存放了数据0x112233.

而这种存放和表示方式,正好符合大端.

解释的有点乱,希望有人能看懂.

如果还有哪里有误,还请各位继续指正.谢谢.

【用函数判断系统是Big Endian还是Little Endian】
bool IsBig_Endian()
//如果字节序为big-endian,返回true;
//反之为 little-endian,返回false
{
unsigned short test = 0x1122;
if(*( (unsigned char*) &test ) == 0x11)
return TRUE;
else
return FALSE;

}//IsBig_Endian()


以上内容,转载自:

http://blog.csdn.net/maxcode/archive/2009/02/14/3890052.aspx