在使用Python多年以后,我偶然发现了一些我们过去不知道的功能和特性。一些可以说是非常有用,但却没有充分利用。考虑到这一点,我编辑了一些的你应该了解的Pyghon功能特色。
带任意数量参数的函数
你可能已经知道了Python允许你定义可选参数。但还有一个方法,可以定义函数任意数量的参数。
首先,看下面是一个只定义可选参数的例子
01 | deffunction(arg1="",arg2=""): |
02 | print"arg1:{0}".format(arg1) |
03 | print"arg2:{0}".format(arg2) |
05 | function("Hello","World") |
现在,让我们看看怎么定义一个可以接受任意参数的函数。我们利用元组来实现。
01 | deffoo(*args):#justuse"*"tocollectallremaining argumentsintoatuple |
03 | print"Numberofarguments:{0}".format(numargs) |
04 | fori,xinenumerate(args): |
05 | print"Argument{0}is:{1}".format(i,x) |
14 | foo("hello","World","Again") |
使用Glob()查找文件
大多Python函数有着长且具有描述性的名字。但是命名为
glob()的函数你可能不知道它是干什么的除非你从别处已经熟悉它了。
它像是一个更强大版本的listdir()函数。它可以让你通过使用模式匹配来搜索文件。
8 | #['arg.py','g.py','shut.py','test.py'] |
你可以像下面这样查找多个文件类型:
01 | importitertoolsasit,glob |
03 | defmultiple_file_types(*patterns): |
04 | returnit.chain.from_iterable(glob.glob(pattern)forpatterninpatterns) |
05 | |
06 | forfilenameinmultiple_file_types("*.txt","*.py"):#addasmanyfiletypearguements |
如果你想得到每个文件的绝对路径,你可以在返回值上调用realpath()函数:
01 | importitertoolsasit,glob,os |
03 | defmultiple_file_types(*patterns): |
04 | returnit.chain.from_iterable(glob.glob(pattern)forpatterninpatterns) |
06 | forfilenameinmultiple_file_types("*.txt","*.py"):#addasmanyfiletypearguements |
07 | realpath=os.path.realpath(filename) |
12 | #C:\xxx\pyfunc\test.txt |
调试
下面的例子使用inspect模块。该模块用于调试目的时是非常有用的,它的功能远比这里描述的要多。
这篇文章不会覆盖这个模块的每个细节,但会展示给你一些用例。
03 | logging.basicConfig(level=logging.INFO,
04 | format='%(asctime)s%(levelname)-8s%(filename)s:%(lineno)-4d:%(message)s', |
07 | logging.debug('Adebugmessage') |
08 | logging.info('Someinformation') |
09 | logging.warning('Ashotacrossthebow') |
12 | frame,filename,line_number,function_name,lines,index=\ |
13 | inspect.getouterframes(inspect.currentframe())[1] |
14 | print(frame,filename,line_number,function_name,lines,index) |
18 | #Shouldprintthefollowing(withcurrentdate/timeofcourse) |
19 | #10-1919:57INFOtest.py:9:Someinformation |
20 | #10-1919:57WARNINGtest.py:10:Ashotacrossthebow |
21 | #(,'C:/xxx/pyfunc/magic.py',16,'',['test()\n'],0) |
生成唯一ID
在有些情况下你需要生成一个唯一的字符串。我看到很多人使用md5()函数来达到此目的,但它确实不是以此为目的。
其实有一个名为uuid()的Python函数是用于这个目的的。
5 | #output=>variousattempts |
6 | #9e177ec0-65b6-11e3-b2d0-e4d53dfcf61b |
7 | #be57b880-65b6-11e3-a04d-e4d53dfcf61b |
8 | #c3b2b90f-65b6-11e3-8c86-e4d53dfcf61b |
你可能会注意到,即使字符串是唯一的,但它们后边的几个字符看起来很相似。这是因为生成的字符串与电脑的MAC地址是相联系的。
为了减少重复的情况,你可以使用这两个函数。
04 | printhmac.new(key,data,hashlib.sha256).hexdigest() |
07 | m.update("Thequickbrownfoxjumpsoverthelazydog") |
10 | #c6e693d0b35805080632bc2469e1154a8d1072a86557778c27a01329630f8917 |
11 | #2fd4e1c67a2d28fced849ee1bb76e7391b93eb12 |
序列化
你曾经需要将一个复杂的变量存储在数据库或文本文件中吧?你不需要想一个奇特的方法将数组或对象格转化为式化字符串,因为Python已经提供了此功能。
03 | variable=['hello',42,[1,'two'],'apple'] |
06 | file=open('serial.txt','w') |
07 | serialized_obj=pickle.dumps(variable) |
08 | file.write(serialized_obj) |
11 | #unserializetoproduceoriginalcontent |
12 | target=open('serial.txt','r') |
13 | myObj=pickle.load(target) |
30 | #['hello',42,[1,'two'],'apple'] |
这是一个原生的Python序列化方法。然而近几年来JSON变得流行起来,Python添加了对它的支持。现在你可以使用JSON来编解码。
7fe0
03 | variable=['hello',42,[1,'two'],'apple'] |
04 | print"Original{0}-{1}".format(variable,type(variable)) |
07 | encode=json.dumps(variable) |
08 | print"Encoded{0}-{1}".format(encode,type(encode)) |
11 | decoded=json.loads(encode) |
12 | print"Decoded{0}-{1}".format(decoded,type(decoded)) |
16 | #Original['hello',42,[1,'two'],'apple']-<type'list'=""style="word-wrap:break-word;"> |
17 | #Encoded["hello",42,[1,"two"],"apple"]-<type'str'=""style="word-wrap:break-word;"> |
18 | #Decoded[u'hello',42,[1,u'two'],u'apple']-<type'list'=""style="word-wrap:break-word;"> |
这样更紧凑,而且最重要的是这样与JavaScript和许多其他语言兼容。然而对于复杂的对象,其中的一些信息可能丢失。
压缩字符
当谈起压缩时我们通常想到文件,比如ZIP结构。在Python中可以压缩长字符,不涉及任何档案文件。
03 | string="""Loremipsumdolorsitamet,consectetur |
04 | adipiscingelit.Nuncutelitidmiultricies |
05 | adipiscing.Nullafacilisi.Praesentpulvinar, |
06 | sapienvelfeugiatvestibulum,nulladuipretiumorci, |
07 | nonultricieselitlacusquisante.Loremipsumdolor |
08 | sitamet,consecteturadipiscingelit.Aliquam |
09 | pretiumullamcorperurnaquisiaculis.Etiamacmassa |
10 | sedturpistemporluctus.Curabitursednibheuelit |
11 | molliscongue.Praesentipsumdiam,consecteturvitae |
12 | ornarea,aliquamanunc.Inidmagnapellentesque |
13 | tellusposuereadipiscing.Sednonmimetus,atlacinia |
14 | augue.Sedmagnanisi,ornareinmollisin,mollis |
15 | sednunc.Etiamatjustoinleoconguemollis. |
16 | Nullaminnequeegetmetushendreritscelerisque |
17 | eunonenim.Utmalesuadalacuseunullabibendum |
18 | ideuismodurnasodales.""" |
20 | print"OriginalSize:{0}".format(len(string)) |
22 | compressed=zlib.compress(string) |
23 | print"CompressedSize:{0}".format(len(compressed)) |
25 | decompressed=zlib.decompress(compressed) |
26 | print"DecompressedSize:{0}".format(len(decompressed)) |
注册Shutdown函数
有可模块叫atexit,它可以让你在脚本运行完后立马执行一些代码。
假如你想在脚本执行结束时测量一些基准数据,比如运行了多长时间:
05 | defmicrotime(get_as_float=False): |
09 | return'%f%d'%math.modf(time.time()) |
10 | start_time=microtime(False) |
11 | atexit.register(start_time) |
15 | print"Executiontook:{0}seconds".format(start_time) |
17 | atexit.register(shutdown) |
19 | #Executiontook:0.2970001387135607seconds |
20 | #Errorinatexit._run_exitfuncs: |
21 | #Traceback(mostrecentcalllast): |
22 | #File"C:\Python27\lib\atexit.py",line24,in_run_exitfuncs |
24 | #TypeError:'str'objectisnotcallable |
26 | #Traceback(mostrecentcalllast): |
27 | #File"C:\Python27\lib\atexit.py",line24,in_run_exitfuncs |
29 | #TypeError:'str'objectisnotcallable |
打眼看来很简单。只需要将代码添加到脚本的最底层,它将在脚本结束前运行。但如果脚本中有一个致命错误或者脚本被用户终止,它可能就不运行了。
当你使用atexit.register()时,你的代码都将执行,不论脚本因为什么原因停止运行