2013-09-06 17 views
33

die documentation auf memoryview Überprüfung:Was genau der Punkt von memoryview in Python ist

memoryview objects allow Python code to access the internal data of an object that supports the buffer protocol without copying.

class memoryview(obj)

Create a memoryview that references obj. obj must support the buffer protocol. Built-in objects that support the buffer protocol include bytes and bytearray.

Dann werden wir den Beispielcode gegeben:

>>> v = memoryview(b'abcefg') 
>>> v[1] 
98 
>>> v[-1] 
103 
>>> v[1:4] 
<memory at 0x7f3ddc9f4350> 
>>> bytes(v[1:4]) 
b'bce' 

Zitat über, lässt nun ein nehmen genauerer blick:

>>> b = b'long bytes stream' 
>>> b.startswith(b'long') 
True 
>>> v = memoryview(b) 
>>> vsub = v[5:] 
>>> vsub.startswith(b'bytes') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'memoryview' object has no attribute 'startswith' 
>>> bytes(vsub).startswith(b'bytes') 
True 
>>> 
So

, was ich aus der oben sammeln:

Wir schaffen ein memoryview Objekt, um die internen Daten eines Puffer-Objekt zu belichten, ohne Kopieren, aber, um etwas Sinnvolles mit dem Objekt zu tun (mit Hilfe der Methoden vom Objekt bereitgestellt), müssen wir eine Kopie erstellen!

Normalerweise wird memoryview (oder das alte Pufferobjekt) benötigt, wenn wir ein großes Objekt haben, und die Scheiben können auch groß sein. Die Notwendigkeit für eine bessere Effizienz wäre vorhanden, wenn wir große Scheiben oder kleine Scheiben machen, aber eine große Anzahl von Malen.

Mit dem obigen Schema, sehe ich nicht, wie es für beide Situationen nützlich sein kann, es sei denn jemand kann mir erklären, was ich hier vermisse.

Edit1:

Wir haben einen großen Teil der Daten, wollen wir es durch Vorschieben durch sie von Anfang bis Ende, zum Beispiel Extrahieren von Token von dem Start eines String-Puffers verarbeiten, bis der Puffer konsumiert. Im C-Term führt dies einen Zeiger durch den Puffer und der Zeiger kann an jede Funktion übergeben werden, die den Puffertyp erwartet. Wie kann etwas Ähnliches in Python getan werden?

Die Leute empfehlen Abhilfe, zum Beispiel viele String-und Regex-Funktionen nehmen Position Argumente, die verwendet werden können, um einen Zeiger zu emulieren. Es gibt zwei Probleme damit: erstens es ist eine Arbeit herum, Sie sind gezwungen, Ihren Code-Stil zu ändern, um die Mängel zu überwinden, und Sekunde: nicht alle Funktionen haben Positionsargumente, zum Beispiel Regex-Funktionen und startswith tun, encode()/decode() nicht.

Andere könnten vorschlagen, die Daten in Chunks zu laden oder den Puffer in kleinen Segmenten zu verarbeiten, die größer sind als das max-Token. Okay, wir sind uns dieser möglichen Workarounds bewusst, aber wir sollten auf eine natürlichere Weise in Python arbeiten, ohne zu versuchen, den Codierungsstil an die Sprache anzupassen - nicht wahr?

Edit2:

Ein Code-Beispiel würde die Dinge klarer. Das ist es, was ich tun möchte, und was ich als Memoryview annahm, würde mir erlauben, es auf den ersten Blick zu tun.Ermöglicht Verwendung PMView (richtige Speicheransicht) für die Funktionalität, die ich suche:

tokens = [] 
xlarge_str = get_string() 
xlarge_str_view = pmview(xlarge_str) 

while True: 
    token = get_token(xlarge_str_view) 
    if token: 
     xlarge_str_view = xlarge_str_view.vslice(len(token)) 
     # vslice: view slice: default stop paramter at end of buffer 
     tokens.append(token) 
    else: 
     break 
