Python 实用进阶技巧:从可变参数到序列化与调试
本文深入解析 Python 中常被忽视的实用功能,包括定义接受任意数量参数的函数、使用 glob 模块进行模式匹配搜索文件、利用 inspect 模块辅助调试、生成唯一 ID 以及处理数据序列化与压缩。通过具体代码示例,帮助开发者提升代码简洁性与效率,掌握从基础语法到高级库应用的多种技巧。
Python 是一门设计简洁且语法清晰的语言。阅读优质的 Python 代码往往如同阅读英语,尽管是语法严谨的英语。这种类似伪代码的特性是 Python 的核心优势之一,它使开发者能够将注意力集中在解决问题的逻辑上,而非语言本身的复杂细节。
在长期使用 Python 的过程中,我发现了一些过去容易被忽略的功能和特性。其中一些功能极具实用价值,却未得到充分利用。基于此,我整理了一些值得了解的 Python 特性,供读者参考。
支持任意数量参数的函数
你可能已经熟悉 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() 函数来实现此目的,但这并非该函数的设计初衷。
实际上,Python 中有一个名为 uuid() 的函数是专门为此目的设计的。
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
注册关闭时执行的函数
有一个名为 atexit 的模块,允许你在脚本运行结束后立即执行特定代码。
例如,如果你想在脚本执行结束时测量基准数据,如运行时长:
乍看之下很简单,只需将代码添加到脚本底部,它将在脚本结束前运行。但如果脚本中出现致命错误或被用户强制终止,这段代码可能不会执行。
当你使用 atexit.register() 时,无论脚本因何种原因停止运行,你的代码都将执行。
总结
你是否意识到这些不为人熟知的 Python 特性非常有用?欢迎在评论区与我们分享。感谢阅读!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













