Python第七章-面向對象

来源:https://www.cnblogs.com/yanadoude/archive/2020/04/02/12622887.html
-Advertisement-
Play Games

面向對象編程基礎 一、面向對象概念 1.1 什麼是面向過程 ​ 就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了。 ​ 生活中的的例子舉例。 1.2 什麼是面向對象 ​ 面向對象是把構成問題事務分解成各個對象,建立對象的目的不是為了完成一個步驟,而 ...


面向對象編程基礎

一、面向對象概念

1.1 什麼是面向過程

​ 就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了。

​ 生活中的的例子舉例。

1.2 什麼是面向對象

​ 面向對象是把構成問題事務分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為。

  1. 面向對象是一種思維方法
  2. 面向對象是一種編程方法
  3. 面向對象並不只針對某一種編程語言

1.3 面向對象和麵向過程的區別和聯繫

面向過程,做什麼

面向過程過程側重整個問題的解決步驟,著眼局部或者具體,核心:過程的實現

【面向過程】:
為了把大象裝進冰箱,需要3個過程。

  1. 把冰箱門打開(得到打開門的冰箱)
  2. 把大象裝進去(打開門後,得到裡面裝著大象的冰箱)
  3. 把冰箱門關上(打開門、裝好大象後,獲得關好門的冰箱)
    每個過程有一個階段性的目標,依次完成這些過程,就能把大象裝進冰箱。

面向對象,誰來做

面向對象側重具體的功能,讓某個對象具有這樣的功能。更加側重於整體。核心:對象

【面向對象】:
為了把大象裝進冰箱,需要做三個動作(或者叫行為)。
每個動作有一個執行者,它就是對象。

  1. 冰箱,你給我把門打開
  2. 大象,你給我鑽到冰箱里去
  3. 冰箱,你給我把門關上
    依次做這些動作,就能把大象裝進冰箱。
各自的優缺點

面向過程的優點:
      流程化使得編程任務明確,在開發之前基本考慮了實現方式和最終結果;
      效率高,面向過程強調代碼的短小精悍,善於結合數據結構來開發高效率的程式。。
      流程明確,具體步驟清楚,便於節點分析。

  缺點是:需要深入的思考,耗費精力,代碼重用性低,擴展能力差,維護起來難度比較高,
          對複雜業務來說,面向過程的模塊難度較高,耦合度也比較高。

面向對象的優點:結構清晰,程式便於模塊化,結構化,抽象化,更加符合人類的思維方式;
    封裝性,將事務高度抽象,從而便於流程中的行為分析,也便於操作和自省; 
    容易擴展,代碼重用率高,可繼承,可覆蓋;
    實現簡單,可有效地減少程式的維護工作量,軟體開發效率高。

  缺點是:效率低,面向對象在面向過程的基礎上高度抽象,從而和代碼底層的直接交互非常少機會,
              從而不適合底層開發和游戲甚至多媒體開發;
              複雜性,對於事務開發而言,事務本身是面向過程的,過度的封裝導致事務本身的複雜性提高。

編程語言對面向對象的實現主流的有兩種方式:基於類的面向對象和基於原型的面向對象。

不管以什麼方式實現,都具有面向對象的三大特征:

  • 封裝

    也就是把客觀事物封裝成抽象的類或具體的對象,並且類或對象可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。

  • 繼承

    可以讓某個類型的對象獲得另一個類型的對象的屬性的方法

  • 多態

    不同實例的相同方法在不同情形有不同表現形式。多態機制使具有不同內部結構的對象可以共用相同的外部介面。

1.4編程語言中面向對象的實現方式

1.4.1基於類的面向對象

典型的語言:Java、C#、 pthon 、c++等

對象(object)依靠 類(class)來產生

1.4.2基於原型的面向對象

典型的語言:JavaScript

對象(object)則是依靠 構造器(constructor)利用 原型(prototype)構造出來的

二、python中的類

python 是基於類的面向的對象語言, 所以學習 python 面向對象, 必須要先學習類

2.1類和實例的概念

通過前面的學習我們已經知道, 面向對象編程(Object Oriented Programming,簡稱OOP),是一種程式設計思想。OOP把對象作為程式的基本單元,一個對象包含了 數據和操作數據的函數(方法)

而面向對象的程式設計把電腦程式視為一組對象的集合,而每個對象都可以接收其他對象發過來的消息,並處理這些消息,電腦程式的執行就是一系列消息在各個對象之間傳遞。


2.1.1 類的理解

在 python 中所有類型的數據都可以看成對象, 包括我們我們以前學習的所有的內置類型int, float等.

像這些 int, float, list這些數據類型, 就是我們面向對象中的類

我們可以根據需要自定義很多類型出來, 這些自定義的類型也是我們面向對象中的類


2.1.2對象的理解

我們天天說對象, 到底該怎麼去理解對象?

a = 3 變數 a 賦值為整數 3, 這裡的 3 就是一個int類型的對象.
nums = [2, 4, 1] 這裡的 [2, 4, 1] 就是list類型的列表對象.

可以這麼說, 在 python 中任何類型的數據數據都是對象.(和其他語言 c++, java 等不太一樣, 他們有一些不是對象的基本數據類型)

對象其實就是對數據和操作數據的方法進行的封裝


2.1.3類與對象的關係

類與對象的關係, 就是我們每個人同人類的關係一樣.

人類是對每個具體的人的共同的特點的抽象. 比如都有手腳, 耳朵, 還都可以吃飯, 娛樂, 男人還可以去大保健. 人類就是編程語言中的類型.

而每個人是人類的一個個的具體的實現. 每個人都是編程語言中的一個對象


類是對對象的抽象描述, 而對象是類的具體實現. 他們是抽象與具體的關係.


例如:
汽車製造圖紙和一個個的汽車.

圖紙就是類, 汽車就是對象


2.1.4先有對象還是先有類

看情況:

  1. 在做面向對象分析的時候, 一般是先有對象, 然後把對象的共性抽象出來, 然後就形成了類.
  2. 編寫代碼的時候, 一般是先完成類的編寫, 然後在需要的時候創建對象就可以了.

2.2 定義類

我們需要關鍵字class來定義類

class 類名:
    # 類中定義的內容

比如我們定義一個表示學生的Student類:

class Student:
    pass

說明:

  1. class 後面緊跟類名. 類名的命名使用駝峰命名法.
  2. 類名的後面跟一個冒號
  3. 然後是帶有正確縮進的類的主體.(上面的例子中使用 pass, 表示空的類主體)

2.3創建對象

定義類的目的就是使用類來創建對象.

在 python 中使用類創建對象與其他語言差別較大, 其他語言需要使用關鍵字new, python 精簡了創建方式, 我們不需要new.

2.3.1 python 就是以函數形式調用來創建對象的!


python 創建對象直接使用類名()就可以了.

class Student:
    pass


s1 = Student()    # 使用類創建對象
print(s1)

創建對象的過程是不是和方法調用一樣一樣的?!

2.4類定義的深入研究

類必須先定義再使用

類的定義與函數定義是一樣的, 都要遵循先定義再使用

s2 = Student()    # 此處無法使用類來創建對象


class Student:
    pass

可以在if語句中甚至函數中定義類

if True:
    class Student:
        pass


s1 = Student()
print(s1)

使用類的時候, 一定要保證類被已經被定義了.


類的主體

類主體中都可以定義什麼?

在 python 中類可以定義:


1. 欄位(field, 在國內很多人叫屬性)

在 python 中欄位分 2 種:

  1. 實例變數(Instance Variables):
    他存儲的值是屬於每一個對象的, 或者對不同的對象來說他們是獨立. 就像人的私有財產
  2. 類變數(Class Variables):
    他存儲的值是屬於類本身的, 而不是屬於某一個具體的對象, 或者說他是被所有的對象所共有的. 就像公共財產

2. 方法

方法就是我們以前學習的函數, 只是同類扯上關係了而已!

在 python 中的方法分 3 種:

  1. 實例方法.
    和實例變數一樣, 他是屬於對象的.
    實例方法相比普通的函數有一個比較特殊的地方:第一個形參總是會自動傳入這個實例(對象)
  2. 類方法
    和類變數一樣, 是屬於類的.
    類方法與實例方法的區別在於第一個參數: 類方法的第一個參數總是這個類本身.
  3. 靜態方法
    靜態方法和實例沒有任何關係. 它僅僅是定義在類中而已, 這個時候類就相當於這個方法的命名空間.

2.4.1類中定義欄位

2.4.1.1類變數

類變數表示所有的對象所共有的一種數據.換句話說, 所有的對象都可以直接訪問到, 並且他們訪問到的是同一個變數(肯定是相同的值!)

把變數直接聲明在類的內部的變數.

訪問類變數直接通過類名.變數名來訪問.

class Student:
    # 直接在類中定義變數,
    # 這樣的變數就是類變數(類屬性, 類似 java 中的靜態屬性)
    country = "china"


print(Student.country)
# 修改類變數的值
Student.country = "usa"
print(Student.country)


當然你也可以在任何的地方通過類名.屬性=值的方式動態給類添加類屬性.

class Student:
    # 直接在類中定義變數,
    # 這樣的變數就是類變數(類屬性, 類似 java 中的靜態屬性)
    country = "china"


Student.count = 1   # 動態添加類屬性
print(Student.count)

但是, 建議在類中直接定義類屬性, 只有在需要的時候才使用動態的方式添加類屬性.


