python--operator overloading (1)

Source: Internet
Author: User

operator Overloading

Key concepts:

1. Operator overloading allows the class to intercept regular Python operations.
2. The class can overload all Python expression operators.
3. Classes can also overload the built-in operations such as printing, function invocation, and attribute point number operations.
4. Overloading makes the class instance behave like a built-in type.
5. Overloading is implemented by a class method of a special name.

Operator overloading simply means intercepting the built-in action in a class method--When an instance of the class appears in the built-in operation, Python automatically calls your method, and the return value of your method becomes the result of the corresponding operation.

=======================================================================

Constructors and expressions: __init__ and __sub__

See a simple overloaded example. The following number class provides a way to intercept the instance's constructor (__init__), and there is a method to catch the subtraction expression (__sub__). This particular method is a hook that can be bound to a built-in operation.

>>> class Number:def __init__ (self,start): Self.data = Startdef __sub__ (self,other): Return number (Self.data- Other) >>> X = number (5) >>> x.data5>>> Y = x-2>>> y.data3
=======================================================================

Common operator overloading methods

In a class, there is almost always an overloaded method of a special name for what you can do with built-in objects (for example, integers and lists). The following table lists some of the most common overloaded methods.

Method Overload Call
__init__ constructor function Object creation: X = Class (args)
__del__ Destructors X Object retract
__add__ operator + If there is no _iadd_,x+y,x+=y
__or__ operator | (bit or) If there is no _ior_,x| Y,x|=y
__repr__,__str__ printing, converting Print (x), repr (x), str (x)
__call__ Function call X (*args,**kargs)
__getattr__ Point number arithmetic x.undefined
__setattr__ Property Assignment Statements X.any = value
__delattr__ Property Delete Del X.any
__getattribute__ Property gets X.any
__getitem__ Index operations X[KEY],X[I:J], for loops and other iterators when not __iter__
__setitem__ Index assignment statement X[key] = value,x[i:j] = sequence
__delitem__ Index and Shard deletion Del X[key],del X[i:j]
__len__ Length Len (X), if there is no __bool__, the truth test
__bool__ Boolean test BOOL (X), true test
__LT__,__GT__, A specific comparison X < y,x > Y
__LE__,__GE__, X<=y,x >= Y
__eq__,__ne__ X = = y,x! = Y
__radd__ Right addition Other+x
__iadd__ field (Enhanced) addition X + = Y (or else __add__)
__iter__,__next__ Iterative environment i = iter (X), Next (i)
__contains__ Member Relationship Testing Item in X (any iteration)
__index__ Integer value Hex (x), Bin (x), Oct (x), o[x],o[x:]
__enter__,__exit__ Environment Manager With obj as Var:
__get__,__set__ Descriptor Properties x.attr,x.attr = Value,del x.attr
__new__ Create Create an object before __init__

The names of all overloaded methods have two underscore characters before and after them, so that the variable names defined in the same class are distinguished from each other.

Operator overloading methods are optional-if you do not write or inherit a method, your class does not support these operations directly, and attempting to use them throws an exception.

Most overloaded methods are used only in high-level programs that require an object's behavior to behave like a built-in type. However, __init__ constructors are often present in most classes.

Some examples of usage of operator overloading are described below.

=======================================================================

Indexes and Shards: __getitem__ and __setitem__

If defined in the class, the index operation for the instance automatically calls __getitem__, passes X as the first argument, and the index value within the square brackets to the second argument. For example, the following class returns the square of the index value.

--------------------------------------------------------------------------------------------------------------- ---

Intercept shards

Interestingly, in addition to indexes, __GETITEM__ is also called for Shard expressions. Formally, built-in types handle shards in the same way. For example, here is a shard that works on a built-in list, using the upper and lower bounds, and a stride. (Shard of knowledge can be recalled here)

>>> L = [5,6,7,8,9]>>> l[2:4][7, 8]>>> l[1:][6, 7, 8, 9]>>> l[:-1][5, 6, 7, 8]>> > l[::2][5, 7, 9]
In fact, the Shard boundary is bound to a Shard object (that is, the slice object) and is passed to the list implementation of the index. In fact, we can always manually pass a Shard object-The Shard syntax is primarily a syntactic sugar indexed with a Shard object:
>>> L[slice (2,4)][7, 8]>>> l[slice (1,none)][6, 7, 8, 9]>>> l[slice (none,-1)][5, 6, 7, 8]>& Gt;> L[slice (none,none,2)][5, 7, 9]
__getitem__ is called both for the base index and for the Shard. The class before us does not handle shards, but the following classes will handle the shards. When called against a base index, the parameter is an integer as before.

