वास्तव में पायथन में मेमोरीव्यू का बिंदु क्या है


84

मेमोरीव्यू पर प्रलेखन की जाँच :

मेमोरीव्यू ऑब्जेक्ट्स पायथन कोड को किसी ऑब्जेक्ट के आंतरिक डेटा तक पहुंचने की अनुमति देता है जो कॉपी किए बिना बफर प्रोटोकॉल का समर्थन करता है।

वर्ग मेमोरीव्यू (obj)

एक मेमोरीव्यू बनाएं जो संदर्भों को संदर्भित करता है। obj बफर प्रोटोकॉल का समर्थन करना चाहिए। बफर प्रोटोकॉल का समर्थन करने वाली निर्मित वस्तुएं बाइट्स और बायट्रेयर शामिल हैं।

फिर हमें नमूना कोड दिया जाता है:

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

उद्धरण पर अब, एक करीब देखो ले:

>>> 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
>>> 

तो मैं ऊपर से क्या इकट्ठा करता हूं:

हम कॉपी किए बिना बफर ऑब्जेक्ट के आंतरिक डेटा को उजागर करने के लिए एक मेमोरीव्यू ऑब्जेक्ट बनाते हैं, हालांकि, ऑब्जेक्ट के साथ उपयोगी कुछ भी करने के लिए (ऑब्जेक्ट द्वारा प्रदान की गई विधियों को कॉल करके), हमें एक कॉपी बनाना होगा!

आमतौर पर मेमोरीव्यू (या पुरानी बफर ऑब्जेक्ट) की आवश्यकता होगी जब हमारे पास एक बड़ी वस्तु होगी, और स्लाइस भी बड़ी हो सकती है। अगर हम बड़ी स्लाइस बना रहे हैं, या छोटी स्लाइस बना रहे हैं, लेकिन बड़ी संख्या में, तो बेहतर दक्षता की आवश्यकता मौजूद होगी।

उपरोक्त योजना के साथ, मैं यह नहीं देखता कि यह किसी भी स्थिति के लिए कैसे उपयोगी हो सकता है, जब तक कि कोई मुझे समझा नहीं सकता कि मैं यहां क्या याद कर रहा हूं।

Edit1:

हमारे पास डेटा का एक बड़ा हिस्सा है, हम इसे शुरू से अंत तक आगे बढ़ाकर संसाधित करना चाहते हैं, उदाहरण के लिए एक स्ट्रिंग बफर की शुरुआत से टोकन निकालने तक बफर का सेवन किया जाता है। सी टर्म में, यह एक पॉइंटर को आगे बढ़ा रहा है। बफर, और पॉइंटर को बफर प्रकार की अपेक्षा किसी भी फ़ंक्शन को पास किया जा सकता है। अजगर में ऐसा कुछ कैसे किया जा सकता है?

लोग वर्कअराउंड का सुझाव देते हैं, उदाहरण के लिए कई स्ट्रिंग और रेगेक्स फ़ंक्शन स्थिति तर्क देते हैं जिनका उपयोग पॉइंटर को आगे बढ़ाने के लिए किया जा सकता है। इसके साथ दो मुद्दे हैं: पहला यह एक काम के आसपास है, आपको कमियों को दूर करने के लिए अपनी कोडिंग शैली को बदलने के लिए मजबूर किया जाता है, और दूसरा: सभी कार्यों में स्थिति तर्क नहीं होते हैं, उदाहरण के लिए रेगेक्स फ़ंक्शन और startswithकरते हैं, encode()/ decode()नहीं।

अन्य लोग डेटा को चंक्स में लोड करने, या अधिकतम टोकन से छोटे खंडों में बफर को संसाधित करने का सुझाव दे सकते हैं। ठीक है, तो हम इन संभावित कार्यदलों से अवगत हैं, लेकिन हम भाषा को फिट करने के लिए कोडिंग शैली को मोड़ने की कोशिश किए बिना अजगर में अधिक स्वाभाविक तरीके से काम करने वाले हैं - क्या हम नहीं हैं?

EDIT2:

एक कोड नमूना चीजों को स्पष्ट कर देगा। यह वही है जो मैं करना चाहता हूं, और जो मैंने मेमोरीविले ग्रहण किया, वह मुझे पहली नज़र में करने की अनुमति देगा। मैं देख रहा हूँ कि कार्यक्षमता के लिए pmview (उचित स्मृति दृश्य) का उपयोग करें:

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


