[Tutor] is this use or abuse of __getitem__ ?

Albert-Jan Roskam fomcl at yahoo.com
Fri Sep 14 20:33:02 CEST 2012


> On 14/09/12 22:16, Albert-Jan Roskam wrote:

>>  Hi,
>> 
>>  I defined a __getitem__ special method in a class that reads a binary data
>>  file using a C library. The docstring should clarify the purpose of the
>> method. This works exactly as I intended it, however, the "key" 
> argument is
>>  actually used as an index (it also raises an IndexError when<key>  is
>> greater than the number of records in the file). Am I abusing the 
> __getitem__
>> method, or is this just a creative way of using it?
> 
> No, that's exactly what __getitem__ is for. It does double-duty for 
> key-lookup
> in mappings (dict[key]) and index-lookup in sequences (list[index]).
> 
> You can also support ranges of indexes by accepting a slice argument.

 

COOL! I was already wondering how this could be implemented. Dive into Python is pretty exhaustive wrt special methods,
but I don't think they mentioned using the slice class. Below is how I did it. Is it recommended to define the geitem() function inside the __getitem__() method? I was thinking I could also define a _getitem() private method. Hmmm, maybe getitem() is redefined over and over again the way I did it now?


    def __getitem__(self, key):
        """ This function reports the record of case number <key>.
        For example: firstRecord = SavReader(savFileName)[0] """
        def getitem(key):
            retcode1 = self.iomodule.SeekNextCase(self.fh, ctypes.c_long(int(key)))
            self.caseBuffer, self.caseBufferPtr = self.getCaseBuffer()
            retcode2 = self.iomodule.WholeCaseIn(self.fh, self.caseBufferPtr)
            record = struct.unpack(self.structFmt, self.caseBuffer.raw)
            if any([retcode1, retcode2]):
                raise RuntimeError, "Error retrieving record %d [%s, %s]" % \
                      (key, retcodes[retcode1], retcodes[retcode2])
            return record
        if isinstance(key, slice):
            records = [getitem(i) for i in range(*key.indices(self.nCases))]
            return records
        elif hasattr(key, "__int__"): # isinstance(key, (int, float)):
            if abs(key) > (self.nCases - 1):
                raise IndexError
            else:
                key = self.nCases + key if key < 0 else key
                record = getitem(key)
                return record
        else:
            raise TypeError   


> Another comment below:
> 
> 
>>  # Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit 
> (Intel)] on win32
>> 
>>       def __getitem__(self, key):
>>           """ This function reports the record of case 
> number<key>.
>>           For example: firstRecord = FileReader(fileName)[0] 
> """
>>           if not isinstance(key, (int, float)):
>>               raise TypeError
> 
> Floats? Do you actually have have case number (for example)
> 0.14285714285714285 ?
> 
> For this case, I think it is reasonable to insist on exactly an int,
> and nothing else (except possibly a slice object, to support for
> example obj[2:15]).
> 

I also accepted floats as a convenience. I had examples in mind like: record = data[1.0] . Kind of annoying when this raises a TypeError.
But in your example makes perfect sense to raise such an exception.

Eryksun, Steven: Thanks!!!

Albert-Jan


More information about the Tutor mailing list