5

我注意到在 python 中,字符串对象只保留一份副本。就像下面的代码:

>>> s1='abcde'
>>> s2='abcde'
>>> s1 is s2
True

s1 和 s2 指向同一个对象。

当我编辑 s1 时,s2 仍然保留对象('abcde'),但 s1 指向一个新副本。这种行为喜欢写时复制。

>>> s1=s1+'f'
>>> s1 is s2
False
>>> s1
'abcdef'
>>> s2
'abcde'

那么python真的在字符串对象上使用复制机制吗?

4

4 回答 4

3

是的; s1和都s2指向同一个对象;因为他们是实习生(基于一些rules);

In [73]: s1='abcde'

In [74]: s2='abcde'

In [75]: id(s1), id(s2), s1 is s2
Out[75]: (63060096, 63060096, True)

就像一条规则是;您只能使用 ascii 字母、数字或下划线;

In [77]: s1='abcde!'

In [78]: s2='abcde!'

In [79]: id(s1), id(s2), s1 is s2
Out[79]: (84722496, 84722368, False)

还; 有趣的是默认情况下所有 0 和长度为 1 的字符串都被保留;

In [80]: s1 = "_"

In [81]: s2 = "_"

In [82]: id(s1), id(s2), s1 is s2
Out[82]: (8144656, 8144656, True)

In [83]: s1 = "!"

In [84]: s2 = "!"

In [85]: id(s1), id(s2), s1 is s2
Out[85]: (8849888, 8849888, True)

如果我将在运行时生成我的字符串;它不会被拘留;

In [86]: s1 = "abcde"

In [87]: s2 = "".join(['a', 'b', 'c', 'd', 'e'])

In [88]: id(s1), id(s2), s1 is s2
Out[88]: (84722944, 84723648, False)

"...during peephole optimization is called constant folding and consists in simplifying constant expressions in advance"(来自链接)并且这些基于上述规则的表达式将被实习

In [91]: 'abc' +'de' is 'abcde'
Out[91]: True

In [92]: def foo():
    ...:     print "abc" + 'de'
    ...:     

In [93]: def foo1():
    ...:     print "abcde"
    ...:     

In [94]: dis.dis(foo)
  2           0 LOAD_CONST               3 ('abcde')
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE        

In [95]: dis.dis(foo1)
  2           0 LOAD_CONST               1 ('abcde')
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE        

并且长度小于等于20的;

In [96]: "a" * 20 is 'aaaaaaaaaaaaaaaaaaaa'
Out[96]: True

In [97]: 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
Out[97]: False

这一切都是因为python字符串是不可变的;你不能编辑它们;

In [98]: s1 = "abcde"

In [99]: s1[2] = "C"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-99-1d7c49892017> in <module>()
----> 1 s1[2] = "C"

TypeError: 'str' object does not support item assignment

Python提供了intern内置函数;在 python 3.x 中,它位于sys 模块中;

In [100]: s1 = 'this is a longer string than yours'

In [101]: s2 = 'this is a longer string than yours'

In [102]: id(s1), id(s2), s1 is s2
Out[102]: (84717088, 84717032, False)

In [103]: s1 = intern('this is a longer string than yours')

In [104]: s2 = intern('this is a longer string than yours')

In [105]: id(s1), id(s2), s1 is s2
Out[105]: (84717424, 84717424, True)

您可以在以下给定链接中阅读更多内容:

http://guilload.com/python-string-interning/

Python 是否实习字符串?

于 2015-02-25T07:57:24.227 回答
3

没有任何相关意义上的复制发生。您的新字符串是一个全新的字符串对象。这与你做了没有什么不同s1 = 'abcdef'。Python 中的某些类型的对象允许您“就地”修改它们,但不能修改字符串。(用 Python 的说法,字符串是不可变的。)

请注意,您的两个原始字符串是同一个对象的事实是由于特定于实现的优化,并不总是如此:

>>> s1 = 'this is a longer string than yours'
>>> s2 = 'this is a longer string than yours'
>>> s1 is s2
False
于 2015-02-25T05:36:38.343 回答
1

它正在自己创建一个新的字符串对象!

s1=s1+'f'

与以下没有什么不同:

s1 = 'abcdef'

请注意,如果您多次附加到一个字符串(因为您实际上是在创建多个字符串),这会显着减慢您的程序。这是一个已知的反模式,因为每个连接都会创建一个新字符串。这导致 O(N^2) 运行时间

于 2015-02-25T05:38:26.523 回答
-1

字符串是不可变的。因此你不能“编辑”一个字符串。你会在你认为你“编辑”它的地方得到一个新的副本,即新的字符串对象。

于 2015-02-25T05:37:43.777 回答