尽管阅读了许多关于该主题的文章(包括 [this][1] 非常流行的关于 SO 的文章),但我很难很好地掌握装饰器。我怀疑我一定是愚蠢的,但是由于愚蠢带来的所有固执,我决定尝试解决这个问题。
那,我怀疑我有一个很好的用例......
下面是我的一个项目中的一些代码,它从 PDF 文件中提取文本。处理涉及三个步骤:
- 设置处理 PDF 文件所需的 PDFMiner 对象(样板初始化)。
- 对 PDF 文件应用处理功能。
- 不管发生什么,关闭文件。
我最近了解了上下文管理器和with
语句,这对他们来说似乎是一个很好的用例。因此,我从定义PDFMinerWrapper
类开始:
class PDFMinerWrapper(object):
'''
Usage:
with PDFWrapper('/path/to/file.pdf') as doc:
doc.dosomething()
'''
def __init__(self, pdf_doc, pdf_pwd=''):
self.pdf_doc = pdf_doc
self.pdf_pwd = pdf_pwd
def __enter__(self):
self.pdf = open(self.pdf_doc, 'rb')
parser = PDFParser(self.pdf) # create a parser object associated with the file object
doc = PDFDocument() # create a PDFDocument object that stores the document structure
parser.set_document(doc) # connect the parser and document objects
doc.set_parser(parser)
doc.initialize(self.pdf_pwd) # pass '' if no password required
return doc
def __exit__(self, type, value, traceback):
self.pdf.close()
# if we have an error, catch it, log it, and return the info
if isinstance(value, Exception):
self.logError()
print traceback
return value
现在我可以轻松地处理 PDF 文件,并确保它能够优雅地处理错误。理论上,我需要做的就是这样的:
with PDFMinerWrapper('/path/to/pdf') as doc:
foo(doc)
这很好,除了我需要在将函数应用于返回的对象之前检查 PDF 文档是否可提取PDFMinerWrapper
。我目前的解决方案涉及一个中间步骤。
我正在使用我调用的一个类,该类Pamplemousse
用作处理 PDF 的接口。反过来,PDFMinerWrapper
每次必须对对象已链接到的文件执行操作时,它都会使用它。
下面是一些(删节的)代码,演示了它的使用:
class Pamplemousse(object):
def __init__(self, inputfile, passwd='', enc='utf-8'):
self.pdf_doc = inputfile
self.passwd = passwd
self.enc = enc
def with_pdf(self, fn, *args):
result = None
with PDFMinerWrapper(self.pdf_doc, self.passwd) as doc:
if doc.is_extractable: # This is the test I need to perform
# apply function and return result
result = fn(doc, *args)
return result
def _parse_toc(self, doc):
toc = []
try:
toc = [(level, title) for level, title, dest, a, se in doc.get_outlines()]
except PDFNoOutlines:
pass
return toc
def get_toc(self):
return self.with_pdf(self._parse_toc)
每当我希望对 PDF 文件执行操作时,我都会将相关函数with_pdf
及其参数传递给该方法。with_pdf
反过来,该方法使用该with
语句来利用上下文管理器PDFMinerWrapper
(从而确保优雅地处理异常)并在实际应用已传递的函数之前执行检查。
我的问题如下:
我想简化这段代码,这样我就不必显式调用Pamplemousse.with_pdf
. 我的理解是装饰器在这里可能会有所帮助,所以:
- 我将如何实现一个装饰器,其工作是调用
with
语句并执行可提取性检查? - 装饰器是否可以是类方法,或者我的装饰器必须是自由形式的函数或类?