Python物件導向之運算子多載

來源:互聯網
上載者:User

標籤: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.real3c3.imag4c1 + c2 # 此處出問題了,試圖讓兩個對象相加---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-7-61818d23e61f> in <module>()----> 1 c1 + c2TypeError: 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 + c2c4.realc4.imag

方法名前後帶雙底線的方法,稱之為專有方法或者魔術方法。帶雙底線的方法是有特殊含義的。

這時我們也不妨看看C++中是如何?運算子多載的吧,代碼如下:

#include <iostream>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 = 3c3.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.x18>>> c3.y6>>> c4 = c1 * c2>>> c4.x80>>> c4.y8

好了,關於舉例就說這麼多。如何查看一個對象有哪些運算子可以重載呢?在互動式解譯器介面下,通過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 = agep = Person(‘lavenliu‘, 28)print(p)  # 列印對象時,預設列印的是其在記憶體中的地址<__main__.Person object at 0x1045b7a58>

如果我們希望列印該對象時,列印其名字與年齡的話,就要重載__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 0x102077b38>, <__main__.Point object at 0x102077e80>}

由上面的輸出,我們可以看到p1與p2是不同的對象。

內建方法與對象的特殊方法 len重載

len的重載。當對象實現了len方法的時候,可以使用內建的len方
法求對象的長度。len方法必須返回非負整數。

bool重載
  1. 當對象o實現了__bool__方法時,bool(o)傳回值為o.__bool__()
  2. 當對象o沒實現__bool__方法時,如果o實現了__len__方法,bool(o)傳回值為len(o) != 0。
  3. 當對象o既沒有__bool__方法及__len__方法時,bool(o)傳回值為True。
  4. 當對象o即實現__bool____len__方法時,__bool__的優先順序更高。
  5. __bool__方法必須返回布爾類型。

以上對if及while進行判斷時是非常有用的。

總結

今天主要介紹了Python中運算子多載的知識點,並使用C++中的運算子多載對位對比。其實也想讓大家體會到如果把某一類問題解決了,那麼類似的問題很多都會迎刃而解,真正做到融會貫通,一通百通。

今天主要講解了:

  1. Python運算子多載
  2. Python內建方法重載(簡單介紹,後面還會有介紹)

希望以上內容對大家有協助。歡迎大家關注DevOps技術客棧。

Python物件導向之運算子多載

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.