Перегрузка операторов

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&plus;e18 .876j
-0490 -90. -.6545&plus;0J
-0x260 -32.54e100 3e&plus;26J
0x69 70.2-E12 4.53e-7j

A complex number consists of an ordered pair of real floating-point numbers denoted by x &plus; 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 (&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 &plus; tinylist) # Prints concatenated lists

This produces the following result −


abcd




Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *