我正在尝试编写我们遇到的各种医学图像格式的通用阅读器。我想,让我们向专业人士学习,然后去模仿 PIL 通用读取文件的方式(“Python Imaging Library”,格式)。
据我了解,PIL 有一个开放函数,可以循环遍历可能的接受函数列表。当一个工作时,它使用相关的工厂函数来实例化适当的对象。
所以我去做了,我的(精简的)努力就在这里:
pluginID = [] # list of all registered plugin IDs
OPEN = {} # plugins have open and (maybe) accept functions as a tuple
_initialized = False
import os, sys
def moduleinit():
'''Explicitly initializes the library. This function
loads all available file format drivers.
This routine has been lifted from PIL, the Python Image Library'''
global _initialized
global pluginID
if _initialized:
return
visited = {}
directories = sys.path
try:
directories = directories + [os.path.dirname(__file__)]
except NameError:
pass
# only check directories (including current, if present in the path)
for directory in filter(isDirectory, directories):
fullpath = os.path.abspath(directory)
if visited.has_key(fullpath):
continue
for file in os.listdir(directory):
if file[-19:] == "TestReaderPlugin.py":
f, e = os.path.splitext(file)
try:
sys.path.insert(0, directory)
try: # FIXME: this will not reload and hence pluginID
# will be unpopulated leading to "cannot identify format"
__import__(f, globals(), locals(), [])
finally:
del sys.path[0]
except ImportError:
print f, ":", sys.exc_value
visited[fullpath] = None
if OPEN:
_initialized = True
return 1
class Reader:
'''Base class for image file format handlers.'''
def __init__(self, fp=None, filename=None):
self.filename = filename
if isStringType(filename):
import __builtin__
self.fp = __builtin__.open(filename) # attempt opening
# this may fail if not implemented
self._open() # unimplemented in base class but provided by plugins
def _open(self):
raise NotImplementedError(
"StubImageFile subclass must implement _open"
)
# this is the generic open that tries to find the appropriate handler
def open(fp):
'''Probe an image file
Supposed to attempt all opening methods that are available. Each
of them is supposed to fail quickly if the filetype is invalid for its
respective format'''
filename=fp
moduleinit() # make sure we have access to all the plugins
for i in pluginID:
try:
factory, accept = OPEN[i]
if accept:
fp = accept(fp)
# accept is expected to either return None (if unsuccessful)
# or hand back a file handle to be used for opening
if fp:
fp.seek(0)
return factory(fp, filename=filename)
except (SyntaxError, IndexError, TypeError):
pass # I suppose that factory is allowed to have these
# exceptions for problems that weren't caught with accept()
# hence, they are simply ignored and we try the other plugins
raise IOError("cannot identify format")
# --------------------------------------------------------------------
# Plugin registry
def register_open(id, factory, accept=None):
pluginID.append(id)
OPEN[id] = factory, accept
# --------------------------------------------------------------------
# Internal:
# type stuff
from types import StringType
def isStringType(t):
return isinstance(t, StringType)
def isDirectory(f):
'''Checks if an object is a string, and that it points to a directory'''
return isStringType(f) and os.path.isdir(f)
幕后的重要一点是在第一次尝试打开文件(moduleinit)时注册所有格式插件。每个符合条件的插件都必须位于可访问的路径中并命名为 *TestReaderPlugin.py。它将(动态)导入。每个插件模块都必须调用一个 register_open 来提供一个 ID、一个创建文件的方法和一个接受函数来测试候选文件。
一个示例插件将如下所示:
import TestReader
def _accept(filename):
fp=open(filename,"r")
# we made it here, so let's just accept this format
return fp
class exampleTestReader(TestReader.Reader):
format='example'
def _open(self):
self.data = self.fp.read()
TestReader.register_open('example', exampleTestReader, accept=_accept)
TestReader.open() 是用户将使用的函数:
import TestReader
a=TestReader.open(filename) # easy
那么 - 问题出在哪里?首先,我仍在寻找pythonic方式。是这个吗?我怀疑它的理由是 moduleinit 阶段的魔法看起来很混乱。它是直接从 PIL 复制的。主要问题:如果您重新加载(TestReader),它将全部停止工作,因为 ID 被初始化为 [],但插件不会重新加载。
有没有更好的方法来设置一个通用阅读器,
1. 允许对所有格式进行简单的 open(filename) 调用,
2. 只需要为您想要的任何格式提供很好封装的插件。
3. 可以重装吗?