Перегрузка операторов
Содержание:
- Python Assignment Operators
- Assigning Values to Variables
- Destroying Objects (Garbage Collection)
- Python Operator Overloading
- 9.9. Order of evaluation¶
- Python Numbers
- Optimisation of ‘not’
- Bit fields, e.g. for communication protocols
- Python Comparison Operators
- Class Inheritance
- Calling a Function
- Operations on Integers of Unknown Magnitude
- Python Lists
Python Assignment Operators
Assume variable a holds the value 10 and variable b holds the value 20, then −
Operator | Description | Example |
---|---|---|
= | Assigns values from right side operands to left side operand | c = a + b assigns value of a + b into c |
+= Add AND | It adds right operand to the left operand and assign the result to left operand | c += a is equivalent to c = c + a |
-= Subtract AND | It subtracts right operand from the left operand and assign the result to left operand | c -= a is equivalent to c = c — a |
*= Multiply AND | It multiplies right operand with the left operand and assign the result to left operand | c *= a is equivalent to c = c * a |
/= Divide AND | It divides left operand with the right operand and assign the result to left operand | c /= a is equivalent to c = c / ac /= a is equivalent to c = c / a |
%= Modulus AND | It takes modulus using two operands and assign the result to left operand | c %= a is equivalent to c = c % a |
**= Exponent AND | Performs exponential (power) calculation on operators and assign value to the left operand | c **= a is equivalent to c = c ** a |
//= Floor Division | It performs floor division on operators and assign value to the left operand | c //= a is equivalent to c = c // a |
Assigning Values to Variables
Python variables do not need explicit declaration to reserve memory space. The declaration happens automatically when you assign a value to a variable. The equal sign (=) is used to assign values to variables.
The operand to the left of the = operator is the name of the variable and the operand to the right of the = operator is the value stored in the variable. For example −
#!/usr/bin/python3 counter = 100 # An integer assignment miles = 1000.0 # A floating point name = "John" # A string print (counter) print (miles) print (name)
Here, 100, 1000.0 and «John» are the values assigned to counter, miles, and name variables, respectively. This produces the following result −
100 1000.0 John
Destroying Objects (Garbage Collection)
Python deletes unneeded objects (built-in types or class instances) automatically to free the memory space. The process by which Python periodically reclaims blocks of memory that no longer are in use is termed Garbage Collection.
Python’s garbage collector runs during program execution and is triggered when an object’s reference count reaches zero. An object’s reference count changes as the number of aliases that point to it changes.
An object’s reference count increases when it is assigned a new name or placed in a container (list, tuple, or dictionary). The object’s reference count decreases when it’s deleted with del, its reference is reassigned, or its reference goes out of scope. When an object’s reference count reaches zero, Python collects it automatically.
a = 40 # Create object <40> b = a # Increase ref. count of <40> c = # Increase ref. count of <40> del a # Decrease ref. count of <40> b = 100 # Decrease ref. count of <40> c = -1 # Decrease ref. count of <40>
You normally will not notice when the garbage collector destroys an orphaned instance and reclaims its space. But a class can implement the special method __del__(), called a destructor, that is invoked when the instance is about to be destroyed. This method might be used to clean up any non memory resources used by an instance.
Example
This __del__() destructor prints the class name of an instance that is about to be destroyed −
#!/usr/bin/python class Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed" pt1 = Point() pt2 = pt1 pt3 = pt1 print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts del pt1 del pt2 del pt3
When the above code is executed, it produces following result −
3083401324 3083401324 3083401324 Point destroyed
Note − Ideally, you should define your classes in separate file, then you should import them in your main program file using import statement.
Python Operator Overloading
Python supports operator overloading. There are specific methods to overload an operator for an object.
Let’s see what happens when an operator is not supported for a class.
class Data: id = 0 def __init__(self, i): self.id = i d1 = Data(10) d2 = Data(20) d3 = d1 + d2 print(d3.id)
Output:
Traceback (most recent call last): File "/Users/pankaj/Documents/PycharmProjects/PythonTutorialPro/hello-world/operators_examples.py", line 9, in <module> d3 = d1 + d2 TypeError: unsupported operand type(s) for +: 'Data' and 'Data'
If we have to support + operator for Data class, we have to define __add__() method for it. Let’s see the updated code and the output.
class Data: id = 0 def __init__(self, i): self.id = i def __add__(self, other): return Data(self.id + other.id) d1 = Data(10) d2 = Data(20) d3 = d1 + d2 print(d3.id)
Output: 30
Below table provide the methods to override to overload an operator in Python.
Operator | Description | Method |
---|---|---|
+ | Addition | __add__(self, other) |
– | Subtraction | __sub__(self, other) |
* | Multiplication | __mul__(self, other) |
True Division | __truediv__(self, other) | |
// | Floor Division | __floordiv__(self, other) |
% | Remainder | __mod__(self, other) |
** | Power | __pow__(self, other) |
& | Bitwise AND | __and__(self, other) |
| | Bitwise OR | __or__(self, other) |
^ | Bitwise XOR | __xor__(self, other) |
> | Greater than | __gt__(self, other) |
>= | Greater than or equal to | __ge__(self, other) |
< | Less than | __lt__(self, other) |
<= | Less than or equal to | __le__(self, other) |
== | Equal to | __eq__(self, other) |
!= | Not equal to | __ne__(self, other) |
9.9. Order of evaluation¶
The order of evaluation from highest to order is as shown in this table:
operators | descriptions |
---|---|
(), [], {}, ‘’ | tuple, list, dictionnary, string |
x.attr, x[], x, f() | attribute, index, slide, function call |
+x, -x, ~x | unary negation, bitwise invert |
** | exponent |
*, /, % | multiplication, division, modulo |
+, — | addition, substraction |
<<, >> | bitwise shifts |
& | bitwise and |
^ | bitwise xor |
bitwise or | |
<, <=, >=, > | comparison operators |
==, !=, is, is not, in, | comparison operators (continue) |
not in | comparison operators (continue) |
not | boolean NOT |
and | boolean AND |
or | boolean OR |
lambda | lamnda expression |
Here is the precedence table for the boolean operators only
Python Numbers
Number data types store numeric values. Number objects are created when you assign a value to them. For example −
var1 = 1 var2 = 10
You can also delete the reference to a number object by using the del statement. The syntax of the del statement is −
del var1]]]
You can delete a single object or multiple objects by using the del statement.
For example −
del var del var_a, var_b
Python supports three different numerical types −
- int (signed integers)
- float (floating point real values)
- complex (complex numbers)
All integers in Python3 are represented as long integers. Hence, there is no separate number type as long.
Examples
Here are some examples of numbers −
int | float | complex |
---|---|---|
10 | 0.0 | 3.14j |
100 | 15.20 | 45.j |
-786 | -21.9 | 9.322e-36j |
080 | 32.3+e18 | .876j |
-0490 | -90. | -.6545+0J |
-0x260 | -32.54e100 | 3e+26J |
0x69 | 70.2-E12 | 4.53e-7j |
A complex number consists of an ordered pair of real floating-point numbers denoted by x + yj, where x and y are real numbers and j is the imaginary unit.
Optimisation of ‘not’
Recent versions of Python implement a simple optimisation in
which branching on a negated boolean expression is implemented
by reversing the sense of the branch, saving a UNARY_NOT opcode.
Taking a strict view, this optimisation should no longer be
performed, because the ‘not’ operator may be overridden to produce
quite different results from usual. However, in typical use cases,
it is not envisaged that expressions involving customised boolean
operations will be used for branching — it is much more likely
that the result will be used in some other way.
Therefore, it would probably do little harm to specify that the
compiler is allowed to use the laws of boolean algebra to
simplify any expression that appears directly in a boolean
context. If this is inconvenient, the result can always be assigned
to a temporary name first.
Bit fields, e.g. for communication protocols
If you need to interpret individual bits in some data, e.g. a byte stream in a communications protocol, you can use the ctypes module.
import ctypes c_uint8 = ctypes.c_uint8 class Flags_bits( ctypes.LittleEndianStructure ): _fields_ = [ ("logout", c_uint8, 1 ), # asByte & 1 ("userswitch", c_uint8, 1 ), # asByte & 2 ("suspend", c_uint8, 1 ), # asByte & 4 ("idle", c_uint8, 1 ), # asByte & 8 class Flags( ctypes.Union ): _anonymous_ = ("bit",) _fields_ = [ ("bit", Flags_bits ), ("asByte", c_uint8 ) flags = Flags() flags.asByte = 0x2 # ->0010 print( "logout: %i" % flags.bit.logout ) # `bit` is defined as anonymous field, so its fields can also be accessed directly: print( "logout: %i" % flags.logout ) print( "userswitch: %i" % flags.userswitch ) print( "suspend : %i" % flags.suspend ) print( "idle : %i" % flags.idle )
>>> logout: logout: userswitch: 1 suspend : idle :
Python Comparison Operators
These operators compare the values on either side of them and decide the relation among them. They are also called Relational operators.
Assume variable a holds the value 10 and variable b holds the value 20, then −
Operator | Description | Example |
---|---|---|
== | If the values of two operands are equal, then the condition becomes true. | (a == b) is not true. |
!= | If values of two operands are not equal, then condition becomes true. | (a!= b) is true. |
> | If the value of left operand is greater than the value of right operand, then condition becomes true. | (a > b) is not true. |
< | If the value of left operand is less than the value of right operand, then condition becomes true. | (a < b) is true. |
>= | If the value of left operand is greater than or equal to the value of right operand, then condition becomes true. | (a >= b) is not true. |
<= | If the value of left operand is less than or equal to the value of right operand, then condition becomes true. | (a <= b) is true. |
Class Inheritance
Instead of starting from scratch, you can create a class by deriving it from a preexisting class by listing the parent class in parentheses after the new class name.
The child class inherits the attributes of its parent class, and you can use those attributes as if they were defined in the child class. A child class can also override data members and methods from the parent.
Syntax
Derived classes are declared much like their parent class; however, a list of base classes to inherit from is given after the class name −
class SubClassName (ParentClass1): 'Optional class documentation string' class_suite
Example
#!/usr/bin/python class Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor" def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttr class Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method' c = Child() # instance of child c.childMethod() # child calls its method c.parentMethod() # calls parent's method c.setAttr(200) # again call parent's method c.getAttr() # again call parent's method
When the above code is executed, it produces the following result −
Calling child constructor Calling child method Calling parent method Parent attribute : 200
Similar way, you can drive a class from multiple parent classes as follows −
class A: # define your class A ..... class B: # define your class B ..... class C(A, B): # subclass of A and B .....
You can use issubclass() or isinstance() functions to check a relationships of two classes and instances.
-
The issubclass(sub, sup) boolean function returns true if the given subclass sub is indeed a subclass of the superclass sup.
-
The isinstance(obj, Class) boolean function returns true if obj is an instance of class Class or is an instance of a subclass of Class
Calling a Function
Defining a function only gives it a name, specifies the parameters that are to be included in the function and structures the blocks of code.
Once the basic structure of a function is finalized, you can execute it by calling it from another function or directly from the Python prompt. Following is the example to call printme() function −
#!/usr/bin/python # Function definition is here def printme( str ): "This prints a passed string into this function" print str return; # Now you can call printme function printme("I'm first call to user defined function!") printme("Again second call to the same function")
When the above code is executed, it produces the following result −
I'm first call to user defined function! Again second call to the same function
Operations on Integers of Unknown Magnitude
Some procedures don’t need to know the magnitude of an integer to give meaningful results.
bitCount()
The procedure and the information below were found in «Bit Twiddling Hacks»(ref.1)
— — — — — — — — — — — — — — — — — — — — — — — —
Counting bits set, Brian Kernighan’s way*
unsigned int v; // count the number of bits set in v unsigned int c; // c accumulates the total bits set in v for (c = ; v; c++) { v &= v - 1; } //clear the least significant bit set
This method goes through as many iterations as there are set bits. So if we have a 32-bit word with only the high bit set, then it will only go once through the loop.
* The C Programming Language 2nd Ed., Kernighan & Ritchie, 1988.
Don Knuth pointed out that this method was published by Peter Wegner in CACM 3 (1960), 322. Also discovered independently by Derrick Lehmer and published in 1964 in a book edited by Beckenbach.
— — — — — — — — — — — — — — — — — — — — — — — —
Kernighan and Knuth, potent endorsements!
This works because each subtraction «borrows» from the lowest 1-bit. For example:
# loop pass 1 loop pass 2 # 101000 101000 100000 100000 # - #!python & 100111 - #!python & 011111 # = 100111 = 100000 = 011111 = 0
It is an excellent technique for Python, since the size of the integer need not be determined beforehand.
def bitCount(int_type): count = while(int_type): int_type &= int_type - 1 count += 1 return(count)
parityOf()
From «Bit Twiddling Hacks»
Code almost identical to bitCount(), above, calculates the parity of an integer, returning 0 if there are an even number of set bits, and -1 if there are an odd number. In fact, counting the bits and checking whether the result is odd with bitcount & 1 is about the same speed as the parity function.
def parityOf(int_type): parity = while (int_type): parity = ~parity int_type = int_type & (int_type - 1) return(parity)
lowestSet()
To determine the bit number of the lowest bit set in an integer, in twos-complement notation i & -i zeroes all but the lowest set bit. The bitLen() proceedure then determines its position. Obviously, negative numbers return the same result as their opposite. In this version, an input of 0 returns -1, in effect an error condition.
For example: # 00111000 # 56 # 11001000 # twos complement, -56 # &= 00001000
def lowestSet(int_type): low = (int_type & -int_type) lowBit = -1 while (low): low >>= 1 lowBit += 1 return(lowBit)
Single bits
The usual single-bit operations will work on any Python integer. It is up to the programmer to be sure that the value of ‘offset’ makes sense in the context of the program.
# testBit() returns a nonzero result, 2**offset, if the bit at 'offset' is one. def testBit(int_type, offset): mask = 1 << offset return(int_type & mask) # setBit() returns an integer with the bit at 'offset' set to 1. def setBit(int_type, offset): mask = 1 << offset return(int_type | mask) # clearBit() returns an integer with the bit at 'offset' cleared. def clearBit(int_type, offset): mask = ~(1 << offset) return(int_type & mask) # toggleBit() returns an integer with the bit at 'offset' inverted, 0 -> 1 and 1 -> 0. def toggleBit(int_type, offset): mask = 1 << offset return(int_type ^ mask)
Python Lists
Lists are the most versatile of Python’s compound data types. A list contains items separated by commas and enclosed within square brackets ([]). To some extent, lists are similar to arrays in C. One of the differences between them is that all the items belonging to a list can be of different data type.
The values stored in a list can be accessed using the slice operator ( and ) with indexes starting at 0 in the beginning of the list and working their way to end -1. The plus (+) sign is the list concatenation operator, and the asterisk (*) is the repetition operator. For example −
#!/usr/bin/python3 list = tinylist = print (list) # Prints complete list print (list) # Prints first element of the list print (list) # Prints elements starting from 2nd till 3rd print (list) # Prints elements starting from 3rd element print (tinylist * 2) # Prints list two times print (list + tinylist) # Prints concatenated lists
This produces the following result −
abcd