9
संदर्भित प्रश्न का उत्तर विस्तार प्रदान नहीं करता है। न ही सीखने वाले कोण से संभावित मुद्दों पर प्रश्न स्पर्श करता है।
बेसल शीशानी

जवाबों:


81

एक कारण memoryviewएस उपयोगी हैं क्योंकि वे अंतर्निहित डेटा की नकल के बिना कटा हुआ हो सकते हैं, इसके विपरीत bytes/ str

उदाहरण के लिए, निम्नलिखित खिलौना उदाहरण लें।

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

मेरे कंप्यूटर पर, मुझे मिलता है

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

आप स्पष्ट रूप से दोहराया स्ट्रिंग टुकड़ा करने की क्रिया की जटिलता देख सकते हैं। केवल 400000 पुनरावृत्तियों के साथ भी, यह पहले से ही अप्राप्य है। इस बीच, मेमोरीव्यू संस्करण में रैखिक जटिलता है और यह तेज़ बिजली है।

संपादित करें: ध्यान दें कि यह CPython में किया गया था। 4.0.1 तक Pypy में एक बग था, जिससे मेमोरीव्यू में द्विघात प्रदर्शन होता था।


उदाहरण अजगर 3 में काम नहीं करता हैTypeError: memoryview: a bytes-like object is required, not 'str'
कलन

@ printएक बयान के रूप में भी पायथन 3 में काम नहीं करता है। यह कोड पायथन 2 के लिए लिखा गया था, हालांकि अजगर 3 के लिए आवश्यक परिवर्तन काफी तुच्छ हैं।
एंटिमोनी

@Yumi Tada, strpython3 में python2 में पूरी तरह से अलग है।
hcnhcn012

3
यह उत्तर इस तथ्य को संबोधित नहीं करता है कि कुछ भी "उपयोगी" करने के लिए, जैसा कि
पूछने वाला

1
@ नागरिक 2077 जैसा कि मेरा उदाहरण दिखाता है, यह मध्यवर्ती हेरफेर को कुशलतापूर्वक करने के लिए उपयोगी है, भले ही आप अंततः इसे बाइट्स ऑब्जेक्ट पर कॉपी करें।
एंटिमोनी

58

memoryviewजब आप द्विआधारी डेटा के सबसेट की आवश्यकता होती है, तो ऑब्जेक्ट्स बहुत अच्छे होते हैं, जिन्हें केवल अनुक्रमण का समर्थन करना होता है। स्लाइस लेने के बजाय (और नई, संभावित बड़ी) वस्तुओं को दूसरे एपीआई में पारित करने के लिए आप केवल एक memoryviewवस्तु ले सकते हैं ।

ऐसा एक एपीआई उदाहरण structमॉड्यूल होगा। bytesपैक्ड सी मूल्यों को पार्स करने के लिए बड़ी वस्तु के एक स्लाइस में पास करने के बजाय , आप memoryviewउस क्षेत्र से गुजरते हैं जिसे आपको निकालने की आवश्यकता है।

memoryviewऑब्जेक्ट्स, वास्तव में, structमूल रूप से अनपैकिंग का समर्थन करते हैं ; आप bytesएक स्लाइस के साथ अंतर्निहित ऑब्जेक्ट के एक क्षेत्र को लक्षित कर सकते हैं , फिर .cast()अंतर्निहित बाइट्स को लंबे पूर्णांक, या फ्लोटिंग पॉइंट मान या पूर्णांक की n- आयामी सूचियों के रूप में 'व्याख्या' करने के लिए उपयोग कर सकते हैं। यह बाइट्स की अधिक प्रतियां बनाने के बिना बहुत ही कुशल बाइनरी फ़ाइल प्रारूप व्याख्याओं के लिए बनाता है।


1
और तुम क्या करते हो जब तुम्हें सबसेट की जरूरत होती है जो अनुक्रमण से अधिक समर्थन करता है ?!
बेसल शिशानी

2
@ बसेलसिहानी: ए का उपयोग न करें memoryview। आप पाठ के साथ काम कर रहे हैं, न कि बाइनरी डेटा।
मार्टिन पीटर्स

हां, पाठ से निपटना। तो हम मेमोरीव्यू का उपयोग नहीं करते हैं, क्या कोई विकल्प है?
बेसेल शिशानी

आप कौनसी समस्याएं हल करने की कोशिश कर रहे हैं? क्या वे सबस्ट्रिंग जिन्हें आपको परीक्षण करने की आवश्यकता है?
मार्टिन पीटर्स

6
@BaselShishani: मैमोरीव्यू स्लाइस करने से उस क्षेत्र को कवर करने वाला नया मेमोरीव्यू मिलता है।
मार्टिन पीटर्स