+0

möglich duplikat von [Wann sollte eine memoryview verwendet werden?] (Http://stackoverflow.com/questions/4845418/when-should-a-memoryview-be-used) –

+3

Die Antwort in der referenzierten Frage doesn ' t liefern Details. Die Frage berührt auch nicht potentielle Probleme aus Sicht des Lernenden. –

Antwort

28

memoryview Objekte groß sind, wenn Sie Untergruppen von binären Daten benötigen, die nur Indizierung unterstützen müssen. Anstatt Scheiben zu nehmen (und neue, potentiell große) Objekte zu erstellen, die an eine andere API übergeben werden, können Sie einfach ein memoryview Objekt nehmen.

Ein solches API Beispiel wäre das struct Modul. Anstatt ein Stück des großen Objekts bytes zu übergeben, um gepackte C-Werte auszuwerten, geben Sie eine memoryview nur der Region ein, aus der Sie Werte extrahieren müssen.

memoryview Objekte, in der Tat, Unterstützung struct entpacken nativ; Sie können eine Region des zugrunde liegenden bytes-Objekts mit einem Slice anvisieren und anschließend .cast() verwenden, um die zugrunde liegenden Bytes als Ganzzahlen, Gleitkommawerte oder n-dimensionale Listen von Ganzzahlen zu interpretieren. Dies ermöglicht sehr effiziente Binärformat-Interpretationen, ohne dass mehr Kopien der Bytes erstellt werden müssen.

+0

Und was tun Sie, wenn Sie Subsets benötigen, die mehr als nur Indizierung unterstützen ?! –

+1

@BaselShishani: Verwenden Sie keine 'Speicheransicht'. Sie haben es mit Text und nicht mit Binärdaten zu tun. –

+0

Ja, im Umgang mit Text. Wir benutzen also nicht Memoryview, gibt es eine Alternative? –

31

Ein Grund memoryviews sind nützlich, weil sie in Scheiben geschnitten werden können, ohne die zugrunde liegenden Daten zu kopieren, im Gegensatz bytes/str.

Nehmen Sie zum Beispiel das folgende Spielzeugbeispiel.

import time 
for n in (100000, 200000, 300000, 400000): 
    data = 'x'*n 
    start = time.time() 
    b = data 
    while b: 
     b = b[1:] 
    print 'bytes', n, time.time()-start 

for n in (100000, 200000, 300000, 400000): 
    data = 'x'*n 
    start = time.time() 
    b = memoryview(data) 
    while b: 
     b = b[1:] 
    print 'memoryview', n, time.time()-start 

Auf meinem Computer, erhalte ich

bytes 100000 0.200068950653 
bytes 200000 0.938908100128 
bytes 300000 2.30898690224 
bytes 400000 4.27718806267 
memoryview 100000 0.0100269317627 
memoryview 200000 0.0208270549774 
memoryview 300000 0.0303030014038 
memoryview 400000 0.0403470993042 

Sie klar quadratische Komplexität des wiederholten String-Slicing sehen kann. Selbst mit nur 400000 Iterationen ist es bereits nicht mehr machbar. Inzwischen hat die Memoryview-Version eine lineare Komplexität und ist blitzschnell.

Edit: Beachten Sie, dass dies in CPython getan wurde. There was a bug in Pypy up to 4.0.1 that caused memoryviews to have quadratic performance.

+0

Das Beispiel funktioniert nicht in Python 3 'TypeError: memoryview: ein Byte-ähnliches Objekt wird benötigt, nicht 'str'' –

+0

@Jose' print' als Anweisung funktioniert auch nicht in Python 3. Dieser Code wurde geschrieben für Python 2, obwohl die für Python 3 erforderlichen Änderungen ziemlich trivial sind. – Antimony

+0

@Yumi Tada, 'str' in python3 ist in python2 völlig anders definiert. – hcnhcn012