在使用Python多年以後,我偶然發現了一些我們過去不知道的功能和特性。一些可以說是非常有用,但卻沒有充分利用。考慮到這一點,我編輯了一些的你應該了解的Pyghon功能特色。
帶任意數量參數的函數
你可能已經知道了Python允許你定義可選參數。但還有一個方法,可以定義函數任意數量的參數。
首先,看下面是一個只定義可選參數的例子
- def function(arg1="",arg2=""):
- print"arg1: {0}".format(arg1)
- print"arg2: {0}".format(arg2)
- function("Hello", "World")
- # prints args1: Hello
- # prints args2: World
- function()
- # prints args1:
- # prints args2:
現在,讓我們看看怎麼定義一個可以接受任意參數的函數。我們利用元組來實現。
- def foo(*args): # just use "*" to collect all remaining arguments into a tuple
- numargs = len(args)
- print"Number of arguments: {0}".format(numargs)
- for i, x in enumerate(args):
- print"Argument {0} is: {1}".format(i,x)
- foo()
- # Number of arguments: 0
- foo("hello")
- # Number of arguments: 1
- # Argument 0 is: hello
- foo("hello","World","Again")
- # Number of arguments: 3
- # Argument 0 is: hello
- # Argument 1 is: World
- # Argument 2 is: Again
使用Glob()查找文件
大多Python函數有著長且具有描述性的名字。但是命名為glob()的函數你可能不知道它是干什麼的除非你從別處已經熟悉它了。
它像是一個更強大版本的listdir()函數。它可以讓你通過使用模式匹配來搜索文件。
- import glob
- # get all py files
- files = glob.glob('*.py')
- print files
- # Output
- # ['arg.py', 'g.py', 'shut.py', 'test.py']
你可以像下面這樣查找多個文件類型:
- import itertools as it, glob
- def multiple_file_types(*patterns):
- return it.chain.from_iterable(glob.glob(pattern) for pattern in patterns)
- for filename in multiple_file_types("*.txt", "*.py"): # add as many filetype arguements
- print filename
- # output
- #=========#
- # test.txt
- # arg.py
- # g.py
- # shut.py
- # test.py
如果你想得到每個文件的絕對路徑,你可以在返回值上調用realpath()函數:
- import itertools as it, glob, os
- def multiple_file_types(*patterns):
- return it.chain.from_iterable(glob.glob(pattern) for pattern in patterns)
- for filename in multiple_file_types("*.txt", "*.py"): # add as many filetype arguements
- realpath = os.path.realpath(filename)
- print realpath
- # output
- #=========#
- # C:\xxx\pyfunc\test.txt
- # C:\xxx\pyfunc\arg.py
- # C:\xxx\pyfunc\g.py
- # C:\xxx\pyfunc\shut.py
- # C:\xxx\pyfunc\test.py
調試
下面的例子使用inspect模塊。該模塊用於調試目的時是非常有用的,它的功能遠比這裡描述的要多。
這篇文章不會覆蓋這個模塊的每個細節,但會展示給你一些用例。
- import logging, inspect
- logging.basicConfig(level=logging.INFO,
- format='%(asctime)s %(levelname)-8s %(filename)s:%(lineno)-4d: %(message)s',
- datefmt='%m-%d %H:%M',
- )
- logging.debug('A debug message')
- logging.info('Some information')
- logging.warning('A shot across the bow')
- def test():
- frame,filename,line_number,function_name,lines,index=\
- inspect.getouterframes(inspect.currentframe())[1]
- print(frame,filename,line_number,function_name,lines,index)
- test()
- # Should print the following (with current date/time of course)
- #10-19 19:57 INFO test.py:9 : Some information
- #10-19 19:57 WARNING test.py:10 : A shot across the bow
- #(, 'C:/xxx/pyfunc/magic.py', 16, '', ['test()\n'], 0)
生成唯一ID
在有些情況下你需要生成一個唯一的字符串。我看到很多人使用md5()函數來達到此目的,但它確實不是以此為目的。
其實有一個名為uuid()的Python函數是用於這個目的的。
- import uuid
- result = uuid.uuid1()
- print result
- # output => various attempts
- # 9e177ec0-65b6-11e3-b2d0-e4d53dfcf61b
- # be57b880-65b6-11e3-a04d-e4d53dfcf61b
- # c3b2b90f-65b6-11e3-8c86-e4d53dfcf61b
你可能會注意到,即使字符串是唯一的,但它們後邊的幾個字符看起來很相似。這是因為生成的字符串與電腦的MAC地址是相聯系的。
為了減少重復的情況,你可以使用這兩個函數。
- import hmac,hashlib
- key='1'
- data='a'
- print hmac.new(key, data, hashlib.sha256).hexdigest()
- m = hashlib.sha1()
- m.update("The quick brown fox jumps over the lazy dog")
- print m.hexdigest()
- # c6e693d0b35805080632bc2469e1154a8d1072a86557778c27a01329630f8917
- # 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
序列化
你曾經需要將一個復雜的變量存儲在數據庫或文本文件中吧?你不需要想一個奇特的方法將數組或對象格轉化為式化字符串,因為Python已經提供了此功能。
- import pickle
- variable = ['hello', 42, [1,'two'],'apple']
- # serialize content
- file = open('serial.txt','w')
- serialized_obj = pickle.dumps(variable)
- file.write(serialized_obj)
- file.close()
- # unserialize to produce original content
- target = open('serial.txt','r')
- myObj = pickle.load(target)
- print serialized_obj
- print myObj
- #output
- # (lp0
- # S'hello'
- # p1
- # aI42
- # a(lp2
- # I1
- # aS'two'
- # p3
- # aaS'apple'
- # p4
- # a.
- # ['hello', 42, [1, 'two'], 'apple']
這是一個原生的Python序列化方法。然而近幾年來JSON變得流行起來,Python添加了對它的支持。現在你可以使用JSON來編解碼。
- import json
- variable = ['hello', 42, [1,'two'],'apple']
- print"Original {0} - {1}".format(variable,type(variable))
- # encoding
- encode = json.dumps(variable)
- print"Encoded {0} - {1}".format(encode,type(encode))
- #deccoding
- decoded = json.loads(encode)
- print"Decoded {0} - {1}".format(decoded,type(decoded))
- # output
- # Original ['hello', 42, [1, 'two'], 'apple'] - <type 'list'="">
- # Encoded ["hello", 42, [1, "two"], "apple"] - <type 'str'="">
- # Decoded [u'hello', 42, [1, u'two'], u'apple'] - <type 'list'="">
這樣更緊湊,而且最重要的是這樣與JavaScript和許多其他語言兼容。然而對於復雜的對象,其中的一些信息可能丟失。
壓縮字符
當談起壓縮時我們通常想到文件,比如ZIP結構。在Python中可以壓縮長字符,不涉及任何檔案文件。
- import zlib
- string = """ Lorem ipsum dolor sit amet, consectetur
- adipiscing elit. Nunc ut elit id mi ultricies
- adipiscing. Nulla facilisi. Praesent pulvinar,
- sapien vel feugiat vestibulum, nulla dui pretium orci,
- non ultricies elit lacus quis ante. Lorem ipsum dolor
- sit amet, consectetur adipiscing elit. Aliquam
- pretium ullamcorper urna quis iaculis. Etiam ac massa
- sed turpis tempor luctus. Curabitur sed nibh eu elit
- mollis congue. Praesent ipsum diam, consectetur vitae
- ornare a, aliquam a nunc. In id magna pellentesque
- tellus posuere adipiscing. Sed non mi metus, at lacinia
- augue. Sed magna nisi, ornare in mollis in, mollis
- sed nunc. Etiam at justo in leo congue mollis.
- Nullam in neque eget metus hendrerit scelerisque
- eu non enim. Ut malesuada lacus eu nulla bibendum
- id euismod urna sodales. """
- print"Original Size: {0}".format(len(string))
- compressed = zlib.compress(string)
- print"Compressed Size: {0}".format(len(compressed))
- decompressed = zlib.decompress(compressed)
- print"Decompressed Size: {0}".format(len(decompressed))
- # output
- # Original Size: 1022
- # Compressed Size: 423
- # Decompressed Size: 1022
注冊Shutdown函數
有可模塊叫atexit,它可以讓你在腳本運行完後立馬執行一些代碼。
假如你想在腳本執行結束時測量一些基准數據,比如運行了多長時間:
- import atexit
- import time
- import math
- def microtime(get_as_float = False) :
- if get_as_float:
- return time.time()
- else:
- return'%f %d' % math.modf(time.time())
- start_time = microtime(False)
- atexit.register(start_time)
- def shutdown():
- global start_time
- print"Execution took: {0} seconds".format(start_time)
- atexit.register(shutdown)
- # Execution took: 0.297000 1387135607 seconds
- # Error in atexit._run_exitfuncs:
- # Traceback (most recent call last):
- # File "C:\Python27\lib\atexit.py", line 24, in _run_exitfuncs
- # func(*targs, **kargs)
- # TypeError: 'str' object is not callable
- # Error in sys.exitfunc:
- # Traceback (most recent call last):
- # File "C:\Python27\lib\atexit.py", line 24, in _run_exitfuncs
- # func(*targs, **kargs)
- # TypeError: 'str' object is not callable
打眼看來很簡單。只需要將代碼添加到腳本的最底層,它將在腳本結束前運行。但如果腳本中有一個致命錯誤或者腳本被用戶終止,它可能就不運行了。
當你使用atexit.register()時,你的代碼都將執行,不論腳本因為什麼原因停止運行。
結論
你是否意識到那些不是廣為人知Python特性很有用?請在評論處與我們分享。謝謝你的閱讀!