尽管已经阅读了很多关于这个主题的文章(包括[这] [1]非常受欢迎的文章),但我仍然很难很好地理解装饰器。我怀疑我一定是愚蠢的,但是随着所有愚蠢带来的固执,我决定尝试弄清楚这一点。用装饰器替换宏样式的类方法?
也就是说,我怀疑我有一个很好的用例...
下面是我的一个项目,从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
语句并执行可提取支票? - 装饰器是否可能是一个类方法,或者我的装饰器是否必须是一个自由形式的函数或类?
您正确解读了我的目标!这非常合理。只是一个简单的问题 - 是否有可能(也是可取的)将'if_extractable'作为'Pamplemousse'类的方法?为了形式的利益,这个功能将成为“Pamplemousse”类的一部分。无论如何,我会测试你的解决方案,非常感谢你! – blz 2012-07-26 12:34:58
我会说不是真的,因为你甚至不能把它装饰成classmethod,因为它会在同一个类中使用它。再加上它不是一种方法,会被某个使用该类的人称为成员,所以你不需要在对象上看到它。将它作为模块中的一个函数并将其保留在类名称空间之外更容易。它更适合那个班。 – jdi 2012-07-26 14:32:14