__Getitem__ में स्लाइसिंग लागू करना


112

मैं एक वर्ग के लिए स्लाइस कार्यक्षमता को लागू करने की कोशिश कर रहा हूं जो मैं कर रहा हूं जो एक वेक्टर प्रतिनिधित्व बनाता है।

मेरे पास अब तक यह कोड है, जो मुझे लगता है कि स्लाइस को ठीक से लागू करेगा, लेकिन जब भी मैं एक कॉल करता हूं जैसे v[4]v जहां एक वेक्टर अजगर है, पर्याप्त पैरामीटर नहीं होने के बारे में एक त्रुटि देता है। इसलिए मैं यह पता लगाने की कोशिश कर रहा हूं कि getitemसादे अनुक्रमित और स्लाइसिंग दोनों को संभालने के लिए मेरी कक्षा में विशेष विधि को कैसे परिभाषित किया जाए ।

def __getitem__(self, start, stop, step):
    index = start
    if stop == None:
        end = start + 1
    else:
        end = stop
    if step == None:
        stride = 1
    else:
        stride = step
    return self.__data[index:end:stride]

जवाबों:


118

__getitem__()विधि एक प्राप्त होगा sliceजब वस्तु कटा हुआ है वस्तु। सीधे शब्दों में देखो start, stopऔर stepके सदस्यों sliceआदेश टुकड़ा के लिए घटकों प्राप्त करने के लिए वस्तु।

>>> class C(object):
...   def __getitem__(self, val):
...     print val
... 
>>> c = C()
>>> c[3]
3
>>> c[3:4]
slice(3, 4, None)
>>> c[3:4:-2]
slice(3, 4, -2)
>>> c[():1j:'a']
slice((), 1j, 'a')

10
नोट: सूची या टपल जैसे अंतर्निहित प्रकारों के विस्तार के लिए आपको __getslice__अजगर 2.X संस्करणों के लिए कार्यान्वयन करना होगा । देख docs.python.org/2/reference/datamodel.html#object.__getslice__
gregorySalvan

@gregorySalvan: क्या उस सेगमेंट के नीचे उस अनुकूलता का उदाहरण नहीं है?
एरिक

3
@ एरिक: नहीं, क्योंकि दूसरे कॉलोनी की उपस्थिति बाईपास है __get/set/delslice__। हालांकि यह बहुत सूक्ष्म है।
user2357112

@ user2357112: वाह, पूरी तरह से उस दूसरे कोलोन को याद किया - धन्यवाद!
एरिक

@alancalvitti IIRC, कि पायथन 2 में नई शैली की कक्षाएं बनाने के लिए है
wjandrea

64

मेरे पास एक "सिंथेटिक" सूची है (एक ऐसा स्थान जहां डेटा आपसे बड़ा है जिसे आप मेमोरी में बनाना चाहते हैं) और मेरा __getitem__ऐसा दिखता है:

def __getitem__( self, key ) :
    if isinstance( key, slice ) :
        #Get the start, stop, and step from the slice
        return [self[ii] for ii in xrange(*key.indices(len(self)))]
    elif isinstance( key, int ) :
        if key < 0 : #Handle negative indices
            key += len( self )
        if key < 0 or key >= len( self ) :
            raise IndexError, "The index (%d) is out of range."%key
        return self.getData(key) #Get the data from elsewhere
    else:
        raise TypeError, "Invalid argument type."

टुकड़ा एक ही प्रकार वापस नहीं करता है, जो कि एक नहीं-नहीं है, लेकिन यह मेरे लिए काम करता है।


1
नहीं होना चाहिए अगर कुंजी> = लेन (स्व) यदि कुंजी <0 या कुंजी> = लेन (स्व) हो तो? क्या होगा यदि एक कुंजी <-लेन (स्व) पास हो?
एस्टन

20

प्लेन इंडेक्स और स्लाइसिंग दोनों को संभालने के लिए गेटिटम क्लास को कैसे परिभाषित करें?

जब आप सबस्क्रिप्ट नोटेशन में एक कोलन का उपयोग करते हैं, तो स्लाइस ऑब्जेक्ट्स अपने आप बन जाते हैं - और जो पास हो जाता है __getitem__isinstanceयह जांचने के लिए उपयोग करें कि क्या आपके पास कोई स्लाइस ऑब्जेक्ट है:

