Я конвертирую код с другого языка на python. Этот код читает довольно большой файл в строке, а затем манипулирует им индексированием массива, например:
str[i] = 'e'
Это не работает непосредственно в python из-за неизменяемости строк. Каков предпочтительный способ сделать это в python?
Я видел функцию string.replace()
, но возвращает копию строки, которая не кажется очень оптимальной, так как строка в этом случае является целым файлом.
l = list(str)
l[i] = 'e'
str = ''.join(l)
Предполагая, что вы не используете текстовую кодировку переменной длины, такую как UTF-8, вы можете использовать array.array
:
>>> import array
>>> a = array.array('c', 'foo')
>>> a[1] = 'e'
>>> a
array('c', 'feo')
>>> a.tostring()
'feo'
Но поскольку вы имеете дело с содержимым файла, mmap
должно быть более эффективным:
>>> f = open('foo', 'r+')
>>> import mmap
>>> m = mmap.mmap(f.fileno(), 0)
>>> m[:]
'foo\n'
>>> m[1] = 'e'
>>> m[:]
'feo\n'
>>> exit()
% cat foo
feo
Здесь приведен быстрый тест script (вам нужно будет заменить dd чем-то другим для не-Unix-ОС):
import os, time, array, mmap
def modify(s):
for i in xrange(len(s)):
s[i] = 'q'
def measure(func):
start = time.time()
func(open('foo', 'r+'))
print func.func_name, time.time() - start
def do_split(f):
l = list(f.read())
modify(l)
return ''.join(l)
def do_array(f):
a = array.array('c', f.read())
modify(a)
return a.tostring()
def do_mmap(f):
m = mmap.mmap(f.fileno(), 0)
modify(m)
os.system('dd if=/dev/random of=foo bs=1m count=5')
measure(do_mmap)
measure(do_array)
measure(do_split)
Выход, который я получил на своем ноутбуке с несколькими годами, соответствует моей интуиции:
5+0 records in
5+0 records out
5242880 bytes transferred in 0.710966 secs (7374304 bytes/sec)
do_mmap 1.00865888596
do_array 1.09792494774
do_split 1.20163106918
Итак, mmap немного быстрее, но ни одно из предлагаемых решений не отличается. Если вы видите огромную разницу, попробуйте использовать cProfile, чтобы узнать, что займет время.
Другие ответили на часть манипуляции с строкой вашего вопроса, но я думаю, вам следует подумать, было бы лучше проанализировать файл и изменить структуру данных, которую представляет текст, а не напрямую манипулировать текстом.
Try:
sl = list(s)
sl[i] = 'e'
s = ''.join(sl)