Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Cython的意外输出和返回值_Python_Python 2.7_Cython - Fatal编程技术网

Python Cython的意外输出和返回值

Python Cython的意外输出和返回值,python,python-2.7,cython,Python,Python 2.7,Cython,首先,我将Cython0.18与Python2.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) p

首先,我将Cython0.18与Python2.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

这到底是怎么回事?首先,
stdout
为什么要输出?为什么我没有得到我应该得到的输出?这是一个Cython bug,还是我只是遗漏了一些琐碎的东西?

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

temp = seq1.lower()
seq1 = temp

temp = seq2.lower()
你需要跳这种舞,而不是像你在问题中指出的那样只跳
seq1=seq1.lower()

但是你所做的是不正确的,这足以诱使Cython认为它是正确的,并编译垃圾

让我们一行一行地看一下:

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

seq1 = temp
这使得
seq1
成为指向
temp
str
对象的内部缓冲区的指针。正如文件明确指出的:

因此,您有责任在必要时保持参考p

这个yadda-yadda-yadda是,并将结果存储在
temp
中。因此,它释放了
temp
的旧值。这是你唯一引用的
str
。因此,GC可以自由地收集它,并且可以立即收集。这意味着
seq1
现在指向已释放对象的内部缓冲区

前两次,你显然很幸运,缓冲区没有得到重用。但是最终,在
while
循环中,它失败了,缓冲区被重用,最后您得到了指向其他字符串缓冲区的指针


那么,你如何解决这个问题呢

好吧,你可以保留所有这些中间引用,只要它们需要

但实际上,为什么您需要
seq1
seq2
成为
char*
值呢?您不会从中获得任何性能优势。事实上,您从中获得了额外的性能成本。每次您将
seq1
用作
str
,它都会从该缓冲区中创建一个新的
str
对象(并复制缓冲区),即使您已经有了一个非常好的对象,如果您没有欺骗Cython,也可以保留它

因此,最简单的修复方法是将第一行替换为:

cpdef unsigned int func(char *sequence1, char *sequence2, bool case_sensitive=True):
    seq1, seq2 = str(sequence1), str(sequence2)

(你其实不需要那里的
str
调用;事实上你没有
cdef
变量就足够了。但我认为这让意图更清楚了。)

我注意到你从一开始就将
seq1
seq2
用作
str
对象,我打赌你是否添加了显式转换(将参数更改为
s1
s2
,然后在顶部写入
str1,str2=str(s1),str(s2)
),问题就消失了。(至少值得测试。)这是与
char*
和Python
str
对象交互所必需的解决方法。我在代码中有一条注释,描述了我为什么这样做。你将seq1和seq2转换为str的想法很有趣。我会试试。马上回来……是的,我找到了这一部分并删除了注释。但这正是第二次会议的灵感所在d注释。在内部使用char*并没有带来任何性能好处。事实上,我认为您正在使它变慢。对于每个中间步骤,您创建一个Python
str
对象,执行
str
操作,存储
str
结果,然后使
seq1
指向该
str
的缓冲区。然后你用
seq1
构建了一个新的
str
,如果你没有欺骗Cython的话,你可以直接引用旧的。事实上……这也是问题的根源。正如你链接的文档所说,“那么你有责任尽可能长时间地保留参考p。”让我写一个答案。使用Apple Python 2.7.2和Cython 0.17.1,我得到了完全相同的输出,至少在第一次运行时是这样。当然,我期望得到相同的垃圾,但不是完全相同的垃圾。我开始查看生成的C代码,试图找出确切的原因,但是……这不值得。使用三种不同的Python 3.x在不同版本中,我始终将
b'tuday'
作为字符串(或者更确切地说,作为
字节
,因此它打印为
seq1b“b'tuday''10
),而不是
stdout
…如图所示。
cpdef unsigned int func(char *sequence1, char *sequence2, bool case_sensitive=True):
    seq1, seq2 = str(sequence1), str(sequence2)