Python 子类化ctypes指针-这段代码是如何工作的,我如何重写它?
我正在使用Python 子类化ctypes指针-这段代码是如何工作的,我如何重写它?,python,ctypes,Python,Ctypes,我正在使用pylibtiff库(托管),并尝试扩展类TIFF(ctypes.c\u void\u p)。我在使用以下方法时遇到问题: #lib已加载到libtiff.so或等效文件的路径 libtiff=ctypes.cdll.LoadLibrary(lib) 类别TIFF(ctypes.c\u void\u p): @类方法 def open(cls,文件名,mode='r'): “”“以tiff格式打开tiff文件。 """ tiff=libtiff.TIFFOpen(文件名,模式) 如果t
pylibtiff
库(托管),并尝试扩展类TIFF(ctypes.c\u void\u p)
。我在使用以下方法时遇到问题:
#lib已加载到libtiff.so或等效文件的路径
libtiff=ctypes.cdll.LoadLibrary(lib)
类别TIFF(ctypes.c\u void\u p):
@类方法
def open(cls,文件名,mode='r'):
“”“以tiff格式打开tiff文件。
"""
tiff=libtiff.TIFFOpen(文件名,模式)
如果tiff.value为无:
raise TypeError('无法打开文件'+`filename'))
返回tiff
(全班)
现在,这里的预期使用模式是打开一个文件并接收一个类TIFF
实例,如下所示:
class TIFFDifferent(TIFF):
…
@classmethod
def open(cls, filename, mode='r'):
tiff = libtiff.TIFFOpen(filename, mode)
if tiff.value is None:
raise TypeError ('Failed to open file '+`filename`)
return cls(tiff)
class TIFFDifferent(TIFF):
…
@classmethod
def open(cls, filename, mode='r'):
stash = libtiff.TIFFOpen.restype
libtiff.TIFFOpen.restype = cls
tiff = libtiff.TIFFOpen(filename, mode)
libtiff.TIFFOpen.restype = stash
if tiff.value is None:
raise TypeError ('Failed to open file '+`filename`)
return tiff
导入libtiff
t=libtiff.TIFF.open('myfile.TIFF')
#例如,获取数据的numpy数组:
arr=t.读取图像()
这是什么魔法?libtiffTIFF*
中的C变量如何回到pythonland并自动成为类TIFF
实例?这大概与ctypes.c\u void\u p
我这样做是因为我试图覆盖类TIFF
上的一个方法:
导入libtiff
类别TIFF不同(libtiff.TIFF):
def read_图像(自身、详细=错误、不同=错误):
如果没有不同:
返回libtiff.TIFF.read_图像(self,verbose)
#我的不同代码。。。
但是,当我尝试创建一个类TIFF different
实例时,我得到的是类TIFF
:
[3]中的:t=libtiffdifferent.TIFFdifferent.open('file.tiff'))
在[4]中:arr=t.read\u图像(different=True)
---------------------------------------------------------------------------
TypeError回溯(最近一次调用上次)
在()
---->1 arr=t.read\u图像(不同=真)
TypeError:read_image()获得意外的关键字参数“different”
在[5]:t.read_图像?
类型:instancemethod
字符串形式:
文件:/Library/Python/2.7/site-packages/libtiff/libtiff_ctypes.py
定义:t.read_图像(self,verbose=False)
文档字符串:
从TIFF读取图像并将其作为数组返回。
In[6]:t
出[6]:
因此,我需要做的是重写
open
——如果不理解从CTIFF*
到pythonclass TIFF
实例的神奇转换,我不知道如何做,而不需要构造函数、强制转换或任何其他显式操作。神奇之处在于:
如ctypes
文档中所述,您不必使用ctypes
类型作为结果类型;您可以指定任何可调用的Python,通常是一个函数,它将验证实C返回值以引发异常,或者是一个类,它将实C返回值作为其构造函数参数
您可能会注意到TIFF
类没有定义\uuuu init\uuuu
方法。这就是继承自c\u void\u p
的地方:您可以从指针构造c\u void\u p
;因此,如果您有一个子类c\u void\u p
,并且它不需要进行任何其他初始化,那么它可以依赖基类构造来处理它
因此,我需要做的是重写open,如果不理解从CTIFF*
到python classTIFF
实例的神奇转换,我不知道如何做,没有构造函数、cast或任何其他显式的东西
很明显,您可以在覆盖中执行显式构造调用,即使原始版本没有这样做:
def myopen(*args):
tiffpointer = libtiff.cfunc(*args)
return TIFF(tiffpointer)
但是,如果不能定义libtiff.cfunc.restype
(例如,因为pylibtiff
中的某些其他代码依赖于它返回不同的结果),则只需要这样做
不管怎样,我不确定这是你真正想要做的。你要做的是写这样的东西:
class TIFFDifferent(TIFF):
…
@classmethod
def open(cls, filename, mode='r'):
tiff = libtiff.TIFFOpen(filename, mode)
if tiff.value is None:
raise TypeError ('Failed to open file '+`filename`)
return cls(tiff)
class TIFFDifferent(TIFF):
…
@classmethod
def open(cls, filename, mode='r'):
stash = libtiff.TIFFOpen.restype
libtiff.TIFFOpen.restype = cls
tiff = libtiff.TIFFOpen(filename, mode)
libtiff.TIFFOpen.restype = stash
if tiff.value is None:
raise TypeError ('Failed to open file '+`filename`)
return tiff
这是可行的,您根本不必理解restype
背后的魔力。除非您担心构建一个短期的临时TIFF
对象的成本(正如您所看到的,除了c\u void\u p
之外,它没有成员,也没有构造函数代码),否则这还不够简单吗
还有一种可能性,我通常不会建议,在这里可能不合适,但可能是:如果pylibtiff
的设计方式使得很难通过子类重写其行为,那么您可以(a)分叉代码并使用自己的版本,或者(b)在运行时使用monkeypatch。正如您在自己的评论中所建议的,类似这样的事情:
class TIFFDifferent(TIFF):
…
@classmethod
def open(cls, filename, mode='r'):
tiff = libtiff.TIFFOpen(filename, mode)
if tiff.value is None:
raise TypeError ('Failed to open file '+`filename`)
return cls(tiff)
class TIFFDifferent(TIFF):
…
@classmethod
def open(cls, filename, mode='r'):
stash = libtiff.TIFFOpen.restype
libtiff.TIFFOpen.restype = cls
tiff = libtiff.TIFFOpen(filename, mode)
libtiff.TIFFOpen.restype = stash
if tiff.value is None:
raise TypeError ('Failed to open file '+`filename`)
return tiff
如果您的构造函数可能抛出异常,那么您可能希望将存储打包到
contextmanager
(或者使用try:
/finally:
)中;否则,您将使重新键入
保持修补状态。神奇之处在于:
如ctypes
文档中所述,您不必使用ctypes
类型作为结果类型;您可以指定任何可调用的Python,通常是一个函数,它将验证实C返回值以引发异常,或者是一个类,它将实C返回值作为其构造函数参数
您可能会注意到TIFF
类没有定义\uuuu init\uuuu
方法。这就是继承自c\u void\u p
的地方:您可以从指针构造c\u void\u p
;因此,如果您有一个子类c\u void\u p
,并且它不需要进行任何其他初始化,那么它可以依赖基类构造来处理它
因此,我需要做的是重写open,如果不理解从CTIFF*
到python类