0

私はライブラリ(ここでpylibtiffホストされています)を使用していて、拡張しようとしています。次の方法で問題が発生しました。class TIFF(ctypes.c_void_p)

# lib has been loaded with the path to libtiff.so, or equivalent
libtiff = ctypes.cdll.LoadLibrary(lib)

class TIFF(ctypes.c_void_p):
    @classmethod
    def open(cls, filename, mode='r'):
        """ Open tiff file as TIFF.
        """
        tiff = libtiff.TIFFOpen(filename, mode)
        if tiff.value is None:
            raise TypeError ('Failed to open file '+`filename`)
        return tiff

(フルクラスはこちら

ここで予想される使用パターンは、次のclass TIFFようにファイルを開いてインスタンスを受け取ることです。

import libtiff
t = libtiff.TIFF.open('myfile.tiff')

# e.g. grab a numpy array of the data:
arr = t.read_image()

この魔法は何ですか?libtiffのC変数は、pythonlandに戻ってきて、自動的にインスタンスになるものとしてどのように入力されますか? おそらくこれはのサブクラス化と関係がありますTIFF*class TIFFctypes.c_void_p

私はメソッドをオーバーライドしようとしているので尋ねますclass TIFF

import libtiff
class TIFFdifferent(libtiff.TIFF):
    def read_image(self, verbose=False, different=False):
        if not different:
            return libtiff.TIFF.read_image(self, verbose)

        # my different code ...

ただし、class TIFFdifferentインスタンスを作成しようとすると、class TIFF代わりに次のようになります。

In [3]: t = libtiffdifferent.TIFFdifferent.open('file.tiff')

In [4]: arr = t.read_image(different=True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-8bdc24ec874c> in <module>()
----> 1 arr = t.read_image(different=True)

TypeError: read_image() got an unexpected keyword argument 'different'

In [5]: t.read_image?
Type:       instancemethod
String Form:<bound method TIFF.read_image of <TIFF object at 0x10b67df80>>
File:       /Library/Python/2.7/site-packages/libtiff/libtiff_ctypes.py
Definition: t.read_image(self, verbose=False)
Docstring:
Read image from TIFF and return it as an array.


In [6]: t
Out[6]: <TIFF object at 0x10b67df80>

だから、私がする必要があるのは、オーバーライドすることでもあります-コンストラクター、キャスト、または他の明示的なものなしで、 CからPythonインスタンスへopenの魔法の変換を理解せずに行う方法がわかりません。TIFF*class TIFF

4

1 に答える 1

3

魔法はlibtiff_ctypes.pyの 1041 行にあります。

libtiff.TIFFOpen.restype = TIFF

ドキュメントの15.17.1.8 戻り値の型で説明されているように、結果の型として型ctypesを使用する必要はありません。ctypes任意の Python 呼び出し可能オブジェクトを指定できます。通常は、実際の C の戻り値を検証して例外を発生させる関数、または実際の C の戻り値をコンストラクター引数として受け取るクラスのいずれかです。

TIFFクラスが__init__メソッドを定義していないことに気付くかもしれません。これが from の継承の出番です。ポインタから ac_void_pを構築できます。c_void_pしたがって、 のサブクラスがありc_void_p、他の初期化を行う必要がない場合は、基本クラスの構築に依存するだけで処理できます。

TIFF*だから、私がする必要があるのは、 open もオーバーライドすることです.CからPythonクラスTIFFインスタンスへの魔法の変換を理解せずに、コンストラクター、キャスト、または明示的なものなしで行う方法がわかりません。

元のバージョンがそれを行わなくても、明らかにオーバーライドで明示的な構築呼び出しを行うことができます。

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)

背後にある魔法をまったく理解する必要なく、それは機能restypeします。存続期間の短い一時TIFFオブジェクト (これまで見てきたように、 a 以外のメンバーもコンストラクター コードもありませんc_void_p) を構築するコストについて心配していない限り、これは十分に単純ではありませんか?

通常はお勧めしませんが、おそらくここでは適切ではありませんが、次の可能性がありますpylibtiff。独自のバージョンをコーディングして使用するか、(b) 実行時にモンキーパッチを適用します。あなた自身のコメントで示唆されているように、次のようなものです:

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

コンストラクターが例外をスローする可能性がある場合は、スタッシングを a でラップするcontextmanager(またはtry:/を使用する) ことをお勧めします。finally:そうしないと、restypeパッチを適用したままになります。

于 2012-12-13T19:26:47.107 に答える