【问题标题】:How can I copy a Python string?如何复制 Python 字符串?
【发布时间】:2014-09-08 09:05:18
【问题描述】:

我这样做:

a = 'hello'

现在我只想要a 的独立副本:

import copy

b = str(a)
c = a[:]
d = a + ''
e = copy.copy(a)

map( id, [ a,b,c,d,e ] )

输出[3]:

[4365576160, 4365576160, 4365576160, 4365576160, 4365576160]

为什么它们都有相同的内存地址,我怎样才能得到a的副本?

【问题讨论】:

  • 要获得与 Martijin 不同的答案(这是完全正确的,但不一定如所述回答问题),您可能需要提供更多详细信息/用例以显示 为什么你想复制它。
  • 正如@elemo 所暗示的,这可能是XY Problem
  • 我有兴趣估计d[ 'hello' ] = e 形式的嵌套字典的内存使用情况,其中e[ 'hi' ] = 'again'。为了生成这样一个嵌套字典,我生成了一个 e 字典并多次复制它。我注意到内存消耗非常低,这导致了我的问题。现在我知道没有创建字符串副本,因此内存消耗低。
  • 如果您希望ba 的修改版本而不修改a,只需让b 成为任何操作的结果。例如b = a[2:-1]b 设置为 'll'a 仍然是 'hello'
  • 奥利是正确的。这是因为 str 是不可变类型。由于 python 使用单例(可能还有其他内部优化),复制 e 字典时不会像预期的那样看到内存扩展。

标签: python string python-2.7


【解决方案1】:

您不需要复制 Python 字符串。它们是不可变的,copy 模块在这种情况下总是返回原始值,str() 也是如此,整个字符串切片并与空字符串连接。

此外,您的'hello' 字符串是interned (certain strings are)。 Python 故意尝试只保留一份副本,因为这样可以加快字典查找速度。

解决此问题的一种方法是实际创建一个新字符串,然后将该字符串切回原始内容:

>>> a = 'hello'
>>> b = (a + '.')[:-1]
>>> id(a), id(b)
(4435312528, 4435312432)

但你现在所做的只是浪费内存。毕竟,你不能以任何方式改变这些字符串对象。

如果您只想知道一个 Python 对象需要多少内存,请使用sys.getsizeof();它为您提供任何 Python 对象的内存占用。

对于容器,这包含内容;你必须递归到每个容器来计算总内存大小:

>>> import sys
>>> a = 'hello'
>>> sys.getsizeof(a)
42
>>> b = {'foo': 'bar'}
>>> sys.getsizeof(b)
280
>>> sys.getsizeof(b) + sum(sys.getsizeof(k) + sys.getsizeof(v) for k, v in b.items())
360

然后,您可以选择使用 id() 跟踪来获取实际内存占用量,或者在对象未被缓存和重用的情况下估计最大占用量。

【讨论】:

  • 创建新字符串对象的方法不止一种,例如b = ''.join(a)
  • @martineau:当然,我真的想说“一种方式”。
  • 强调“你不需要复制 Python 字符串”。这些操作只是返回相同的字符串是有原因的。
  • 但是,在这种情况下,OP 正在尝试浪费内存。由于他想知道一定数量的字符串将使用多少内存,这就是实际目标。显然他可以生成唯一的字符串,但作为一种变通方法,这只是不必要的工作。
  • +1 表示“随便”,使用会输出 42 的示例。
【解决方案2】:

你可以通过字符串格式化在python中复制一个字符串:

>>> a = 'foo'  
>>> b = '%s' % a  
>>> id(a), id(b)  
(140595444686784, 140595444726400)  

【讨论】:

  • 在 Python 3.6.5 中不正确。 id(a) 和 id(b) 是相同的。即使我使用现代版本的格式,即b = '{:s}'.format(a),结果也没有什么不同
【解决方案3】:

我刚刚开始一些字符串操作并发现了这个问题。我可能正在尝试做类似 OP 的事情,“通常我”。前面的回答并没有解开我的疑惑,但想了想,我终于“明白了”。

