2012-04-30 20 views
15

这更多的是我尝试理解的Python模块中遇到的一个'有趣'现象,而不是帮助请求(虽然解决方案也是有用的)。违反CPython中的字符串不变性

>>> import fuzzy 
>>> s = fuzzy.Soundex(4) 
>>> a = "apple" 
>>> b = a 
>>> sdx_a = s(a) 
>>> sdx_a 
'A140' 
>>> a 
'APPLE' 
>>> b 
'APPLE' 

呀,所以fuzzy模块完全违反了Python中的不变性。它能够做到这一点,因为它是一个C扩展?这是否构成CPython和模块的错误,甚至是安全风险?

此外,任何人都可以想出一种方法来解决这种行为?我希望能够保留字符串的原始大小写。

干杯,

亚历

+0

我没有看到生成的C中的任何地方它突变字符串。 –

+0

@ IgnacioVazquez-Abrams:也许我错过了一些东西,但是它不会在'__call__' [[__pyx_f_5fuzzy_7Soundex ___ call__']]中变异呢?它声明了一个cdef char ptr,它将其设置为等于PyString_AsString调用的结果,然后修改其内容。 – DSM

+0

@DSM:不在Bitbucket的代码中。我只能看到[891行](https://bitbucket.org/yougov/fuzzy/src/c210ad2f3f68/src/fuzzy.c#cl-891)的内容。 –

回答

13

该错误已得到解决back in February;更新你的版本。

要回答你的问题,是的,有几种方法可以在C级别修改不可变类型。在这一点上,安全影响是未知的,甚至可能是不可知的。

+0

感谢您的回答!实际上,我仅在三周前使用easy_install来安装模糊。它给我的版本是fuzzy-1.0-py2.7-win-amd64.egg,而且这个版本有错误。 – Alex

+0

@Alex:他们并不总是保持在那里;从Bitbucket安装。 –

2

我没有可现在来测试fuzzy模块,但下面有一个新的身份创建一个字符串:

>>> a = "hello" 
>>> b = ''.join(a) 
>>> b 
'hello' 
>>> id(a), id(b) 
(182894286096, 182894559280) 
+0

是的,这个工作:) – Alex

0

如果它改变不可变的字符串,这是一个错误,你可以走过这个:

s(a.upper()) 
2

我不太了解CPython,但看起来像fuzzy.c它声明char *cs = s,其中s__call__的输入。它然后变异cs[i],这将明显变异s[i],因此原始字符串。这绝对是一个模糊的错误,你应该把它归档在bitbucket。正如格雷格的回答所说,使用''.join(a)将创建一个新副本。

+0

它已被提交Bitbucket。两次。 –