分类: '编程相关' 的归档
python代码风格检查工具──pylint
pylint是一个python代码检查工具,可以帮助python程序员方便地检查程序代码的语法和风格,通过这个工具,可以使你的python代码尽量保持完美,哈哈。
具体可以检查什么东西呢?
比如你写了 from XXX import * 了,它就会提示你这样import是不好的。
比如你操作符的前后没有空格,它也会提示你。
比如逗号后面没跟空格也会。
还有你import了没用到的模块,定义了没使用的变量等也会提示。
还有你的变量名是否符合规范也会提示。
总之它提示的内容很多很全面,而且它最后会给出一个所检查的代码的总体分数,如果能达到满分10分的话,简直就是神作了,因为pylint本身的代码也才9.5分左右,哈哈。
比较惨的是,TX发现这个工具以后,检查了几个python项目的分数,都不是很高,我那gmbox得了2分多点,还算是高的。不过,经过一番优化,现在的gmbox已经有6.64分,及格了,哈哈。。
值得一提的是,pylint不仅可以像默认那样输出字符结果,还可以彩色化输出,甚至还可以输出HTML和visual studio的格式。具体用法可以参见man页和这个文档。
python程序打包工具 ── cx_Freeze
cx_Freeze是一个类似py2exe的工具,它们区别是py2exe是将python程序打包成windows下可以执行的exe文件的,而cx_Freeze则是将python程序打包为linux下可以直接执行的ELF格式的二进制可执行文件(看说明好像也能生成windows的可执行文件,号称跨平台)。
cx_Freeze的作用就是让你的python程序可以脱离python运行环境,在没有安装python的微型linux系统(例如cdlinux、tinycore等)里,方便地运行你的python程序。从功能上来说,也可以将其理解为一个python程序的编译器,将你的源码隐藏起来。
使用方法也很简单,下载以后,解压,如一般的python模块一样,cd到目录以后,
python setup.py install |
就可以完成安装,这样你的系统里就会有cxfreeze命令了。
然后,cd到你的python程序的目录执行
cxfreeze 你的程序文件.py --target-dir dist |
就会在当然目录生成一个dist的目录,里面就会有一堆so文件和可执行目标文件了,当然如果你还有图片或者其他数据文件的话,手工复制到相应目录,这时候运行那个可执行文件,就应该能看到效果了。
现在只需将dist目录打包,传到没有python的目标系统里,你程序也就能运行了。
PS: cx_Freeze还有另外两种使用方法,需要了解的话,可以自行查看随代码打包的html文档。
python 内建函数
说明:本文内容全部出自python官方文档,但是会有自己的理解,并非单纯的翻译。文章较长,如有错误之处,还请大家指正。
abs(x)
返回x的绝对值;当x是复数时,返回x的模。没错,python内建支持复数,见下面的complex()函数。
all(iterable)
当iterable里的每项都为真时,才返回真,等效于:
def all(iterable): for element in iterable: if not element: return False return True |
any(iterable)
只要iterable里有一项为真,就返回真,等效于:
def any(iterable): for element in iterable: if element: return True return False |
basestring()
这是 str 和 unicode 的抽象类,它不能被调用也不能被实例化,但是可以用在 isinstance 函数里进行判断,isinstance(obj, basestring) 等效于 isinstance(obj, (str, unicode)).
>>> isinstance(123, basestring) False >>> isinstance("123", basestring) True >>> isinstance(u"一二三", basestring) True |
bin(x)
如果x是一个整数,则返回一个与x等值的二进制python表达式;如果x不是一个整数类型,则x的类需要有一个可以返回一个整数的__index__()函数。
bool([x])
返回一个布尔型的值,如果x为False或者没传x参数的时候返回False,否则返回True。
callable(object)
判断object是否可调用,如果object是 函数、类、或者含有__call__()的类对象的话,将返回True。
chr(i)
返回一个单个字符的字符串,此字符的ascii码值为i(0<=i<=255),此函数是ord函数的反函数。如果参数大于255而想得到一个unicode字符的话,需要使用unichr()
classmethod(function)
返回一个类的方法(类的方法有别于实例的方法,是不需要实例化也可以通过类名访问的方法),定义一个类的方法需要用这样的形式:
class C: @classmethod def f(cls, arg1, arg2, ...): ... |
cmp(x, y)
比较两个对象x和y。如果x小于y,返回负数;大于返回正数;等于返回0。
compile(source, filename, mode[, flags[, dont_inherit]])
把source字符串编译成一个AST对象,暂时用不到,先略过。
complex([real[, imag]])
用传入的实部和虚部创建一个复数对象。
delattr(object, name)
删除对象的属性,相当于 del object.name ,可以和setattr配合使用。
dict([arg])
建立一个新的字典型数据,可以从参数里获取数据。
>>> dict({"a":"b","c":"d"}) {'a': 'b', 'c': 'd'} |
dir([object])
如果不加参数,返回当前执行环境下的变量名的列表。
如果加了object参数,则会根据复杂的规则得到object的属性名列表,需要注意的是,当object定义了__dir__()或者 __getattr__()方法时,返回的结果并不一定正确。
示例:
>>> dir() ['__builtins__', '__doc__', '__name__', '__package__'] >>> t=[1,2] >>> dir() ['__builtins__', '__doc__', '__name__', '__package__', 't'] >>> dir(t) ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__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__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] |
divmod(a, b)
通常返回a和b的商和余数组成的元组: (a // b, a % b)。参数不能是复数。
enumerate(sequence[, start=0])
返回一个列举后的对象,sequence要支持迭代。返回的对象支持next()方法,此方法依次返回一个从start开始增长的序数和sequence里的元素组成的元组。看以下的例子:
>>> enu=enumerate(['Spring', 'Summer', 'Fall', 'Winter']) >>> enu.next() (0, 'Spring') >>> enu.next() (1, 'Summer') >>> for i, season in enu: ... print i, season ... 2 Fall 3 Winter |
eval(expression[, globals[, locals]])
执行expression表达式,可以用globals和locals来限制expression能访问的变量。
值得注意的是,expression不仅可以是明文的字符串,还可以是compile()函数返回的代码对象。
execfile(filename[, globals[, locals]])
此函数类似exec表达式。只是从文件里读取表达式。它和import的区别在于,execfile会无条件地读取文件,而且不会生成新的模块。
globals和locals的用法和上面的eval同理。
file(filename[, mode[, bufsize]])
File类型的构造函数,参数的作用和下面提到的open()函数是一样的。
值得注意的是,open()函数更适合于打开一个文件,而file函数更适用于类型测试,例如: isinstance(f, file)
filter(function, iterable)
构造一个function(iterable)为true的list。当然iterable为字符串或者tuple的时候,返回的类型也是字符串或者tuple,否则返回list。
>>> filter(lambda c: c in 'abc', 'abcdcba') 'abccba' >>> filter(lambda i: i < 3, (1, 2, 3, 2, 1)) (1, 2, 2, 1) >>> filter(lambda i: i < 3, [1, 2, 4, 2, 1]) [1, 2, 2, 1] |
如果function为None,则iterable为false的元素将被剔除。也就是说,function不为None的时候,filter(function, iterable)
等效于[item for item in iterable if function(item)]
,否则等效于[item for item in iterable if item]
float([x])
传入一个字符串或者整数或者float,返回一个float数据。
format(value[, format_spec])
根据format_spec格式化输出value的值,实际上只是调用了value.__format__(format_spec)
,很多内建类型都有标准的输出函数。
frozenset([iterable])
由iterable创建一个frozenset对象,frozenset是set的一个子类,它和set的区别在于它不支持某些可以修改set的操作,例如:add、remove、pop、clear等。可以理解为一个set的常量。
getattr(object, name[, default])
获得对象的属性值,name必须是字符串,如果name是object的属性,则getattr(x, 'foobar')
相当于x.foobar
,如果name不是object的属性,则返回default,如果没有default就会抛出AttributeError意外。
globals()
返回一个包含当前“全局符号表”的dict。
hasattr(object, name)
参数是一个对象和一个字符串,如果object对象有名为name的属性,则返回True,否则返回False。在执行getattr(object, name)
之前,可以以此来检测属性的存在性。
hash(object)
如果可能的话,返回object的hash值,hash值是一个整型的数字,用于快速比较两个对象。两个相等的数字型对象将有相同的hash值,比如:
>>> hash(1) == hash(1.0) True |
help([object])
调用内建的帮助系统(交互式)。
如果省略参数,则会进入帮助控制台,出现help>
的提示符,输入相应内容就可以查看相应的帮助。
如果参数是字符串,则在模块名、函数名、类名、方法名、关键字及文档和帮助主题里搜索此字符串,并显示。
如果参数是其他类型的对象,则显示此对象的帮助信息。
hex(x)
将任何长度的整型数字转化为16进制的字符串。
如果转换浮点数为16进制,则须使用float.hex()
方法。
id(object)
返回一个整型(或者长整型)的object的唯一标识符。注意:两个生命周期没有交叉的对象,也许会返回同一个标识符。(在CPython里,其实就是返回object的地址)
input([prompt])
等效于 eval(raw_input(prompt))
返回用户输入的python表达式的值,一句话:注意安全。
int([x[, base]])
根据x的值返回一个整数,x可以是一个含有数字信息的字符串或者数字类型(整型/浮点型/长整型/复数)。可选的base参数,代表进制,可以是2~36之间的数字或者0。如果base的值为0,将会根据x的值选取适当的基数。如果不提供任何参数,将返回0。
isinstance(object, classinfo)
如果object是classinfo或者classinfo的子类的实例,或者是和classinfo同类的对象,则返回True。classinfo也可以是类或者对象组成的tuple,这时候,object只要是classinfo里的一者就返回True:
>>> isinstance(1, (int,float) ) True >>> isinstance(1.0, (int,float) ) True >>> isinstance("1.0", (int,float) ) False |
issubclass(class, classinfo)
如果class是classinfo的直接或者间接之类的话,就返回True。一个类也被视为自己的之类。同上例,classinfo也可以是tuple。
iter(o[, sentinel])
返回一个“迭代器”对象,根据sentinel的设置不停地对第一个参数进线取值。当忽略第二个参数时,o必须是一个支持__iter__()或者__getitem__()方法的对象,否则将会抛出TypeError例外。如果提供了sentinel参数,o必须是一个可调用的对象,这时将不停地调用此方法,并返回迭代器的项,知道返回的值等于sentinel为止,这时将抛出StopIteration。
第二种形式特别适用于打开一个文件,一行行处理文本,知道遇到特定的行:
with open("mydata.txt") as fp: for line in iter(fp.readline, "STOP"): process_line(line) |
len(s)
返回s的长度,也就是项数。自建会调用__len__函数取值。
list([iterable])
返回一个含有所有iterable中的元素的list对象。如果参数为空,则返回空的list。
locals()
和上面的globals()
对应,返回一个包含当前“局部符号表”的dict。在函数里调用的时候,将排除在类中声明的变量。
long([x[, base]])
根据字符串或者数字类型的参数,返回一个长整型的数字。参数的含义和上面的int
类似。
map(function, iterable, …)
对iterable里的每项执行function函数,并把结果以一个list的形式返回。如果有3个以上的参数,则后面的参数也需要是可迭代的,map会把额外的参数传给function,例如,这样可以把两个tuple一一相加得到一个list:
>>> map(lambda x, add: x + add, (2, 4, 5), (1, 3, 6) ) [3, 7, 11] |
如迭代器的长度不一致,缺失的项将用None代替:
>>> map(lambda x, add: x + add, (2, 4, 5), (1, 3)) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <lambda> TypeError: unsupported operand type(s) for +: 'int' and 'NoneType' |
如果function为None,将用 identity function 代替(好像就是直入直出)。
max(iterable[, args…][, key])
如果只给一个参数,就返回iterable里最大的项;如果是多个参数的话,则返回参数里最大的项。
>>> max("abcd") 'd' >>> max(1, 2, 3) 3 |
额外的key参数,是用于比较的函数,比如,下面这个可以得到各项除3的余数最大的一个:
>>> max([1, 2, 3, 4], key=lambda x: x % 3) 2 |
min(iterable[, args…][, key])
同上,求最小值。
next(iterator[, default])
依次返回迭代器iterator的项。当iterator没有更多的项时,如果有default参数,则返回default,否则抛出StopIteration例外。
>>> a = iter(range(3)) >>> next(a) 0 >>> next(a) 1 >>> next(a) 2 >>> next(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> next(a, "No More Item...") 'No More Item...' |
object()
返回一个空的对象,但是此对象会有一些公有的属性:
>>> o = object() >>> dir(o) ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] |
oct(x)
将任意精度的十进制整数x转换成八进制。
open(filename[, mode[, bufsize]])
打开文件,返回一个文件对象,如果文件打不开,将抛出IOError
错误。
filename参数,是要打开的文件名。
mode参数是打开方式,通常是'r'
表示读,'w'
表示写(如果已存在则会覆盖),'a'
表示追加。缺省为'r'
。另外,缺省使用的是文本模式,会把'\n'
转成系统相关的换行符,如果要避免这个引起的问题,需要在各个模式后面加一个'b'
表示使用二进制模式。另外还有些’+uU’之类的模式,不常用,也就不介绍了吧。
可选的bufsize参数表示缓冲区的大小。0表示不缓冲,1表示行缓冲,其他正数表示近视的缓冲区字节数,负数表示使用系统默认值。默认是0。
ord(c)
给定一个长度为1的字符串或者unicode字符,返回该字符的ascii码或者unicode码,前一种情况是chr()
的反函数,后一种情况是unichr()
的反函数。
pow(x, y[, z])
返回x的y次方,也就是x**y
。如果有z的话,返回x的y次方除z得到的余数(这个比pow(x, y) % z
更高效,这点可以看我写的欧拉工程第48题的代码,之前很慢,现在很快)。
如果第二个参数是负数的话,将返回浮点型的数据,而且这个时候不能有z。
print([object, …][, sep=’ ‘][, end=’\n’][, file=sys.stdout])
输出一个或多个object到file,中间用sep间隔,并在结尾加上end。
后3个参数如果给出的话,必须用keyword arguments的形式,也就是必须指定参数名,否则将一概被视为object的一部分而被输出。
需要注意的是和python 2.6前的print关键字的区别。
property([fget[, fset[, fdel[, doc]]]])
返回一个属性,参数分别是获取、设置和删除的函数外加doc string,看例子吧:
>>> class C(object): ... def __init__(self): ... self._x = None ... def getx(self): ... print "OK. give you:", self._x ... return self._x ... def setx(self, value): ... print "Now x is:", value ... self._x = value ... def delx(self): ... del self._x ... x = property(getx, setx, delx, "I'm the 'x' property.") ... >>> a = C() >>> a.x = 123 Now x is: 123 >>> print a.x OK. give you: 123 123 >>> help(a.x) OK. give you: 123 >>> help(C.x) #这里可以看到I'm the 'x' property. |
range([start], stop[, step])
方便地产生一个包含等差数列的list,如果忽略start,则默认为0;如果忽略step,则默认为1。经常被用于for循环里。注意返回的结果并不包含stop。
raw_input([prompt])
从输入读入一行字符串,结尾的回车将被去掉。如果提供了prompt参数,将做为输入的提示符。
reduce(function, iterable[, initializer])
将两个参数的function函数循环应用到迭代器的各项,例如reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
相当于((((1+2)+3)+4)+5)
。如果提供了可选的initializer参数,则会将它放在迭代器的前面进行运算。
reload(module)
重新加载之前已经导入的模块。当你在设计一个模块,并用外部编辑器更新了它的代码时,可以用reload重新导入此模块,来验证模块的正确性。
reload执行时候的具体细节这里就不描述了。
repr(object)
返回一个尽量包含object的信息的字符串,其实交互式python解释器,在输入一个对象回车的时候,就是返回对象的repr值。
对于很多常见的对象,返回的值都尽可能地使得能够被eval
解释并返回对象本身;另外的就尽量包含所在的域信息和类型或者地址等。
一个类可以通过__repr__()方法自定义repr的返回值。
reversed(seq)
返回一个倒序的迭代器。seq要么支持 __reversed__() 方法,要么支持取项的操作(也就是支持__len__()方法和从0开始的整数值的__getitem__()方法)。
例子:
>>> reversed(range(5)) <listreverseiterator object at 0x80a658c> >>> [i for i in reversed(range(5))] [4, 3, 2, 1, 0] |
round(x[, n])
将浮点数x四舍五入取整到小数点后n位小数。n的默认值是0,也就是取整。
set([iterable])
由迭代器iterable返回一个集合对象,集合中的元素是随机顺序,但是不重复的。此函数在去掉列表的重复项的时候,特别有用:
>>> l = [1, 2, 3, 2, 4, 3] >>> set(l) set([1, 2, 3, 4]) >>> list(set(l)) [1, 2, 3, 4] >>> ''.join(set("hello")) 'helo' |
setattr(object, name, value)
此函数和getattr()
配合使用,setattr(x, 'foobar', 123)
相当于x.foobar = 123
。
slice([start], stop[, step])
返回一个分片对象,分片对象就只包含了start, stop, step这3个信息,它在python内部和一些第三方库中广泛被使用,其实类似a[1:3]这样的操作也会生成分片对象。如果省略start和step,将默认为None。
可以看到下面两者其实是等效的:
>>> range(5)[slice(1, 4, 2)] [1, 3] >>> range(5)[1:4:2] [1, 3] |
sorted(iterable[, cmp[, key[, reverse]]])
返回一个排序后的列表,用于排序的元素来自iterable,后面的参数控制排序的过程。
cmp是自定义的比较函数,接受两个参数,返回负数表示第一个参数较小,返回0表示两者一样大,返回正数表示第一个参数较大。
key可以理解为每个参数的求值函数。如果提供了key,则在比较前,先对每个先用key进线求职,对结果再进行排序,但是返回的排序后的结果还是之前的值。
reverse如果是True,则按降序排列,默认是从小到大的升序。
看例子:
#正常的排序 >>> sorted([1, 5, 3, 4, 6]) [1, 3, 4, 5, 6] #倒序 >>> sorted([1, 5, 3, 4, 6], reverse=True) [6, 5, 4, 3, 1] #提供了key,结果是除3的余数谁最小,谁就排前 >>> sorted([1, 5, 3, 4, 6], key=lambda x: x%3) [3, 6, 1, 4, 5] #用cmp实现的版本 >>> sorted([1, 5, 3, 4, 6], cmp=lambda x,y: x%3 - y%3) [3, 6, 1, 4, 5] |
值得注意的是,虽然cmp和key都可以实现上面的除3余数排列,但是因为cmp要对每次比较的两个元素都调用一次函数,所以,效率不如key来得高。
staticmethod(function)
返回一个静态方法function
要声明一个静态方法,需要使用如下的语法:
class C: @staticmethod def f(arg1, arg2, ...): ... |
静态方法可以被类本身调用(例如:C.f()
)也可以被类的对象调用(例如:C().f()
)。
str([object])
返回一个精确可打印的字符串,来说明object。和repr(object)
不同,str(object)
返回的字符串不一定能被eval()执行来得到对象本身,str(object)
的目标只是可打印和可读。
sum(iterable[, start])
对iterable在start做为初值的基础上进行累加。start的默认值为0。
注意此方法不能对字符串进行相加(连接)操作,连接字符串还是用''.join(sequence)
好了。另外,sum(range(n), m)
等价于reduce(operator.add, range(n), m)
,要更精确地对浮点数进行累加,请使用math.fsum()。
super(type[, object-or-type])
返回一个指代type的父类或者兄弟类的对象,可以用这个对象间接地调用父类或者兄弟类的方法。在有复杂的类继承关系结构的时候,会很有用。用到的时候可以自行研究下这文章。
tuple([iterable])
返回一个tuple对象(元组),元素来自iterable。如果省略参数,将返回空的元组。
type(object)
返回object的类型,返回值本身是个“类型对象”。注意,进行类型判断建议使用isinstance()
函数。
>>> type(1) <type 'int'> >>> type(type(1)) <type 'type'> >>> type(1) == int #非常不建议这样的使用方法。 True >>> isinstance(1,int) #建议这样使用。 True |
type(name, bases, dict)
不同于上面那个一个参数的type,这个方法用于快速构造一个类,传入的3个参数将分别转化为所得到的类的__name__,__bases__和__dict__。
例如,下面这两个X是等价的:
>>> class X(object): ... a = 1 ... >>> X = type('X', (object,), dict(a=1)) |
unichr(i)
返回一个单个字符的unicode串,此字符的unicode码值为i。对于Unicode,此函数也是ord()的反函数。i的范围由python解释器的编译环境决定。
unicode([object[, encoding[, errors]]])
返回一个代表object的unicode字符串。
如果给定了encoding和/或errors,将用ascii或者encoding指定的编码对object进行解码,在遇到解码错误的时候,errors的值将影响函数的下一步动作:如果errors的值是'strict'
(默认值),将会抛出ValueError错误;如果errors的值是'ignore'
将会忽略错误,继续解码;如果errors是'replace'
,将使用U+FFFD来替换当前字符。
看个例子,我的utf8环境下:
>>> unicode('我是bones7456', encoding='utf8') u'\u6211\u662fbones7456' >>> print unicode('我是bones7456', encoding='utf8') #可见解码成功 我是bones7456 >>> unicode('我是bones7456') #不指定编码方式,将默认使用ascii解码,失败了。 Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128) >>> unicode('我是bones7456', errors='ignore') #忽略失败,可以得到英文数字部分 u'bones7456' >>> unicode('我是bones7456', errors='replace') #替换的话,会加上一堆???哈哈。 u'\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdbones7456' >>> print unicode('我是bones7456', errors='replace') ������bones7456 |
如果没有后面的俩参数,unicode()
的行为类似于str()
,只不过返回的unicode字符串而已。
如果,object对象提供了__unicode__()方法,将调用此方法来返回一个可被用户自定义的unicode串。
vars([object])
如果省略object,vars()
和locals()类似,如果object是模块、类、类的对象或者其他还有__dict__属性的对象的话,就返回它的__dict__。
xrange([start], stop[, step])
此函数和range()非常类似,但是返回的不是一个列表,而是一个xrange对象。xrange对象在被引用时,也能生成列表的各项,但是这些项不是同时存在于内存里的。xrange和range比的优势是更小巧,更快。
zip([iterable, …])
哈,说到这个函数,我还给python官方文档提过一个bug,因为之前版本的文档的示例代码有点小问题,前因后果可以看这里。
zip函数返回一个元组的列表,第i个元组,就包含了每个iterable的第i项。如果参数的各iterable不一样长,会别截取到最短的值,这个值也就是结果列表的长度。
然后,zip内如果有个 *
开头,将会执行逆运算(unzip),示例:
>>> x = [1, 2, 3] >>> y = [4, 5, 6] >>> zipped = zip(x, y) >>> zipped [(1, 4), (2, 5), (3, 6)] >>> x2, y2 = zip(*zipped) >>> x == list(x2) and y == list(y2) True |
__import__(name[, globals[, locals[, fromlist[, level]]]])
此函数被import语句调用。代码中很少会用到这个函数,除非你要import的模块名是运行时才可知的。就不详述了。
欧拉工程
咳咳,我做为非正常网民网瘾戒除中心的砖家,正式给介绍介绍一下这个欧拉工程。
呃。。。还是请我们的校长──lerosua──来介绍吧~下面引自这篇博文:
欧拉工程是一个用编程来解决一连串数学问题的项目。发现它对训练数学及编程挺有作用的。网上也有许多人做上面的题目并发布自己的算法。
上面共有261题,分几个等级,一级比一级难。我看了第261题的提交,目前只是22个。完成它绝对是时间及精力及耐力及智力的较量。
于是本人决定将此作为一个项目来做,逐步进阶。
骨头与xiooli同学也并肩作战。
我们解决的问题的源码将会发布在以下svn中。欢迎审阅.
http://nrciz.googlecode.com/svn/trunk/projecteuler
其实,之前(几个月前吧)我就已经做过几题了。可以说,正是因为欧拉工程,我才喜欢上python的,当我看到第一题用一句
sum([n for n in range(1000) if n%3==0 or n%5==0]) |
就完美地搞定了,是多么地流畅,多么地自然,我就喜欢上了这门语言~
我们现在已经在逐步把很多题目翻译成中文了,所以,大家有空就去这里看看吧~最好是大家都能参与到其中来哦~
神一样的Quine
有个很牛B的小日本搞出来的东西。
# ruby l=92.chr;eval s="s=s.dump[r=1..-2].gsub(/("+l*4+"){4,}(?!\")/){|t|'\"+l*%d+\"'%(t .size/2)};5.times{s=s.dump[r]};puts\"# python\\nprint(\\\"# perl\\\\nprint(\\\\\\ \"# lua"+l*4+"nprint("+l*7+"\"(* ocaml *)"+l*8+"nprint_endline"+l*15+"\"-- haskel l"+l*16+"nimport Data.List;import Data.Bits;import Data.Char;main=putStrLn("+l*31 +"\"/* C */"+l*32+"n#include<stdio.h>"+l*32+"nint main(void){char*s[501]={"+l*31+ "\"++intercalate"+l*31+"\","+l*31+"\"(c(tail(init(show("+l*31+"\"/* Java */"+l*32 +"npublic class QuineRelay{public static void main(String[]a){String[]s={"+l*31+" \"++intercalate"+l*31+"\","+l*31+"\"(c("+l*31+"\"brainfuck"+l*64+"n++++++++[>++++ <-]+++++++++>>++++++++++"+l*31+"\"++(concat(snd(mapAccumL h 2("+l*31+"\"110"+l*31 +"\"++g(length s)++"+l*31+"\"22111211100111112021111102011112120012"+l*31+"\"++co ncatMap("+l*32+"c->let d=ord c in if d<11then"+l*31+"\"21002"+l*31+"\"else"+l*31+ "\"111"+l*31+"\"++g d++"+l*31+"\"22102"+l*31+"\")s++"+l*31+"\"2100211101012021122 2211211101000120211021120221102111000110120211202"+l*31+"\"))))))++"+l*31+"\","+l *63+"\""+l*64+"n"+l*63+"\"};int i=0;for(;i<94;i++)System.out.print(s[i]);}}"+l*31 +"\")))))++"+l*31+"\",0};int i=0;for(;s[i];i++)printf("+l*63+"\"%s"+l*63+"\",s[i] );puts("+l*63+"\""+l*63+"\");return 0;}"+l*31+"\");c s=map("+l*32+"s->"+l*31+"\"" +l*63+"\""+l*31+"\"++s++"+l*31+"\""+l*63+"\""+l*31+"\")(unfoldr t s);t[]=Nothing; t s=Just(splitAt(if length s>w&&s!!w=='"+l*31+"\"'then 501else w)s);w=500;f 0=Not hing;f x=Just((if x`mod`2>0then '0'else '1'),x`div`2);g x= reverse (unfoldr f x); h p c=let d=ord c-48in(d,replicate(abs(p-d))(if d<p then '<'else '>')++"+l*31+"\" ."+l*31+"\");s="+l*31+"\"# ruby"+l*32+"n"+l*31+"\"++"+l*31+"\"l=92.chr;eval s=\"+ (z=l*31)+\"\\\"\"+s+z+\"\\\""+l*31+"\"++"+l*31+"\""+l*32+"n"+l*31+"\""+l*15+"\""+ l*7+"\")"+l*4+"n\\\\\\\")\\\")\"########### (c) Yusuke Endoh, 2009 ###########\n" |
这段ruby代码,相当牛,如作者所说,运行这段ruby,生成一段python代码,再运行python代码,生成一段perl代码,再运行perl代码,生成一段lua代码。。。这样一直下去,经过11种语言,最后。。。居然又能重新得到之前的ruby代码。。
这11种语言是:ruby 1.8.7-p72、Python 2.5.2、perl v5.10.0、Lua 5.0.3、OCaml 3.10.2、ghc-6.8.2、gcc 4.3.2、java “1.5.0_17″、beef 0.0.6-2、whitespace 0.3-2、unlambda 2.0.0-5。
在est这里看到了介绍,实在忍不住,把所有解释器都装上验证了一把,果然是可以的。彻底无语了,特此把中间结果都打包放上来,供大家瞻仰。
ubuntu下也想自己试试的话,得确保有这些包: ruby lunar lua50 ocaml-interp ghc6 sun-java5-jdk beef whitespace unlambda
PS: 我以为 brainfuck 就已经很BT了,没想到还有更BT的 whitespace ,彻底无语了。
Bash其实也可以做CGI用
标题其实是“废话”。因为,其实稍微熟悉web原理的都知道,理论上,所有可执行的程序/脚本,都可以被server程序(例如apache/mini_httpd/lighttpd/nginx等)调用,只要能够输出HTML,都可以成功。
而这个用bash做CGI的想法,纯属闲着无聊的时候,瞎想出来的。不过有这个想法的,我肯定不是第一人,这里和这里都有类似的描述。
不过,我这个Web From Scratch的过程还颇有点波折,试了蛮久才成功,就在此记录一下。
其实,说白了都是也就一句话:扩展名不能随意取。当然这个只是针对我这个主机的apache来说的,其他的server可能有其他的规则,暂且不做定论。
之前我一直把我的脚本文件名写成index.sh,结果怎么试都不行,后来无意中改成inedx.py(虽然里面还是#!/bin/bash开头的)居然就可以了,于是我就找到原因了,现在我改成个更通用的index.cgi了,哈哈。
另外关于.htaccess,由于自己也是一知半解,就不讨论了,有兴趣的话,可以看看这里,这里只贴下我用到的代码,可以把对此域名的任何路径的请求都让index.cgi来处理。
RewriteEngine on DirectoryIndex index.cgi RewriteCond %{REQUEST_URI} !(index.cgi) RewriteRule ^(.*)$ index.cgi/$1 [L] |
来看看我的bash,就是简单地输出服务器信息:
#!/bin/bash #下面这两行头一定要有,不然可是会引发 500 Internal Server Error 错误的。 echo "Content-type: text/html" echo "" echo "<h1>Bash CGI works!</h1>" env | while read line;do echo "<b>" echo "$line" | cut -d= -f 1 echo "</b>=<i>" echo "$line" | cut -d= -f 2- echo "</i><br>" done |
最近几天,可以点击 http://hzlug.org/abc?xxx=yyy 观察这个脚本运行的效果,以后可以把这个地址做它用,嘿嘿。
可以看到 REDIRECT_URL 和 QUERY_STRING 这两个环境变量分别是路径和参数,这样理论上就可以用一个脚本来完成很复杂的功能了~
至于HZLUG到底会做成什么样子,还请大家多多提意见哦~
用python来收发邮件
由于python的模块很强大,用python来收发邮件,就显得很轻松了。
python不仅有email模块,还有专门处理pop、smtp甚至imap的模块。
下面就来演示一下这几个的用法,先看看怎么用pop3和email模块来收邮件。
>>> import poplib >>> p=poplib.POP3_SSL('pop.gmail.com') #如果服务器不需要启用SSL,那么只需要用 poplib.POP3('xxx.com') 就好了。 >>> p.user('linuxcn.ibot') '+OK send PASS' >>> p.pass_('密码') '+OK Welcome.' >>> p.stat() #统计状态,返回一个元组,第一个表示几封邮件,第二个表示一共几个字节 (2, 4543) >>> p.list() #返回每个邮件的状态 ('+OK 2 messages (4543 bytes)', ['1 3679', '2 864'], 15) >>> p.retr(2) #获取某个邮件的全文,这个邮件就是我自己给另一个测试账号发的邮件,元组里包含了邮件头和邮件的正文。 ('+OK message follows', ['Delivere ...为了排版方便,此处有删节... e--'], 869) >>> mailsrc='\n'.join([l for l in p.retr(2)[1]]) >>> print mailsrc #如果上面还看不出啥的话,这样看应该就明显了。 Delivered-To: linuxcn.ibot@gmail.com Received: by 10.216.47.83 with SMTP id s61cs422102web; Sat, 15 Aug 2009 07:58:32 -0700 (PDT) MIME-Version: 1.0 Received: by 10.114.180.16 with SMTP id c16mr2819847waf.57.1250348310512; Sat, 15 Aug 2009 07:58:30 -0700 (PDT) Date: Sat, 15 Aug 2009 22:58:30 +0800 Message-ID: <ae14629e0908150758n49649527xf326b8c1a60f36bf@mail.gmail.com> Subject: =?UTF-8?B?5rWL6K+V5Li76aKY?= From: LLY <bones7456@gmail.com> To: linuxcn.ibot@gmail.com Content-Type: multipart/alternative; boundary=001636417e2fe4c3a904712f669e --001636417e2fe4c3a904712f669e Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: base64 5rWL6K+V5q2j5paHCg== --001636417e2fe4c3a904712f669e Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: base64 5rWL6K+V5q2j5paHPGJyPgo= --001636417e2fe4c3a904712f669e-- >>> p.quit() #收完邮件了,理论上是要退出一下的 '+OK Farewell.' >>> import email #源码得到了,现在轮到email模块登场了 >>> e=email.message_from_string(mailsrc) #这个就可以把邮件源码转换成一个email的对象了。 >>> print e['subject'] #这个是编码后的主题 =?UTF-8?B?5rWL6K+V5Li76aKY?= >>> print email.header.decode_header(e['subject'])[0][0] #这个是解码后的主题 测试主题 >>> e.get_payload() #获取当前email的有效部分,可以看到有这个邮件有两个部分,从上面的邮件源码,我们也可以得知,此邮件确实有text/plain 和 text/html 两部分 [<email.message.Message instance at 0xb751102c>, <email.message.Message instance at 0xb751172c>] >>> e.get_payload(0) #获取有效部分的第一个,这个还是一个email对象的实例。 <email.message.Message instance at 0xb751102c> >>> type(e) <type 'instance'> >>> type(e.get_payload(0)) <type 'instance'> >>> import base64 #解码邮件正文还得用上base64模块 >>> print base64.decodestring(e.get_payload(0).get_payload()) #解码正文的第一部分 测试正文 >>> print base64.decodestring(e.get_payload(1).get_payload()) #解码正文的第二部分,是html,看来只多了个br而已,哈哈 测试正文<br> |
当然,上面的例子只是最简单的,复杂的附件什么的,也可以用库里的相关函数一一搞定的。另外,看文档的意思,传了get_payload的第二个参数按理应该能自动调用base64模块解码的,但是不知道为什么,我没有试验成功,只能自己手工解了~
下面,再来看看怎么用smtp发邮件,如果是复杂的邮件,也需要建立一个email对象的实例,把正文/附件等一一放上去就好,但是作为演示,我们就用邮件的源码来发一个纯手工的,哈哈
>>> import smtplib #加载模块 >>> msg='To: linuxcn.ibot@gmail.com\r\nFrom: my@localhost\r\nSubject: test\r\n\r\nthis is msg body\r\n' #邮件的源码 >>> s=smtplib.SMTP('smtp.163.com') #同样这里也有SMTP_SSL,到底用什么要看服务器的设置 >>> s.login('bones7456','密码') #一般都要登录了,才能发邮件,login里提供两个参数,用户名和密码 (235, 'Authentication successful') >>> s.sendmail('bones7456@163.com','linuxcn.ibot@gmail.com',msg) #发送邮件,三个参数分别是 from/to/msg,就这名简单就成功了。。 {} >>> s.quit() (421, 'closing transmission channel') |
就这么几行,一封邮件就发出去了,够简单吧。。。更详细的内容就看官方文档吧~
JSON数据格式简介
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。
以上摘自JSON官方介绍,这个格式是如此地简单,以至于光看这篇官方文档就可以完全掌握了,而无须其他过多地介绍了。
最初看到这个JSON,是在twitter上,这种小交互量的场景很适合用JSON,比XML更轻巧些。今天,看到新闻,taobao也搞了个开放平台,里面也支持JSON和xml这两种格式,所以我觉得这个格式以后会越来越流行,特发此文关注下。
折腾py2exe
序: 恩,这个确实挺折腾的,几乎一个下午都在搞py2exe,加上晚上又搞了一会儿,总算勉强让gmbox的exe可执行文件运行起来了…
首先,为什么要折腾py2exe呢? 其实就是为了那个gmbox,在设计之初,我就让它打算跨平台支持windows的.为此我也折腾过windows的python运行环境.但是如果那样的话,有windows的朋友要用gmbox,就必须安装python、GTK+库、PyCairo、PyGObject和PyGTK,这可不是一般的烦.所以有市场就会有需求,像我这样的问题我肯定不是第一个遇到的.于是就有了py2exe.
py2exe实际上是python distutils的一个扩展,使用py2exe,你必需有一个windows的环境,安装了python和你程序用到的依赖包(例如gmbox的pygtk等),也就是说,在这个”开发环境”你要能够运行起你的程序,然后下载py2exe,安装到python的lib目录下,就可以用来生成目标exe文件了,以后你只要把生成的东西复制到其他windows的机器,就可以脱离python运行环境和库的依赖了.是不是很爽呢?
虽说网上都说py2exe用起来很简单,但是我还是折腾了不少时间,可能是因为gmbox比较特殊:同时有CLI和GUI,有图标和数据文件,有自己的lib库等,当然更可能是因为我太菜了…嘿嘿..
不管怎么说,在这里记一下折腾的步骤,也许可以让后人少走点弯路:
- 打包文件(gmbox的打包文件在这里,建议边参考代码,边看下面的内容)最好要和你的主程序文件放在同一目录下.我曾经试着把打包文件放在上级目录,结果在搜索依赖库的时候遇到了很多麻烦.
- 打包文件本身其实也是一个python的程序,虽然一般只有一个setup函数.此函数可以有 name,description,version,console,windows,options,data_files 等参数.
- 要生成一个或多个命令行的exe,setup需要一个List型的名为console参数,指名源py文件.
- 要生成一个或多个GUI的exe,setup需要一个List型的名为windows参数,指名源py文件.List的每项都可以有图标等选项,就是icon_resources哪里,图标也是个Tuple的List,但是windows一般只会显示出第一个图标,所以一个就够了.
- 如果你想用png文件直接当图标,那很可能会在生成exe的时候,引起python崩溃,所以还是赶紧转成ico吧
- 如果你和我一样,生成的GUI的exe文件,在执行的时候,报 ImportError: No module named cairo ,那最好在setup函数里加上options,里面有include cairo的选项.
- 如果你也有数据文件(比如glade文件,图片文件等),py2exe默认并不会帮你一起打包,你需要在setup函数中加传data_files参数.data_files需要是一个List,每项可以是直接指向数据文件的字符串,也可以是一个Tuple;如果是前者,数据文件会直接在生成的dist目录下面,如果是后者,Tuple的第一个元素是目标目录,第二个元素是是个源文件名的List,效果是把所有的源文件存放在dist下的指定的目标目录下.(呃,好长好拗口…)
- 在py2exe生成的环境中,__file__这个应用将失效,这个问题的解决方法可以参看这里.个人觉得Alternate Solution更加靠谱.
- 好了,现在如果你已经写好了打包文件(win_packer.py),也对源代码进行了应有的修改,你就可以执行 python win_packer.py py2exe 来生成exe了,执行此命令会在当前目录下多出一个 dist 目录,你只要把dist目录复制出来,运行里面的exe,就可以了
- 最后,如果你的GUI程序还是运行不了,你还需要手工将你的GTK+安装安装目录(默认是C:\GTK)下的etc和lib目录复制到dist目录
当然,由于包含了一堆的运行环境,生成的dist目录将会是比较巨大的,现在的gmbox的exe居然有18M多,嘿嘿,应该还有优化和压缩的空间,改天再研究了~
给python增加IPC模块
前天介绍了linux进程间通信──消息队列,由于消息队列是linux内核提供的功能,所以理所当然地,C语言用起来最为方便:直接include一个sys/msg.h就可以了,所以之前的文章,我也是用C语言来做演示的.
那么我喜欢的Python能不能用IPC呢?能不能像C一样用消息队列呢?
其实,Python的内置模块里,并没有对IPC的支持,但是好在python的可扩展性超强,我们可以用swig来为python增加一个IPC模块.方法如下:
下载这个tar包(修改自这里),解压到任意目录,得到 ipc.h ipc.i Makefile 3个文件,如果你不是用的python2.6,需要修改一下 Makefile 里的路径(python3系列未测试).然后
make && make install |
这样,你就可以在python里 import ipc模块了.
还是贴示例代码,保存为ipc_msg.py,并加可执行权限:
#!/usr/bin/env python import sys,ipc if len(sys.argv)==5 and sys.argv[3][0]=='s': ipc_key=int(sys.argv[1]) msg_id = ipc.msgget(ipc_key,0666|ipc.IPC_CREAT) if 0 > msg_id: sys.exit(1) mbuf = ipc.msgbuf() mbuf.mtype = int(sys.argv[2]) mbuf.mtext = sys.argv[4] if 0 > ipc.msgsnd(msg_id,mbuf,len(mbuf.mtext),0): sys.exit(3) print 'Send Success.' elif len(sys.argv)==4 and sys.argv[3][0]=='r': ipc_key=int(sys.argv[1]) mbuf = ipc.msgbuf() msg_id = ipc.msgget(ipc_key,0666) if 0 > msg_id: sys.exit(1) msg_len=ipc.msgrcv(msg_id,mbuf,2048,int(sys.argv[2]),ipc.IPC_NOWAIT) if 0 > msg_len: print 'No message received.' sys.exit(3) else: print 'Recv Success.(%d bytes):'% msg_len print mbuf.mtext elif len(sys.argv)==3 and sys.argv[2][0]=='c': ipc_key=int(sys.argv[1]) id_dsp = ipc.msqid_ds() msg_id = ipc.msgget(ipc_key,0666) if 0 > msg_id: sys.exit(1) if 0 > ipc.msgctl(msg_id,ipc.IPC_RMID,id_dsp): sys.exit(2) else: print "usage: \n%s key type s message --to send message\n\ %s key type r --to receive\n\ %s key c --to clear queue"\ %(sys.argv[0],sys.argv[0],sys.argv[0]) |
运行结果:
lily@LLY:~/test/ipc$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages lily@LLY:~/test/ipc$ ./ipc_msg.py 1 2 s abc Send Success. lily@LLY:~/test/ipc$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000001 65536 lily 666 3 1 lily@LLY:~/test/ipc$ ./ipc_msg.py 1 2 r Recv Success.(3 bytes): abc lily@LLY:~/test/ipc$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000001 65536 lily 666 0 0 lily@LLY:~/test/ipc$ ./ipc_msg.py 1 c lily@LLY:~/test/ipc$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages lily@LLY:~/test/ipc$ |
怎么样?和之前的C语言版本一模一样吧?