只要abcde 具有相同的值,它们就指向同一个地方。内存已保存。一旦变量开始具有不同的值,它们就会开始具有不同的引用。我的学习经验来自这段代码:

import copy
a = 'hello'
b = str(a)
c = a[:]
d = a + ''
e = copy.copy(a)

print map( id, [ a,b,c,d,e ] )

print a, b, c, d, e

e = a + 'something'
a = 'goodbye'
print map( id, [ a,b,c,d,e ] )
print a, b, c, d, e

打印输出为:

[4538504992, 4538504992, 4538504992, 4538504992, 4538504992]

hello hello hello hello hello

[6113502048, 4538504992, 4538504992, 4538504992, 5570935808]

goodbye hello hello hello hello something

【讨论】:

【解决方案4】:

换一种说法,“id()”不是你关心的。您想知道是否可以在不损害源变量名的情况下修改变量名。

>>> a = 'hello'                                                                                                                                                                                                                                                                                        
>>> b = a[:]                                                                                                                                                                                                                                                                                           
>>> c = a                                                                                                                                                                                                                                                                                              
>>> b += ' world'                                                                                                                                                                                                                                                                                      
>>> c += ', bye'                                                                                                                                                                                                                                                                                       
>>> a                                                                                                                                                                                                                                                                                                  
'hello'                                                                                                                                                                                                                                                                                                
>>> b                                                                                                                                                                                                                                                                                                  
'hello world'                                                                                                                                                                                                                                                                                          
>>> c                                                                                                                                                                                                                                                                                                  
'hello, bye'                                                                                                                                                                                                                                                                                           

如果你习惯了 C,那么这些就像指针变量,只是你不能取消引用它们来修改它们指向的内容,但是 id() 会告诉你它们当前指向的位置。

当您考虑更深层次的结构(如列表或字典)时,python 程序员就会遇到问题:

>>> o={'a': 10}                                                                                                                                                                                                                                                                                        
>>> x=o                                                                                                                                                                                                                                                                                                
>>> y=o.copy()                                                                                                                                                                                                                                                                                         
>>> x['a'] = 20                                                                                                                                                                                                                                                                                        
>>> y['a'] = 30                                                                                                                                                                                                                                                                                        
>>> o                                                                                                                                                                                                                                                                                                  
{'a': 20}                                                                                                                                                                                                                                                                                              
>>> x                                                                                                                                                                                                                                                                                                  
{'a': 20}                                                                                                                                                                                                                                                                                              
>>> y                                                                                                                                                                                                                                                                                                  
{'a': 30}                                                                                                                                                                                                                                                                                              

这里 o 和 x 指的是同一个 dict o['a'] 和 x['a'],并且该 dict 是“可变的”,因为您可以更改键 'a' 的值。这就是为什么 "y" 需要是一个副本,而 y['a'] 可以引用其他东西。

【讨论】:

    【解决方案5】:

    复制字符串可以通过两种方式完成:]

    【讨论】:

      【解决方案6】:

      这是可能的,使用这个简单的技巧:

      a = "Python"
      b = a[ : : -1 ][ : : -1 ]
      print( "a =" , a )
      print( "b =" , b )
      a == b  # True
      id( a ) == id( b ) # False
      

      【讨论】:

        【解决方案7】:

        正如其他人已经解释的那样,实际上很少需要这样做,但是,您可以这样做:
        (适用于 Python 3,但 Python 2 可能有类似的东西)

        import ctypes
        
        copy          = ctypes.pythonapi._PyUnicode_Copy
        copy.argtypes = [ctypes.py_object]
        copy.restype  = ctypes.py_object
        
        s1 = 'xxxxxxxxxxxxx'
        s2 = copy(s1)
        
        id(s1) == id(s2) # False
        

        【讨论】:

          猜你喜欢
          • 2015-11-28
          • 2015-07-25
          • 2014-10-29
          • 2019-07-23
          • 1970-01-01
          • 2021-11-17
          • 2012-07-20
          • 2016-07-10
          • 2017-08-11
          相关资源
          最近更新 更多