Python何时为相同的字符串分配新内存?

Python何时为相同的字符串分配新内存?

两个具有相同字符的Python字符串,a == b,可以共享内存,id(a)== id(b),或者可以在内存中两次,id(a)!= id(b)。尝试

ab = "ab"print id( ab ), id( "a"+"b" )

在这里,Python认识到新创建的“a”+“b”与已经在内存中的“ab”相同 - 不错。

现在考虑一个N长的州名列表[“亚利桑那州”,“阿拉斯加”,“阿拉斯加”,“加利福尼亚”......](在我的案例中为N~500000)。
我看到50个不同的id()s⇒每个字符串“Arizona”......只存储一次,很好。
但是将列表写入磁盘并再次读回:“相同”列表现在有N个不同的id()s,内存更多,见下文。

怎么 - 任何人都可以解释Python字符串内存分配?

""" when does Python allocate new memory for identical strings ?
    ab = "ab"
    print id( ab ), id( "a"+"b" )  # same !
    list of N names from 50 states: 50 ids, mem ~ 4N + 50S, each string once
    but list > file > mem again: N ids, mem ~ N * (4 + S)
"""from __future__ import divisionfrom collections import defaultdictfrom copy import copyimport cPickleimport randomimport sys

states = dict(AL = "Alabama",AK = "Alaska",AZ = "Arizona",AR = "Arkansas",CA = "California",CO = "Colorado",CT = "Connecticut",DE = "Delaware",FL = "Florida",GA = "Georgia",)def nid(alist):
    """ nr distinct ids """
    return "%d ids  %d pickle len" % (
        len( set( map( id, alist ))),
        len( cPickle.dumps( alist, 0 )))  # rough est ?# cf http://stackoverflow.com/questions/2117255/python-deep-getsizeof-list-with-contentsN = 10000exec( "\n".join( sys.argv[1:] ))  # var=val ...random.seed(1)

    # big list of random names of states --names = []for j in xrange(N):
    name = copy( random.choice( states.values() ))
    names.append(name)print "%d strings in mem:  %s" % (N, nid(names) )  # 10 ids, even with copy()

添加25jan:
Python内存(或任何程序)中有两种字符串:

  • Ustrings,在一个独特字符串的Ucache中:这些节省内存,如果两者都在Ucache中,则快速== b

  • Ostrings,其他,可以存储任意次数。

intern(astring)在Ucache中放入astring(Alex +1); 除此之外我们对Python如何将Ostrings移动到Ucache一无所知 - “ab”之后“a”+“b”是如何进入的?(“来自文件的字符串”毫无意义 - 没有办法知道。)
简而言之,Ucaches(可能有几个)仍然是模糊的。

一个历史脚注: SPITBOL 统一所有字符串ca. 1970年。


尚方宝剑之说
浏览 669回答 3
3回答

拉莫斯之舞

Python语言的每个实现都可以自由地在分配不可变对象(例如字符串)时做出权衡 - 要么创建一个新的对象,要么找到一个现有的等价对象并再使用一个对它的引用,就好了。观点看法。当然,在实践中,现实世界的实现需要合理的妥协:在定位这样的对象时,再一次提及合适的现有对象既便宜又容易,只要找到一个合适的现有对象(可能是可能不存在)看起来可能需要很长时间搜索。因此,例如,在单个函数中多次出现相同的字符串文字(在我所知的所有实现中)都使用“对同一对象的新引用”策略,因为在构建该函数的常量池时,它非常快速且容易避免重复; 但是跨越不同的功能这样做可能是一项非常耗时的任务,因此现实世界的实施要么根本不做,要么只在一些启发式确定的案例子集中做到这一点,人们可以希望合理权衡编译时间(通过搜索相同的现有常量减慢)与内存消耗(如果继续生成新的常量副本,则增加)。我不知道Python的任何实现(或者其他具有常量字符串的语言,例如Java)在从文件读取数据时会花费很多时间来识别可能的重复项(通过多个引用重用单个对象) - - 它似乎并不是一个很有希望的权衡(在这里你需要支付运行时间,而不是编译时间,因此权衡更具吸引力)。当然,如果您知道(由于应用程序级别的考虑因素)这些不可变对象很大并且很容易出现重复,您可以非常轻松地实现自己的“常量池”策略(实习生可以帮助您为字符串执行此操作,但是你不难推出自己的东西,例如,带有不可变项目的元组,巨大的长整数,

繁华开满天机

我强烈怀疑Python在这里表现得像许多其他语言一样 - 在源代码中识别字符串常量并使用公用表,但在动态创建字符串时不应用相同的规则。这是有道理的,因为源代码中只有一组有限的字符串(当然,Python允许你动态地评估代码),而你在程序过程中创建大量字符串的可能性更大。 。这个过程通常被称为实习 - 实际上,通过这个页面的外观,它也被称为Python实习。

慕虎7371278

旁注:了解Python中对象的生命周期非常重要。请注意以下会话:Python 2.6.4 (r264:75706, Dec 26 2009, 01:03:10) [GCC 4.3.4] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> a="a">>> b="b">>> print id(a+b), id(b+a)134898720 134898720>>> print (a+b) is (b+a)False您认为通过打印两个单独表达式的ID 并注意到“它们是相等的,两个表达式必须相等/等同/相同”是错误的。单行输出并不一定意味着它的所有内容都是在同一时刻创建和/或共存的。如果您想知道两个对象是否是同一个对象,请直接询问Python(使用is运算符)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python