首先,我将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
成为指向seq1
中str
对象的内部缓冲区的指针。正如文件特别指出的:因此,您有责任在必要时保留参考p。
temp = seq2.lower()
这个yadda yadda yaddas,并将结果存储在
temp
中。因此,它释放了temp
的旧值。这是你唯一提到的temp
。因此,GC可以自由地收集它,并立即这样做这意味着str
现在指向已释放对象的内部缓冲区。前两次,你显然很幸运,缓冲区不会被重用。但最终,在
seq1
循环中,它失败了,缓冲区被重用了,最后得到一个指向其他字符串缓冲区的指针。那么,你怎么解决这个问题呢?
好吧,只要有需要,你可以保留所有中间引用。
但实际上,你为什么需要
while
和seq1
作为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/