>>> class indexer:data = [5,6,7,8,9]def __getitem__ (Self,index):p rint (' GetItem: ', index) return self.data[ index]>>> X = Indexer () >>> x[0]getitem:05>>> x[1]getitem:16>>> X[-1]getitem: 19
However, when called on a shard, the method receives a Shard object that passes a new index expression directly to the nested list index:

>>> X[2:4]getitem:slice (2, 4, none) [7, 8]>>> X[1:]getitem:slice (1, none, none) [6, 7, 8, 9]>>> X[:-1]getitem:slice (None,-1, None) [5, 6, 7, 8]>>> X[::2]getitem:slice (None, none, 2) [5, 7, 9]
If used, the __setitem__ index assignment method intercepts the index and shard assignment similarly-it receives a Shard object for the latter, which may be passed to another index assignment in the same way:
def __setitem__ (self,index,value): ... self.data[index] = value
------------------------------------------------------------------------------------------------------------------
index iterations: __getitem__

This is a very useful technique. The For statement is performed from 0 to a larger index value, repeating the "index operation" of the sequence until an exception that exceeds the bounds is detected. Therefore, __getitem__ can also be a way of overloading iterations in Python. If this method is defined, the for loop invokes the class's __getitem__ method each time it loops, and continues to match with a higher offset value. As follows:
We know that any class that supports a for loop will also automatically support all of Python's iterative environments, such as member relationship test in, list parsing, built-in function map, list and Yuanzu value operations, and type construction methods, as shown in the following example:

>>> ' P ' in xtrue>>> [C for C in x][' s ', ' P ', ' a ', ' m ']>>> list (map (str.upper,x)) [' s ', ' P ', ' a ', ' m ']>>> a,b,c,d = x>>> a,c,d (' s ', ' a ', ' m ') >>> list (x), tuple (x), ' ". Join (x) ([' s ', ' P ', ' a ', ' m '], (' S ', ' P ', ' a ', ' m '), ' Spam ') >>> X<__main__.stepper object at 0x0376a6b0>
In practical applications, this technique can be used to create an object that provides a sequence interface, and adds logic to the type operation of the built-in sequence.
=======================================================================

Iterator objects: __iter__ and __next__

Although the __getitem__ technique described above is effective, it is only a fallback approach to iteration. The iterative environment in general Python will first try the __iter__ method and then try the __getitem__ method.

The iterative environment is implemented by calling the built-in function iter to try to find the __iter__ method, and this method should return an iterator object. If provided, Python repeats the next method of invoking the iterator object until the stopiteration exception occurs. If such a __iter__ method is not found, Python uses the __getitem__ mechanism instead, repeating the index with an offset as before, until the Indexerror exception is thrown.
------------------------------------------------------------------- -----------------------------------------------

User-defined Iterators

In the __iter__ mechanism, the class is implementing a user-defined iterator through the "iterator protocol" described earlier. The following example defines a user-defined iterator class to generate a square value.

In this example, the iterator object is the instance self, because the next method is part of the class.
Unlike __getitem__, __iter__ loops only once, not multiple times. Each time a new loop is created, you have to create a new iterator object, as follows:

>>> X = squares (1,5) >>> [n for N in X][1, 4, 9, +, 25]>>> [n for n ' x][]>>> [n for N in Squares (1,5)][1, 4, 9, 16, 25]
------------------------------------------------------------------------------------------------------------------

Objects with multiple iterators

As mentioned before, an iterator object can be defined as a separate class with its own state information to support multiple iterations of the same data. Look at the following example:

>>> s = ' Ace ' >>> for x in S:for y in S:print (x+y,end= ') AA ac AE CA cc CE ea EC ee
Here, the outer loop calls ITER to get the iterator from the string, and each nested loop does the same thing to get a separate iterator.

As previously mentioned, generator expressions, as well as built-in functions such as map and zip, all prove to be single-iteration objects; Instead, range built-in functions and other built-in types, such as lists, support multiple active iterators in separate locations.

When we use classes to write our own defined iterators, we decide to support a single or multiple active iterators. To achieve the effect of multiple iterators, __iter__ simply defines a new state object for the iterator, rather than returning self.

For example, the following defines an iterator class that, when iterated, skips the next element. Because the iterator object is recreated at each iteration, it is able to support multiple loops in the active state.
>>> class Skipiterator:def __init__ (self,wrapped): self.wrapped = Wrappedself.offset = 0def __next__ (self): if Self.offset >= Len (self.wrapped): Raise Stopiterationelse:item = Self.wrapped[self.offset]self.offset + = 2return Item>>> class Skipobject:def __init__ (self,wrapped): self.wrapped = Wrappeddef __iter__ (self): return Skipiterator (self.wrapped) >>> alpha = ' abcdef ' >>> skipper = Skipobject (alpha) >>> I = iter ( Skipper) >>> print (Next (i), next (i), next (i)) a C e>>> for x in Skipper:for y in skipper:print (x+y,end = " ) AA AC AE CA cc CE ea EC ee
This example works like nesting loops on built-in strings, because each loop has its own iterator object that records its own information, so the loop in each active state has its own position in the string.

=======================================================================

Memberships: __contains__, __iter__, and __getitem__

In the iterative realm, a class typically implements an in member-relational operator as an iteration, using the __iter__ method or the __getitem__ method. To support a more specific member relationship, the class might write a __contains__ method-which, when present, takes precedence over the __iter__ method, and the __iter__ method takes precedence over the __getitem__ method.

The __contains__ method should define a member relationship to apply a key to a map and a search for the sequence.

Consider the following class, which writes 3 methods and test membership relationships and various iterative environments that apply to an instance. When called, its method prints a trace message.

Class Iters:    def __init__ (self,value):    self.data = value    def __getitem__ (self,i):    print (' get[%s]: '% I,end = ")    return self.data[i]    def __iter__ (self):    print (' iter=> ', end= ')    self.ix = 0    return Self    def __next__:    print (' Next: ', end= ')    if Self.ix = = Len (self.data):    raise Stopiteration    item = Self.data[self.ix]    Self.ix + = 1    return item    def __contains__ (self,x):    print (' Contains: ', end= ')    return x in self.dataif __name__ = = ' __main__ ':    x = Iters ([1,2,3,4,5])    print (3 in x) C21/>for i in X: print (        i,end= ") print (    [i**2 for I in X])    print (list (map (bin,x)))    i = ITER (X)    while 1:        try:            print (Next (I), end = ' @ ')        except stopiteration:            break
When this script runs, its output is as follows:
Contains:trueiter=> next:1next:2next:3next:4next:5next:iter=> next:next:next:next:next:next:[1, 4, 9, 16, 25] iter=> next:next:next:next:next:next:[' 0b1 ', ' 0b10 ', ' 0b11 ', ' 0b100 ', ' 0b101 ']iter=> next:1 @ next:2 @ next:3 @ Next : 4 @ next:5 @ Next:
As you can see, the specific __contains__ intercepts the membership, and the generic __iter__ captures other iterations of the environment so that __next__ is called repeatedly, and __getitem__ is not called.

However, to see what happens to the output of the code after commenting out the __contains__ method-the membership is now routed to the generic __iter__:
iter=> next:next:next:trueiter=> next:1next:2next:3next:4next:5next:iter=> Next:next:next:next:next:next : [1, 4, 9, +, 25]iter=> next:next:next:next:next:next:[' 0b1 ', ' 0b10 ', ' 0b11 ', ' 0b100 ', ' 0b101 ']iter=> next:1 @ Next : 2 @ next:3 @ next:4 @ next:5 @ Next:
However, if both __contains__ and __iter__ are commented out, the output is as follows--the index __getitem__ workaround is called, and successive higher indexes are used for the membership and other iterative environments:
Get[0]:get[1]:get[2]:trueget[0]:1get[1]:2get[2]:3get[3]:4get[4]:5get[5]:get[0]:get[1]:get[2]:get[3]:get[4]:get [5]:[1, 4, 9, 25]get[0]:get[1]:get[2]:get[3]:get[4]:get[5]:[' 0b1 ', ' 0b10 ', ' 0b11 ', ' 0b100 ', ' 0b101 ']get[0]:1 @ get[1 ]:2 @ get[2]:3 @ get[3]:4 @ get[4]:5 @ GET[5]:
As we can see, the __getitem__ method is more generic.

python--operator overloading (1)

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.