5

私は Cython を使い始めたばかりで、Cython 固有のものをグーグルで検索するのも非常に難しいことがわかりました。

Cython で Python 関数を再実装しています。Python では次のようになります。

def func(s, numbers=None):
    if numbers:
         some_dict = numbers
    else:
         some_dict = default
    return sum(some_dict[c] for c in s)

Python 2 と 3 では問題なく動作します。しかし、 and と入力しようとするsc、少なくとも 1 つの Python バージョンで機能しなくなります。私は試した:

def func(char *s, numbers=None):
    if numbers:
         some_dict = numbers
    else:
         some_dict = default
    cdef char c
    cdef double m = 0.0
    for c in s:
        m += some_dict[<bytes>c]
    return m

正直なところ、これは私がまったく機能するようになった唯一のことであり、Python 2 ではまともなスピードアップが得られますが、Python 3 では機能しません。

def func(unicode s, numbers=None):
    if numbers:
         some_dict = numbers
    else:
         some_dict = default
    cdef double m = 0.0
    for c in s:
        m += some_dict[c]
    return m

しかし、実際には a が発生し、まだ a のKeyErrorように見えます (欠落しているキーはa で始まる場合) ですが、私が言うと.cchar80s'P'print(type(c))<class 'str'>

元の型指定されていないコードは両方のバージョンで動作しますが、Python 2 で動作する型付きバージョンよりも約 2 倍遅くなります。

では、Python 3 でまったく動作させるにはどうすればよいでしょうか。また、両方の Python バージョンで同時に動作させるにはどうすればよいでしょうか。型/バージョン チェックで型宣言をラップできますか? それとも、2 つの関数を作成し、そのうちの 1 つを条件付きで公開されている名前に割り当てる必要がありますか?

PS 重要な場合は、文字列に ASCII 文字のみを許可しても問題ありませんが、Cython は明示的なエンコード/デコードを好むように見えるため、そうであるとは思えません。


編集:明示的なエンコードとバイト文字列の反復も試みましたが、これは理にかなっていますが、次のコード:

def func(s, numbers=None):
    if numbers:
         some_dict = numbers
    else:
         some_dict = default
    cdef double m = 0.0
    cdef bytes bs = s.encode('ascii')
    cdef char c
    for c in bs:
        m += some_dict[(<bytes>c).decode('ascii')]
    return m

Python 2 での最初の試行よりも 3 倍遅く (純粋な Python 関数の速度に近い)、Python 3 ではほぼ 2 倍遅くなります。

4

1 に答える 1

0

foo.h

// #include <unistd.h>;  // for ssize_t
double foo(char * str, ssize_t str_len, double weights[256]){
    double output = 0.0;
    int i;
    for(i = 0; i < str_len; ++i){
        output += weights[str[i]];
    }
    return output;
}

from cpython.string cimport PyString_GET_SIZE, PyString_Check, PyString_AS_STRING

cdef extern from "foo.h":
    double foo(char * str, ssize_t str_len, double weights[256])   

cdef class Numbers:
    cdef double nums[256]

    def __cinit__(self, py_numbers):
        for x in range(256):
            self.nums[i] = py_numbers[i]

def py_foo(my_str, Numbers nums_inst):
    cdef:
        double res
    # check here my_str is BYTEstring
    if not PyString_Check(my_str):
        raise TypeError("bytestring expected got %s instead" % type(my_str))
    res = foo(PyString_AS_STRING(my_str), PyString_GET_SIZE(my_str), nums_inst.nums)
    return res

(未テスト)

于 2013-03-12T12:51:58.450 に答える