Python magic method-custom sequence, python magic

Source: Internet
Author: User

Python magic method-custom sequence, python magic

The magic methods related to custom sequences allow the classes we have created to possess sequence features, so that they can be used like python's built-in sequences (dict, tuple, list, string, etc ).

To implement this function, follow the python-related protocol. The so-called protocol is some agreed content. For example, to iterate a class, you must implement two magic methods: __iter _ and next (_ new _ in python3.x __). _ Iter _ should return an object. This object must implement the next method. Generally, self is returned. The next method must return the next element each time it is called, and trigger the StopIteration exception when the element is exhausted.

In fact, the essence of the for Loop is to call the _ iter _ method of the object first, and then repeatedly call the next method of the object returned by the _ iter _ method, and stop when a StopIteration exception is triggered, this exception is handled internally, so we cannot see the exception throw.

This relationship is like an interface. If you review the previous magic methods, you can find that the result of many built-in functions is the return value of the corresponding magic method.

The following are related magic methods:

  • _ Len _ (self)

  • The length of the returned container.Variable and immutable containersIt is part of the Protocol.

  • _ Getitem _ (self, key)

  • Defines the Behavior Produced by Using self [key] when an item is accessed. This is alsoVariable container and immutable containerPart of the Protocol. If the key type is incorrect, A TypeError is generated. If the key does not have a proper value, a KeyError is generated.

  • _ Setitem _ (self, key, value)

  • Defines the Behavior Produced by Using self [key] = value when an entry is assigned a value. This is alsoVariable container Protocol. In addition, KeyError and TypeError are also generated in the corresponding circumstances.

  • _ Delitem _ (self, key)

  • Defines the action that occurs when an item is deleted. (For example, del self [key]). This isVariable containerPart of the Protocol. When using an invalid key, you must throw an appropriate exception.

  • _ Iter _ (self)

  • Returns a containerIteratorIn many cases, the iterator is returned, especially when the built-in iter () method is called and when the for x in container: method is used for loop. Iterators are their own objects. They must define the _ iter _ Method for returning self.

  • _ Reversed _ (self)

  • Implements the behavior when reversed () is called. ShouldReturnVersion after reverse sequence. It is implemented only when the sequence is ordered, such as list or tuples.

  • _ Contains _ (self, item)

  • Defines the behaviors generated when calling in and not in to test whether a member exists. This is not what the Protocol requires, but you can implement it as required. When _ contains _ is not defined, Python iterates this sequence and returns True when the desired value is found.

  • _ Missing _ (self, key)

  • In dictSubclass. It defines the behavior that occurs when a key that does not exist in the dictionary is accessed. (For example, if I have a dictionary d, when "george" is not the key in the dictionary, d ["george"] is used. _ missing _ ("george") will be called ).

The following is a sample code:

class Foo(object):    def __init__(self, key, value):        self.key = []        self.value = []        self.key.append(key)        self.value.append(value)    def __len__(self):        return len(self.key)    def __getitem__(self, item):        try:            __index = self.key.index(item)            return self.value[__index]        except ValueError:            raise KeyError('can not find the key')    def __setitem__(self, key, value):        if key not in self.key:            self.key.append(key)            self.value.append(value)        else:            __index = self.key.index(key)            self.value[__index] = value    def __delitem__(self, key):        try:            __index = self.key.index(key)            del self.key[__index]            del self.value[__index]        except ValueError:            raise KeyError('can not find the key')    def __str__(self):        result_list = []        for index in xrange(len(self.key)):            __key = self.key[index]            __value = self.value[index]            result = __key, __value            result_list.append(result)        return str(result_list)    def __iter__(self):        self.__index = 0        return self    def next(self):        if self.__index == len(self.key):            self.__index = 0            raise StopIteration()        else:            __key = self.key[self.__index]            __value = self.value[self.__index]            result = __key, __value            self.__index += 1            return result    def __reversed__(self):        __result = self.value[:]        __result.reverse()        return __result    def __contains__(self, item):        if item in self.value:            return True        else:            return False

 