4

मुझे यह समझने में जहां गड़बड़ है वहां सादा बनाते हैं।

प्रश्नकर्ता, खुद की तरह, एक मेमोरीव्यू बनाने में सक्षम होने की उम्मीद करता है जो मौजूदा सरणी का एक टुकड़ा (उदाहरण के लिए एक बाइट्स या बायटियर) का चयन करता है। इसलिए हमें कुछ इस तरह की उम्मीद थी:

desired_slice_view = memoryview(existing_array, start_index, end_index)

काश, ऐसा कोई कंस्ट्रक्टर नहीं होता, और डॉक्स इसके बजाय क्या करना है, इसका कोई मतलब नहीं है।

कुंजी यह है कि आपको पहले एक मेमोरीव्यू बनाना होगा जो पूरे मौजूदा सरणी को कवर करता है। उस मेमोरीव्यू से आप एक दूसरा मेमोरीव्यू बना सकते हैं जो मौजूदा सरणी का एक टुकड़ा शामिल करता है, जैसे:

whole_view = memoryview(existing_array)
desired_slice_view = whole_view[10:20]

संक्षेप में, पहली पंक्ति का उद्देश्य केवल एक वस्तु प्रदान करना है जिसका स्लाइस कार्यान्वयन (डंडर-गेटिटेम) एक मेमोरीव्यू देता है।

यह अस्वाभाविक लग सकता है, लेकिन कोई इसे कुछ तरीकों से तर्कसंगत बना सकता है:

  1. हमारा वांछित आउटपुट एक मेमोरीव्यू है जो किसी चीज का एक टुकड़ा है। आम तौर पर हम उस पर स्लाइस ऑपरेटर [10:20] का उपयोग करके उसी प्रकार की वस्तु से एक कटा हुआ वस्तु प्राप्त करते हैं। इसलिए यह उम्मीद करने के लिए कुछ कारण है कि हमें एक मेमोरीव्यू से अपना वांछित_ प्राप्त करने की आवश्यकता है, और इसलिए पहला कदम पूरे अंतर्निहित सरणी का मेमोरीव्यू प्राप्त करना है।

  2. शुरू और अंत के तर्कों के साथ एक मेमोरीव्यू कंस्ट्रक्टर का अनुभवहीन अनुभव यह विचार करने में विफल रहता है कि स्लाइस विनिर्देश वास्तव में सामान्य स्लाइस ऑपरेटर की सभी अभिव्यक्तियों ([3 :: 2] या [: -4] आदि जैसी चीजों की आवश्यकता है)। उस वन-लाइनर कंस्ट्रक्टर में मौजूदा (और समझे गए) ऑपरेटर का उपयोग करने का कोई तरीका नहीं है। आप इसे मौजूदा_अरे दलील में संलग्न नहीं कर सकते हैं, क्योंकि यह मेमोरी व्यू कंस्ट्रक्टर को कुछ स्लाइस मापदंडों को बताने के बजाय उस सरणी का एक टुकड़ा बना देगा। और आप ऑपरेटर को तर्क के रूप में उपयोग नहीं कर सकते, क्योंकि यह एक ऑपरेटर है और मूल्य या वस्तु नहीं है।

जाहिर है, एक मेमोरीव्यू कंस्ट्रक्टर एक स्लाइस ऑब्जेक्ट ले सकता है:

desired_slice_view = memoryview(existing_array, slice(1, 5, 2) )

... लेकिन यह बहुत संतोषजनक नहीं है, क्योंकि उपयोगकर्ताओं को स्लाइस ऑब्जेक्ट के बारे में सीखना होगा और इसके निर्माता के मापदंडों का क्या मतलब होगा, जब वे स्लाइस ऑपरेटर के नोटेशन के संदर्भ में पहले से ही सोचते हैं।


4

यहाँ python3 कोड है।

#!/usr/bin/env python3

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

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

1

एंटीमनी द्वारा उत्कृष्ट उदाहरण। दरअसल, Python3 में, आप डेटा = 'x' * n को डेटा = बाइट्स (n) से बदल सकते हैं और नीचे दिए गए कथनों को प्रिंट करने के लिए कोष्ठक लगा सकते हैं:

import time
for n in (100000, 200000, 300000, 400000):
    #data = 'x'*n
    data = bytes(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
    data = bytes(n)
    start = time.time()
    b = memoryview(data)
    while b:
        b = b[1:]
    print('memoryview', n, time.time()-start)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.