首先,我将cython 0.18与python 2.7.4结合使用。我正在经历一个相当奇怪的虫子,我不知道为什么这是玩具代码:

from cpython cimport bool

cpdef unsigned int func(char *seq1, char *seq2, bool case_sensitive=True):
        print 'seq1', seq1, len(seq1)
        print 'seq2', seq2, len(seq2)
        print

        #take care of case sensitivity
        if not case_sensitive:
                #this is kinda hacky, but I've gotta assign the lowercased string to a Python object before assigning it back to char *
                #see http://docs.cython.org/src/userguide/language_basics.html#caveats-when-using-a-python-string-in-a-c-context
                temp = seq1.lower()
                seq1 = temp

                temp = seq2.lower()
                seq2 = temp

        print 'seq1', seq1, len(seq1)
        print 'seq2', seq2, len(seq2)
        print

        #trim common characters at the beginning of the words
        while len(seq1) > 0 and len(seq2) > 0 and seq1[0] == seq2[0]:
                temp = seq1[1:]
                seq1 = temp

                temp = seq2[1:]
                seq2 = temp

        print 'seq1', seq1, len(seq1)
        print 'seq2', seq2, len(seq2)
        print

        #handle degenerate cases
        if not seq1:
                return len(seq2)
        if not seq2:
                return len(seq1)

下面是一个示例调用:
>>> from func import func
>>> print func('TUESDAYs', 'tuesday', False)

现在,我希望看到的是:
seq1 TUESDAYs 8
seq2 tuesday 7

seq1 tuesdays 8
seq2 tuesday 7

seq1 s 1
seq2  0

1

但我实际上看到的是:
seq1 TUESDAYs 8
seq2 tuesday 7

seq1 tuesdays 8
seq2 tuesday 7

seq1 stdout 6
seq2 tuesday 7

0

这到底是怎么回事?首先,为什么要输出为什么我得不到我应该得到的输出?这是一只赛顿虫,还是我只是错过了一些琐碎的东西?

最佳答案

问题是在所有这样的情况下:

temp = seq1.lower()
seq1 = temp

temp = seq2.lower()

你需要跳这个舞而不仅仅是因为你在问题中指出的原因是因为。
但你所做的并不是正确的,这足以诱使cython认为这是正确的,并编译垃圾。
让我们一行一行地说:
temp = seq1.lower()

这将从seq1 = seq1.lower()中创建一个str,调用其seq1,并将结果存储在lower()中。
seq1 = temp

这使得temp成为指向seq1str对象的内部缓冲区的指针。正如文件特别指出的:
因此,您有责任在必要时保留参考p。
temp = seq2.lower()

这个yadda yadda yaddas,并将结果存储在temp中。因此,它释放了temp的旧值。这是你唯一提到的temp。因此,GC可以自由地收集它,并立即这样做这意味着str现在指向已释放对象的内部缓冲区。
前两次,你显然很幸运,缓冲区不会被重用。但最终,在seq1循环中,它失败了,缓冲区被重用了,最后得到一个指向其他字符串缓冲区的指针。
那么,你怎么解决这个问题呢?
好吧,只要有需要,你可以保留所有中间引用。
但实际上,你为什么需要whileseq1作为seq2值呢你不会从中得到任何性能上的好处事实上,你从中得到了额外的性能成本每次使用char*作为seq1时,它都会从缓冲区中创建一个新的str对象(并复制缓冲区),即使您已经有了一个非常好的对象,如果您没有欺骗Cython,您也可以保留它。
因此,最简单的解决方法是将第一行替换为:
cpdef unsigned int func(char *sequence1, char *sequence2, bool case_sensitive=True):
    seq1, seq2 = str(sequence1), str(sequence2)

(实际上您不需要在那里调用str函数;事实上您不需要str变量就足够了。但我认为这让我们的意图更加明确。)

关于python - Cython的意外输出和返回值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15982503/

10-09 17:12