2014-11-19 17 views
5

Mam ogromny str o długości ~ 1GB:Widok Pythona str

>>> len(L) 
1073741824 

muszę przybierać różne kawałki sznurka od konkretnych indeksów do końca łańcucha. W C zrobiłbym:

char* L = ...; 
char* p1 = L + start1; 
char* p2 = L + start2; 
... 

Ale w Pythonie, krojenie ciąg tworzy nową instancję str używając więcej pamięci:

>>> id(L) 
140613333131280 
>>> p1 = L[10:] 
>>> id(p1) 
140612259385360 

Aby zaoszczędzić pamięć, w jaki sposób utworzyć obiekt STR-like to jest w rzeczywistości wskaźnik do oryginalnego L?

Edit: mamy buffer i memoryview w Pythonie 2 i Python 3, ale memoryview nie wykazują ten sam interfejs jako str lub bytes:

>>> L = b"0" * 1000 
>>> a = memoryview(L) 
>>> b = memoryview(L) 
>>> a < b 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unorderable types: memoryview() < memoryview() 

>>> type(b'') 
<class 'bytes'> 
>>> b'' < b'' 
False 
>>> b'0' < b'1' 
True 
+0

nie można po prostu zrobić 'id (L [10:])' zamiast tworzenia nowej zmiennej? – HarryCBurn

+0

@Iplodman Wciąż tworzy nowy plaster, używając pamięci, a następnie odrzuca tymczasowy kawałek. – vz0

+0

Python ma typ bufora, patrz http://stackoverflow.com/questions/3422685/what-is-python-buffer-type-for – gabber

Odpowiedz

5

Jest to rodzaj memoryview:

>>> v = memoryview('potato') 
>>> v[2] 
't' 
>>> v[-1] 
'o' 
>>> v[1:4] 
<memory at 0x7ff0876fb808> 
>>> v[1:4].tobytes() 
'ota' 
+0

edytowane pytanie – vz0

+0

Być może twoja odpowiedź powinna być edytowana, aby używać bajtów, aby działała również w pythonie 3. Albo usuń tag 3.x z pytania. –

+0

@AndrasDeak nie wstydź się, po prostu edytuj to bezpośrednio. – wim

1

Jeśli chcesz pracować na łańcuchu, użyj iteratorów, aby uzyskać rzeczywisty dostęp do danych bez duplikowania zawartości w pamięci

Twój narzędzie handlu byłoby itertools.tee i itertools.islice

>>> L = "Random String of data" 
>>> p1, p2 = tee(L) 
>>> p1 = islice(p1,10,None) 
>>> p2 = islice(p2,15,None) 
>>> ''.join(p1) # This now creates a copy now 
'ing of data' 
>>> ''.join(p2) # This now creates a copy now 
'f data' 

to w sensie dosłownym, uzyskując wskaźnik, w przeciwieństwie do C/C++, to tylko do przodu Kursor/iterator

Uwaga Wyłączony -kurs należy wykonać z należytą starannością, korzystając z forwardowanych iteratorów, mianowicie:

  1. Aby zapisać wskaźnik przed advan cing. itertools.tee byłby przydatny tutaj, jak w p1, p_saved = tee(p1)
  2. Możesz czytać jako znak next(p1) lub jako ciąg ''.join(p1), ale ponieważ ciąg python nie jest zmienny, za każdym razem, gdy potrzebujesz widoku ciągu, byłbyś prezentowany jako kopia.
  3. Ponieważ można czytać jako pojedyncze znaki, wszystkie algorytmy powinny wykorzystywać możliwości iterowalne, zamiast generować ciąg. Na przykład, aby porównać dwa itertors, zamiast porównywania zawartości ''.join(p1) == ''.join(p2), należy wykonać następujące czynności all(a == b for a, b in izip(p1, p2))
+0

edytowane pytanie – vz0

+0

@ vz0: Wydaje się, moja odpowiedź jest nadal ważna po edycji – Abhijit

+1

Nie, nie jest. Nie można porównywać vz0

Powiązane problemy