Create a simulated dictionary class. This class maintains two lists internally. The key stores the key and the value stores the value. The two lists correspond one to one through the index, to simulate the dictionary.

First, let's look at the _ len _ method. According to the protocol, this method should return the length of the container, because this class requires the length of the two lists during design, therefore, in theory, the length of the list returned is the same. Here I select the length of the returned key.

Then the _ getitem _ method is used. This method calls a. _ getitem _ ('scolia ') when a ['scolia '). That is to say, this method defines the acquisition of elements. The idea here is to first find the index in the key list, then use the index to find the corresponding element in the value List, and then return it. Then, in order to further pretend to be a dictionary, I caught possible ValueError (this is an exception triggered when item is not in the key list) and disguised it as a KeyError when the dictionary cannot find the key.

Theoretically, as long as the above two methods are implemented, an immutable container can be obtained. But I am not satisfied, so I will continue to expand.

The _ setitem _ (self, key, value) method defines the behavior of an operation such as a ['scolia '] = 'good'. At this time,. _ setitem _ ('scolia ', 'good') because it is a binding method, self is automatically passed and we don't need to worry about it. Here, I also simulate the overwriting feature when assigning values to the same key in the dictionary. This method does not need to return any value, so the return statement is omitted.

The _ delitem _ (self, key) method defines the actions of del a ['scolia '] And the 'scolia' in it is passed as a parameter. An exception conversion is also performed here.

Only the above four methods can be used as variable containers.

The following _ str _ corresponds to the str () function, which will be further discussed in the class representation. This is added only when the print statement looks good, the print statement calls the str () function by default.

The _ iter _ and next methods are discussed at the beginning, so that they can be added for iterative operations.

The _ reversed _ (self) method returns an inverted copy, which shows the order. Of course, whether or not you need to check the individual.

_ Contains _ implements member judgment. Here we are more concerned with the data in the value List, So we determine the value list. This method requires a Boolean value.

The test is as follows:

a = Foo('scolia', 'good')a[123] = 321a[456] = 654a[789] = 987print adel a[789]print afor x, y in a:    print x, yprint reversed(a)print 123 in aprint 321 in a

 

  • _ Missing _ (self, key)

class Boo(dict):    def __new__(cls, *args, **kwargs):        return super(Boo, cls).__new__(cls)    def __missing__(self, key):        return 'The key(%s) can not be find.'% key

 

Test:

b = Boo()b['scolia'] = 'good'print b['scolia']print b['123']

 

 

Of course, you can also trigger an exception when the key is not found. The specific implementation depends on your individual needs.

 

Slice operation implementation:

  Curious people may also find that there is no typical sequence operation above: Slice implementation.

In fact, the _ getitem _ (self, item) magic method is used for slicing. Let's see what the item parameter will get when we use slicing:

class Foo(object):    def __init__(self, x):        self.x = x    def __getitem__(self, item):        return itema = Foo(123)print a[1:2]

An object similar to a function is obtained. Its type is:

This type is created by the slice function. If you are interested, you can use the help function for in-depth research.

This function can be created using either slice (stop) or slice (start, stop [, step, we can use the start, stop, and step attributes to obtain the corresponding values.

To make the preceding example support slicing, you only need to modify the code at _ getitem _ (self, item:

    def __getitem__(self, item):        if isinstance(item, slice):                return self.value[item.start:item.stop:item.step]        else:            try:                __index = self.key.index(item)                return self.value[__index]            except ValueError:                raise KeyError('can not find the key')

 

Output:

a = Foo('scolia', 'good')a[123] = 321a[456] = 654a[789] = 987print a[:]print a[2:]print a[:3]print a[1:5]print a[1:10:2]print a[-4:-2]

The system runs well and supports the slicing function.

 

Welcome to your discussion.

Reference: click here

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.