1. 程式人生 > 程式設計 >Python基於class()實現面向物件原理詳解

Python基於class()實現面向物件原理詳解

首先,類是一個集合,包含了資料,操作描述的一個抽象集合

你可以首先只把類當做一個容器來使用

class Cycle:
  def __init__(self,r):
    self.pi=3.14
    self.r=r
a=Cycle(4)
b=Cycle(7)

你看,我們定義了一個 Cycle 類,我們現在只是將它當做一個數據集合來用,我們利用其例項之間彼此資料隔離的特性來保證具體的例項資料彼此不汙染。好了你現在想問,為什麼我們要用資料集合來放資料

好了,我們來看看沒有類之前我們會怎麼樣,假設我們現在要計算圓的面積

def square(r,pi):
  return pi * (r**2)
PI=3.14
a_r=4
a_square=square(a_r,PI)
b_r=7
b_square=square(b_r,PI)

看起來沒有問題,好了,現在問題來了,假如,你現在要計算很多圓的面積,那麼你是不是發現,不斷的用變數命來隔離資料方式變得越來越髒了。而且你發現是不是有很多冗餘的程式碼

好了我們這麼改一改

class Cycle:
  def __init__(self,r):
    self.pi=3.14
    self.r=r

def square(value):
  if not isinstance(value,Cycle):
    raise ValueError("value muse be Cycle instace")
  value.square=value.pi * (value.r**2)

a=Cycle(4)
b=Cycle(7)

square(a)
square(b)

好了,你有沒有覺得現在清晰了一點。

好了,現在我們現在還可以改一下

class Cycle:
  def __init__(self,r):
    self.pi=3.14
    self.r=r
  def square(self,value):
    return self.pi * (self.r**2)

好了,現在你可能迷惑了,我們為啥要把 square 函式放在類中?

好了,我現在要計算長方形,原型,梯形各種各樣二維幾何圖形的面積,這樣該怎麼寫???

你想了想我們之前說的將類作為資料容器,你想了想寫了如下的程式碼

class Rectangle:
  def __init__(self,length,height):
    self.length=length
    self.height=height
class Cycle:
  def __init__(self,r):
    self.pi=3.14
    self.r=r
def rec_square(value):
  if not isinstance(value,Rectangle):
    raise ValueError("value muse be Rectangle instace")
  value.square=value.length * value.height
def cycle_square(value):
  if not isinstance(value,Cycle):
    raise ValueError("value muse be Cycle instace")
  value.square=value.pi * (value.r**2)

你想一想,這樣是不是感覺如果計算需求越來越多,程式碼是不是還是會越來越髒?

如果我們將函式放在類裡,並且用繼承的特性,我們可以寫出這樣的程式碼

class Geometry:
  def get_square(self):
    raise NotImplementedError

class Rectangle(Geometry):
  def __init__(self,height):
    self.length=length
    self.height=height
  def get_square(self):
    return self.length*self.height

class Cycle(Geometry):
  def __init__(self,r):
    self.pi=3.14
    self.r=r
  def get_square(self):
    return self.pi * (self.r**2)

def square(value):
  if not isinstance(value,Geometry):
    raise ValueError("value muse be Geometry instace")
  value.square=value.get_square()

你看,我們現在只需要給使用者暴露一個統一的介面,使用者(使用者也以是我們自己)不需要關心怎麼樣選擇正確的函式,他只需要呼叫統一的 square 函式,就可以獲取到具體的面積,是不是輕鬆很多了??

所以,類,它是對資料,操作的一種封裝,這個封裝的意義在於我們可以去更好的優化程式碼結構。

好了再舉一個例子,我們可以用類來控制訪問許可權

class People:
  def __init__(self,website):
    self.__favorite_website="1024.com"
  def bad_or_not(self):
    return self.__favorite_website=="1024.com"

你看,我們用 private 變數,來確保外部沒法直接訪問一些敏感資料(實際上 Python 裡 private 並不嚴格,hook 一下還是可以訪問的)

好,在舉一個例子

class People:
  def __init__(self,website):
    self.__favorite_website="1024.com"
  def bad_or_not(self):
    return self.__favorite_website=="1024.com"
  @property
  def favorite_website(self):
    return self.__favorite_website
  @favorite_website.setter
  def favorite_website(self,value):
    if value=="1024.com":
      raise ValueError("你不能去草榴,兄弟,你營養不足")
    self.__favorite_website=value

你看,我們現在很方便的實現在設定資料值的時候,對其過濾。

撤了這麼多,回到你的問題

首先A君說的沒毛病,但我想知道僅僅使用函式錘子,螺絲刀來完成一個專案比使用Class工廠+函式錘子來完成一個專案的效率會更低麼?

理由是什麼?大神在什麼時候會考慮使用Class來提高程式碼的“執行效率”和程式碼的“可讀性”。迴歸實際情況,我很多時候都是呼叫同一個函式/方法去輸出某個結果。

至今還想不出為什麼呼叫Class會更方便?(PS:本人大菜鳥,寫了上千行程式碼了,但仍然搞不懂什麼情況下需要用到Class類。也曾嘗試在自己的程式碼中強行加入Class輸出結果

但感覺不靈活,而且要寫的程式碼明顯多了也不便於理解。求大神舉例,碾壓我的無知!)。C君說大型專案不使用Class呼叫物件會累死,到底這個“累死”體現在哪裡?

首先一個問題,我整個答案裡所寫的這些程式碼,不用面向物件這一套能不能實現?

很明顯,能。

但是實現的乾淨麼?個人覺得不乾淨。

專案規格上去後,我們如果按照傳統的方式進行開發,務必要多重檢查,確保自己不會手抖呼叫了錯誤的東西。而 OOP 這一套思想,其實就是通過利用合適的程式碼結構和封裝,某種程度上來講是減少我們犯錯的可能。

同時,現在開發基本都不是一個人的單打獨鬥,你寫的程式碼可能會被其餘人使用與維護。我們有個前提,要假設使用維護你程式碼的人都是傻逼。我們要適當的封裝程式碼,優化結構,讓使用者儘可能的少犯錯、

所以最後,無論是各個語言的變數命名規則也好,還是 OOP 這一套正規化也好。其本質是在自由度與可讀性可維護性之間的一種相對較優的妥協,這種妥協根本的目的就在於通過規範化的操作與封裝,減少團隊開發維護的成本,優化開發體驗。

另外,關於開發這一套還有個老生常談的問題過度封裝。我個人的觀點是在你知道什麼是 過度封裝 之前,你沒必要考慮這個問題,按照教科書和開原始碼裡的結構,去不斷封裝優化你的程式碼。

面向物件 更容易使用 ,缺點就是 換一個開發人,難維護,很難理解前面人的思維,出了錯不好找位置

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。