python加法运算符重载_Python面向对象之运算符重载

运算符重载只是意味着在类方法中拦截内置的操作,也就是说当类的实例出现在内置操作中,Python自动调用我们的方法,并且我们的方法的返回值变成了相应操作的结果。

关于重载的关键知识点:

运算符重载让类拦截常规的Python运算

类可重载所有Python表达式运算符

类也可重载打印、函数调用、属性点号运算等内置运算

重载使类实例的行为像内置类型

重载是通过提供特殊名称的类方法来实现的

换句话说,当类中提供了某个特殊名称的方法,在该类的实例出现在它们相关的表达式时,Python自动调用它们。

当然有些运算符是不能重载:赋值运算符、逻辑运算符。在C++中,赋值运算符与逻辑运算符是可以重载的。

运算符重载

接下来我们看一个实数的例子,我们都知道,实数包含实部与虚部,这个例子主要实现两个实数的相加。代码如下:

class Complex:

def __init__(self, real, imag):

self.real = real

self.imag = imag

def add(self, other):

return Complex(self.real+other.real, self.imag+other.imag)

def sub(self, other):

return Complex(self.real-other.read, self.imag-other.imag)

c1 = Complex(1, 1)

c2 = Complex(2, 3)

c3 = c1.add(c2)

c3.real

3

c3.imag

4

c1 + c2 # 此处出问题了,试图让两个对象相加

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

TypeError Traceback (most recent call last)

in ()

----> 1 c1 + c2

TypeError: unsupported operand type(s) for +: 'Complex' and 'Complex'

对上面的程序稍作修改,使其增加减法运算符的重载:

class Complex:

def __init__(self, real, imag):

self.real = read

self.imag = imag

def __add__(self, other):

return Complex(self.real + other.real, self.imag + other.imag)

def __sub__(self, other):

return Complex(self.real - other.read, self.imag - other.imag)

c1 = Complex(1, 1)

c2 = Complex(2, 3)

c4 = c1 + c2

c4.real

c4.imag

方法名前后带双下划线的方法,称之为专有方法或者魔术方法。带双下划线的方法是有特殊含义的。

这时我们也不妨看看C++中是如何实现运算符重载的吧,代码如下:

#include

using namespace std;

class Complex {

private:

int real;

int imag;

public:

Complex(int real=0, int imag=0)

{

this->real = real;

this->imag = imag;

}

int get_real()

{

return this->real;

}

int get_imag()

{

return this->imag;

}

Complex operator+(const Complex& c)

{

Complex complex;

complex.real = this->real + c.real;

complex.imag = this->imag + c.imag;

return complex;

}

};

int main(int argc, char *argv[])

{

Complex c1(1, 1);

Complex c2(2, 3);

Complex c3;

c3 = c1 + c2;

cout << "c3.real = " << c3.get_real() << endl;

cout << "c3.imag = " << c3.get_imag() << endl;

return 0;

}

编译并运行:

$ g++ complex.cpp -o complex

$ ./complex

c3.real = 3

c3.imag = 4

通过上述两个例子对比我们可以很容易就发现,在Python中实现运算符重载只需要很少的代码(这个Python例子只有)就可以完成,而使用C++或其他编译型的语言要更多一些的代码(本例中是50多行)。通过上面的两种代码的风格对比,你是否发现编程语言中的面向对象编程是否都长得很像呢?如果回答是肯定的,那么说明我们确实理解或掌握了面向对象编程的这一类问题,而不管它是什么编程语言。

上述我们实现了两个对象的加法及减法运算,也就是在类中重载了加法及减法运算符。接下来再看一个例子,我们实现乘法的运算符重载。代码如下:

class Calc:

def __init__(self, x, y):

self.x = x

self.y = y

def __add__(self, other):

return Calc(self.x + other.x, self.y + other.y)

def __mul__(self, other):

return Calc(self.x * other.x, self.y * other.y)

>>> c1 = Calc(10, 2)

>>> c2 = Calc(8, 4)

>>> c3 = c1 + c2

>>> c3.x

18

>>> c3.y

6

>>> c4 = c1 * c2

>>> c4.x

80

>>> c4.y

8

好了,关于举例就说这么多。如何查看一个对象有哪些运算符可以重载呢?在交互式解释器界面下,通过help命令来查看。如查看int对象可以支持的运算符重载:

Help on class int in module builtins:

class int(object)

| int(x=0) -> integer

| int(x, base=10) -> integer

|

| Convert a number or string to an integer, or return 0 if no arguments

| are given. If x is a number, return x.__int__(). For floating point

| numbers, this truncates towards zero.

|

| If x is not a number or if base is given, then x must be a string,

| bytes, or bytearray instance representing an integer literal in the

| given base. The literal can be preceded by '+' or '-' and be surrounded