2.4.1.2 實例變數

實例變數表示每個對象都自己所獨有.

所以, 實例變數與每個具體的對象相關.

添加實例變數:

一般是在一個叫做__init__()的方法裡面來添加. (關於方法下節再細講, 現在你只需要知道他是一個函數就可以了)

__init__(), 註意他是左右分別有 2 個_. 這個方法不需要我們手動去調用, 當你使用類創建對象的時候, 會自動調用這個方法.

這個方法的第 1 個參數永遠是創建的那個對象(所有的實例方法都是這樣的), 我們可以通過這個參數來向對象中添加屬性, 這樣的屬性就是實例屬性.

作為國際慣例, 第 1 個參數的一般都命名為self, 當然你也可以給他起個別的名字, 但是何必呢!


class Student:
    def __init__(self):
        self.name = "李四"
        self.age = 20


s = Student()
print(s.name)
print(s.age)


上面這種寫法, 會導致使用這個類創建的對象的nameage這個兩個實例變數的值都會初始化為同樣的值, 這其實並不好.

我們想每個變數初始化的值都不一樣, 可以在創建的對象的是把具體的值溝通過實參傳遞過去, 則實參會自動傳到__init__()方法的第 2 個開始的參數中.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age


zs = Student("張三", 20)
print(zs.name + " " + str(zs.age))
ls = Student("李四", 30)
print(ls.name + " " + str(ls.age))

你會發現每個對象的值都不一樣的!


2.4.1.3 可以通過對象直接訪問類變數

