[2018-12-31] [2018-12-31] [2018-12-31] [2018-12-31] [2018-12-31] [2018-12-31] [2018-12-31] After the merger, some serious errors have been corrected (such as the section of custom sequence slicing), and a lot of changes have been made to the structure of the text and chapter cohesion. The original series of single will not be deleted, after all, also have a separate role. Please read the improved Version of Advanced Python: a comprehensive slice of advanced features! Mp.weixin.qq.com/s/IRAjR-KHZ…

Slicing is one of the most fascinating, powerful, and Amazing language features in Python (almost none), and in Advanced Python: Slicing Myths and Advanced Uses, I covered the basics, advanced uses, and some of the pitfalls of slicing. These are all based on native sequence types (strings, lists, tuples……) So, can we define our own sequence type and have it support slicing syntax? Further, can we customize other objects (such as dictionaries) to support slicing?

1, magic method:__getitem__()

It is not difficult to make custom objects support slicing syntax, just implement the magic method __getitem__() when defining the class. So, here’s how to do it.

Syntax: Object.__getitem__ (self, key)

Official document meaning: Called to implement evaluation of self[key]. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the __getitem__() method. If key is of an inappropriate type, TypeError may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. For mapping types, if key is missing (not in the container), KeyError should be raised.

The __getitem__() method returns the value of the key argument, which can be an integer value and a slice object, and supports negative indexes. If the key is of either type, TypeError is thrown; If the index is out of bounds, an IndexError is thrown; If a mapping type is defined, a KeyError is thrown if the key argument is not the key value of its object.

2, custom sequence to achieve the slicing function

Next, we define a simple MyList and add slicing to it. (PS: for demonstration only, the completeness of other functions is not guaranteed).

class MyList(): def __init__(self): self.data = [] def append(self, item): self.data.append(item) def __getitem__(self, key): print("key is : "+ STR (key)) return self.data[key] l = MyList() l.append("My") l.append("name") l.append("is") l.append("Python cat ") Print (l[:2]) print(l['hi']) print(l[:2]) print(l['hi']) slice(None, 2, None) ['My', 'name'] key is : hi Traceback (most recent call last): ... TypeError: list indices must be integers or slices, not strCopy the code

From the output, the custom MyList supports both lookups by index and slicing operations, which is exactly what we want.

In particular, the __getitem__() method in this example performs different functions (fetching index bits or slicing values) depending on the parameter type and handles exceptions properly, so we don’t need to write verbose processing logic. There are a lot of learning materials on the Internet that are completely misleading, teaching you to distinguish between different types of parameters, and then writing a whole block of code for indexing and slicing syntax, which is just gilding the lily. The following is a typical example of an error:

#### def __getitem__(self, index): CLS = type(self) if isinstance(index, slice): Return CLS (self._components[index]) elif isinstance(index, numbers.Integral): Return self._components[index] else: self._components[index] msg = "{cls.__name__} indices must be integers" raise TypeError(msg.format(cls=cls))Copy the code

3. Customize the dictionary to achieve the slicing function

Slicing is a property of sequence types, so in the above example, we do not need to write the implementation logic for slicing. However, for other custom objects that are not sequence types, you have to implement the slicing logic yourself. Take the custom dictionary as an example (PS: for demonstration only, the completeness of other features is not guaranteed) :

class MyDict(): def __init__(self): self.data = {} def __len__(self): return len(self.data) def append(self, item): self.data[len(self)] = item def __getitem__(self, key): if isinstance(key, int): return self.data[key] if isinstance(key, slice): slicedkeys = list(self.data.keys())[key] return {k: self.data[k] for k in slicedkeys} else: Raise TypeError d = MyDict() d.append("My") d.append("name") d.append("is") d.append("Python cat ") print(d[2]) print(d[:2]) raise TypeError d = MyDict() d.append("My") d.append("name") d.append("is") d.append("Python cat ") print(d[:2]) Print (d / 2-4: -) print (d) [' hi '] # # # output: is {0: 'My', 1: 'name'} {0: 'My', 1: 'name'} Traceback (most recent call last): ... TypeErrorCopy the code

The key point of the above example is to take out the dictionary keys and slice the list of key values. The beauty is that, without worrying about index crossing and negative index, the dictionary slice is converted into the dictionary key value slice, finally achieving the purpose.

4, summary

A final summary: This article introduces the __getitem__() magic method and is used to implement slicing for custom objects (for example, list and dictionary types). Hopefully it will help you.

Reference reading:

Advanced Python: Pitfalls and advanced uses of slicing

Getitem usage: t.cn/EbzoZyp

Python slice assignment source analysis: t.cn/EbzSaoZ