Две строки 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 → каждая строка "Аризона"... хранится только один раз, отлично.
НО напишите список на диск и снова прочитайте его:
"тот же самый" список теперь имеет N разных идентификаторов(), больше памяти, см. ниже.
Как получилось: может ли кто-нибудь объяснить выделение строки строки 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 division
from collections import defaultdict
from copy import copy
import cPickle
import random
import 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/info/2117255/python-deep-getsizeof-list-with-contents
N = 10000
exec( "\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()
# list to a file, back again -- each string is allocated anew
joinsplit = "\n".join(names).split() # same as > file > mem again
assert joinsplit == names
print "%d strings from a file: %s" % (N, nid(joinsplit) )
# 10000 strings in mem: 10 ids 42149 pickle len
# 10000 strings from a file: 10000 ids 188080 pickle len
# Python 2.6.4 mac ppc
Добавлено 25jan:
В памяти Python (или любой программы) есть два типа строк:
- Установки в Ucache уникальных строк: они сохраняют память и быстро делают == b, если оба находятся в Ucache
- Ostrings, остальные, которые могут храниться любое количество раз.
intern(astring)
помещает вёрстка в Ucache (Alex +1);
кроме того, что мы ничего не знаем о том, как Python перемещает Ostrings в Ucache -
как "a" + "b" встал после "ab"?
( "Строки из файлов" бессмысленны - нет способа узнать.)
Короче говоря, Ucaches (может быть несколько) остаются мутными.
Историческая сноска: SPITBOL uniquified все строки ca. 1970.