python 允許通過對象直接訪問到類變數. (有些語言是不允許的, 比如 c#, JavaScript 就不允許, 但是 java 允許)

class Student:
    country = "china"

    def __init__(self, name, age):
        self.name = name
        self.age = age


zs = Student("張三", 20)
print(zs.name + " " + str(zs.age))
ls = Student("李四", 30)
print(ls.name + " " + str(ls.age))

print(zs.country) # 通過對象直接訪問類變數
print(ls.country)


2.4.2 類中定義方法

2.4.2.1. 定義實例方法

實例方法和普通方法的區別:

  1. 實例方法必須定義在類中
  2. 實例方法的第一個參數永遠是那個具體的對象, 而且不需要調用者手動傳入, python 會自動傳入那個對象. 而且這個形參一般命名為self
  3. 實例方法調用方式:對象.實例方法(實參)

class Student:
    def __init__(self, name):
        self.name = name

    # 定義一個實例方法:一個參數表示具體的對象, python 會預設傳入
    def speak(self):
        print("我的名字是:" + self.name)  # 在實例方法中訪問實例變數


s = Student("志玲")
s.speak()


self的理解

學過其他語言的人都知道, python 的 self 其實就是在其他語言的this.

那麼self到底指代哪個對象?

通過哪個對象調用的這個實例方法, 那麼這個實例方法中的self就指代誰

而且 python 的self一朝綁定, 終身不變. (不像 javascript 中的那個 this 小婊砸隨著調用方式的不同而而更改綁定對象, 讓你眼花繚亂到懷疑人生)


class Student:
    def __init__(self, name):
        self.name = name

    # 定義一個實例方法:一個參數表示具體的對象, python 會預設傳入
    def speak(self):
        print("我的名字是:" + self.name)  # 在實例方法中訪問實例變數


s = Student("志玲")
# s.speak 的 this 永遠指定的是 s 對象
foo = s.speak  # 重新定義一個變數, 指向了對象 s 的 speak 方法. 
foo()  # 則 self 仍然綁定的是 s 對象


class Student:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print("我的名字是:" + self.name)  # 在實例方法中訪問實例變數


s1 = Student("志玲")
s2 = Student("鳳姐")

s2.speak = s1.speak

s2.speak()

說明:
s1.speak表示的那個方法賦值給s2.speak, 雖然你調用的時候使用的是s2.speak(), 但是他指向的那個方法的self已經永遠的綁定到了s1


2.4.2.2. 定義類方法

類方法和實例方法的區別:

  1. 一個方法想成為類方法, 需要在方法的上面要添加一個內置裝飾器:@classmethod
  2. 實例方法的第一個參數是具體的對象, 而類方法的第一個參數是類對象.(python 中一切皆對象, 那麼類本身也是個對象, 我們一般稱之為類對象). 類對象也是 python 自動傳遞. (類對象一般起名為 cls)
  3. 調用實例方法使用對象.實例方法(實參), 而調用類方法使用類名.類方法(實參)
  4. 類方法中可以訪問類變數, 但是不能訪問實例變數, 因為沒有self啊.

class Student:
    country = "china"

    @classmethod
    def say(cls):
        print("我們的國家是:" + cls.country)

Student.say()


什麼時候使用類方法

如果一個方法不需要操作實例變數, 則這個方法建議定義成類方法!


註意:

有一點註意, 類方法也可以通過實例對象來調用, 但是不管怎麼調用, 類方法的第一個參數總是類對象!

class Student:
    country = "china"

    @classmethod
    def say(cls):
        print("我們的國家是:" + cls.country)


Student.say()
s = Student()
s.say()


2.3.2.3. 定義靜態方法

靜態方法其實是一種普通的函數, 他僅僅是處於類的命名空間中.(把當前類作為了他的命名空間, 其他情況與普通函數沒有任何區別).

  1. 定義靜態方法只需要在函數的上面添加一個裝飾器:@staticmethod
  2. 調動靜態方法: 類名.靜態方法(實參). 只需要把類名作為他的首碼來執行, 與普通函數相比, 沒有其他任何多餘的操作!

class Student:
    @staticmethod  # 定義靜態方法
    def create_student():
        print("我是個靜態方法")


Student.create_student()


靜態方法的應用場景

因為 python 的類中只有一個__init__()方法, 意味著創建對象的方式只能有一種.

我們可以使用靜態方法給外界提供其他的創建對象的方式.


import time
class Date:
    """
    創建一個表示日期的類
    """
	def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    @staticmethod
    def now():
        """
        創建表示當前日期的對象
        :return:
        """
        t = time.localtime()
        return Date(t.tm_year, t.tm_mon, t.tm_mday)

    @staticmethod
    def tomorrow():
        """
        創建表示明日日期的對象
        :return:
        """
        t = time.localtime(time.time() + 60 * 60 * 24)
        return Date(t.tm_year, t.tm_mon, t.tm_mday)

now = Date.now()
print("現在是: %d年%d月%d日" % (now.year, now.month, now.day))
now = Date.tomorrow()
print("明天是: %d年%d月%d日" % (now.year, now.month, now.day))

2.4.3 python中的__init()__方法

在任何一個 python 類中, 都存在一個__init__()的方法, 而且只能存在一個.

我們不管用什麼辦法創建對象, 都會自動的去執行__init__()方法

預設情況下的__init()__

預設情況, __init()__什麼都不做.

__init__()初始化實例變數

__init()__方法的主要作用就是添加並初始化實例變數. 初始化的實例變數的值在創建對象的時候通過實參傳遞過來.

__init__()的第一個形參總是新創建的那個實例對象.


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 項目簡介 項目來源於: "https://gitee.com/glotion/servlet jsp_news" 本系統基於 JSP+Servlet+C3P0+Mysql 。涉及技術少,易於理解,適合 JavaWeb初學者 學習使用。 難度等級:簡單 技術棧 編輯器 IntelliJ IDEA 20 ...
  • 給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。 如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。 您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。 示例: 輸入:(2 -> 4 -> ...
  • 一. 反射 反射的概念是由Smith在1982年首次提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了電腦科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,併在Lisp和麵向對象方面取得了成績。 python面向對象中的反射:通過字元 ...
  • [TOC] 本文內所有實現的代碼均附在文末,有需要可以參考。~~(好奇寶寶們可以粘貼下來跑一下~~ 多線程程式評價標準 安全性: ​ 安全性就是不損壞對象。也就是保證對象內部的欄位的值與預期相同。 生存性: ​ 生存性是指無論什麼時候,必要的處理都一定能夠執行。失去生存性最典型的例子就是“死鎖”。 ...
  • 用vector實現鄰接表 vector <int> G[100]; //表示有100個頂點的圖的鄰接表 G[u].push_back(v); //從頂點u 向頂點v 畫邊,即在相當於創建一個二維數組G[100][i] //搜索與頂點u 相鄰的頂點v for( int i = 0; i < G[u]. ...
  • 作者:劉超 轉自【劉超的通俗雲計算】 什麼是雲計算 早在十年前,市場上就出現了很多和雲計算相關的崗位,當時正是雲計算技術最火熱的時代,不管是BAT還是華為等企業都開始佈局雲計算,於是OpenStack研發、容器研發、底層開發等相關崗位相應地也越來越多,雖然這幾年大數據和AI的風頭已經完全壓過了雲計算 ...
  • 前言 文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者:李嘉圖 PS:如有需要Python學習資料的小伙伴可以加點擊下方鏈接自行獲取http://t.cn/A6Zvjdun 起因 今天有個朋友家裡wifi密碼忘了,沒有能連上的 ...
  • JDBC 前言 在學習了SQL語句後,我們肯定會思考如何使用資料庫里的數據。這個時候,我們便要學習JDBC來將資料庫與JAVA結合在一塊。 正題 什麼是JDBC? Java資料庫連接,(Java Database Connectivity,簡稱JDBC)是Java語言中用來規範客戶端程式如何來訪問數 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...