from __future__ import print_function

class Sliceable(object):
    def __getitem__(self, subscript):
        if isinstance(subscript, slice):
            # do your handling for a slice object:
            print(subscript.start, subscript.stop, subscript.step)
        else:
            # Do your handling for a plain index
            print(subscript)

मान लें कि हम एक रेंज ऑब्जेक्ट का उपयोग कर रहे थे, लेकिन हम चाहते हैं कि स्लाइस नई रेंज ऑब्जेक्ट्स के बजाय सूचियों को वापस लौटाए (जैसा कि यह करता है):

>>> range(1,100, 4)[::-1]
range(97, -3, -4)

हम आंतरिक सीमाओं के कारण सीमा को उप-वर्ग नहीं कर सकते, लेकिन हम इसे सौंप सकते हैं:

class Range:
    """like builtin range, but when sliced gives a list"""
    __slots__ = "_range"
    def __init__(self, *args):
        self._range = range(*args) # takes no keyword arguments.
    def __getattr__(self, name):
        return getattr(self._range, name)
    def __getitem__(self, subscript):
        result = self._range.__getitem__(subscript)
        if isinstance(subscript, slice):
            return list(result)
        else:
            return result

r = Range(100)

हमारे पास पूरी तरह से बदली जाने वाली रेंज ऑब्जेक्ट नहीं है, लेकिन यह काफी करीब है:

>>> r[1:3]
[1, 2]
>>> r[1]
1
>>> 2 in r
True
>>> r.count(3)
1

स्लाइस नोटेशन को बेहतर ढंग से समझने के लिए, यहां स्लीसेबल का उपयोग उदाहरण दिया गया है:

>>> sliceme = Sliceable()
>>> sliceme[1]
1
>>> sliceme[2]
2
>>> sliceme[:]
None None None
>>> sliceme[1:]
1 None None
>>> sliceme[1:2]
1 2 None
>>> sliceme[1:2:3]
1 2 3
>>> sliceme[:2:3]
None 2 3
>>> sliceme[::3]
None None 3
>>> sliceme[::]
None None None
>>> sliceme[:]
None None None

अजगर 2, जागरूक रहें:

पायथन 2 में, एक पदावनत विधि है जिसे आपको कुछ अंतर्निहित प्रकारों को उप-वर्ग करते समय ओवरराइड करने की आवश्यकता हो सकती है।

से डेटामॉडल दस्तावेज़ :

object.__getslice__(self, i, j)

संस्करण 2.0 के बाद से पदावनत:__getitem__() विधि के मापदंडों के रूप में स्लाइस ऑब्जेक्ट का समर्थन करें । (हालांकि, सीपीथॉन में निर्मित प्रकार वर्तमान में अभी भी लागू होते हैं __getslice__()। इसलिए, आपको इसे लागू करने से पहले व्युत्पन्न वर्गों में ओवरराइड करना होगा।)

यह पायथन 3 में चला गया है।


7

हारून के जवाब का विस्तार करने के लिए, जैसी चीजों के लिए numpy, आप यह देखने के लिए कि क्या givenहै tuple:

class Sliceable(object):
    def __getitem__(self, given):
        if isinstance(given, slice):
            # do your handling for a slice object:
            print("slice", given.start, given.stop, given.step)
        elif isinstance(given, tuple):
            print("multidim", given)
        else:
            # Do your handling for a plain index
            print("plain", given)

sliceme = Sliceable()
sliceme[1]
sliceme[::]
sliceme[1:, ::2]

`` `

आउटपुट:

('plain', 1)
('slice', None, None, None)
('multidim', (slice(1, None, None), slice(None, None, 2)))

एक छोटी सी अनुवर्ती के रूप में, यहाँ एक उदाहरण है इस रोजगार एक साथ MATLAB अनुक्रमण और NumPy अनुक्रमण (जो वर्तमान में MATLAB R2016b में समर्थित नहीं है) के बीच मैप करने के लिए, का उपयोग का उदाहरण इसके बारे में।
एरिक कजिनो

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.