| by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.

| Base 0 means to interpret the base from the string as an integer literal.

| >>> int('0b100', base=0)

| 4

|

| Methods defined here:

|

| __abs__(self, /) # 绝对值

| abs(self)

|

| __add__(self, value, /) # 加法

| Return self+value.

|

| __and__(self, value, /) # 逻辑与

| Return self&value.

|

| __bool__(self, /) # 布尔

| self != 0

|

| __ceil__(...)

| Ceiling of an Integral returns itself.

|

| __divmod__(self, value, /)

| Return divmod(self, value).

|

| __eq__(self, value, /) # 相等

| Return self==value.

|

| __float__(self, /)

| float(self)

|

| __floor__(...)

| Flooring an Integral returns itself.

|

| __floordiv__(self, value, /)

| Return self//value.

| __format__(...)

| default object formatter

|

| __ge__(self, value, /) # 大于等于

| Return self>=value.

|

| __getattribute__(self, name, /)

| Return getattr(self, name).

|

| __getnewargs__(...)

|

| __gt__(self, value, /) # 大于

| Return self>value.

|

| __hash__(self, /)

| Return hash(self).

|

| __index__(self, /)

| Return self converted to an integer, if self is suitable for use as an index into a list.

|

| __int__(self, /)

| int(self)

# 省略很多

内置函数重载

内置函数也是可以重载的,如果要改变对象的默认行为,那么就需要对它的内置函数进行重载。举个简单的例子:

class Person:

def __init__(this, name, age):

this.name = name

this.age = age

p = Person('lavenliu', 28)

print(p) # 打印对象时,默认打印的是其在内存中的地址

如果我们希望打印该对象时,打印其名字与年龄的话,就要重载__str__内置方法了。上述代码修改如下:

class Person:

def __init__(this, name, age):

this.name = name

this.age = age

def __str__(this):

return '{}: {}, {}'.format(__class__.__name__, this.name, this.age)

p = Person('Taoqi', 25)

print(p)

Person: Taoqi, 25

上面我们就重载了内置方法__str__,改变上述对象的默认输出行为。

接下来给大家讲解hash的重载,object有一个__hash__属性,而所有的对象都继承自object。

print(hash('abc'))

print(hash(123))

# 重载hash方法

class Point:

def __hash__(self):

return 1

print(hash(Point()))

: 3225858027842937999

: 123

: 1

使用内置函数hash对某个对象求hash值时,会调用对象的__hash__方法。__hash__方法必须返回int类型。hash方法可以用来做什么呢?什么样的对象又是可hash的呢?

可hash对象,就是具有__hash__方法的对象。除非明确的把hash设置为None,

class Point:

__hash__ = None

set([Point()])

: TypeError: unhashable type: 'Point'

一个类如果没有重写__hash__方法的话,这个类的每个对象通常具有不同的hash。如下:

class Point:

pass

p = Point()

print(hash(p))

print(id(p))

print(hash(id(p)))

p2 = Point()

print(hash(p2))

print(id(p2))

: 270104426

: 4321670816

: 4321670816

: -9223372036584671309

: 4321671992

在举一个解析集合坐标的例子,

class Point:

def __init__(self, x, y):

self.x = x

self.y = y

def __hash__(self):

return hash('{}:{}'.format(self.x, self.y))

p1 = Point(3, 5)

p2 = Point(3, 5)

# p1, p2都是(3,5)坐标,那么它们应该是相同的对象

# 接下来使用set()去重

print(set([p1, p2]))

: {<__main__.point object at>, <__main__.point object at>}

由上面的输出,我们可以看到p1与p2是不同的对象。

内置方法与对象的特殊方法

len重载

len的重载。当对象实现了len方法的时候,可以使用内置的len方

法求对象的长度。len方法必须返回非负整数。

bool重载

当对象o实现了__bool__方法时,bool(o)返回值为o.__bool__()。

当对象o没实现__bool__方法时,如果o实现了__len__方法,bool(o)返回值为len(o) != 0。

当对象o既没有__bool__方法及__len__方法时,bool(o)返回值为True。

当对象o即实现__bool__及__len__方法时,__bool__的优先级更高。

__bool__方法必须返回布尔类型。

以上对if及while进行判断时是非常有用的。

总结

今天主要介绍了Python中运算符重载的知识点,并使用C++中的运算符重载对位对比。其实也想让大家体会到如果把某一类问题解决了,那么类似的问题很多都会迎刃而解,真正做到融会贯通,一通百通。

今天主要讲解了:

Python运算符重载

Python内置方法重载(简单介绍,后面还会有介绍)

希望以上内容对大家有帮助。欢迎大家关注DevOps技术客栈。

你可能感兴趣的:(python加法运算符重载)