如何理解 Python 中的面向對象編程?

2021-12-24 CSDN
現如今面向對象編程的使用非常廣泛,本文我們就來探討一下Python中的面向對象編程。
Python支持多種類型的編程範式,例如過程式編程、函數式編程、面向對象編程,而且還可以融合多種類型的範式。現如今面向對象編程的使用非常廣泛。面向對象編程的基本元素是對象,其包含的數據成員稱為屬性,函數(例程、過程)稱為方法。對象是類的實例。換句話說,類主要定義對象的結構,然後我們以類為模板創建對象。類不但包含方法定義,而且還包含所有實例共享的數據。本文我們來探討一下Python中的面向對象編程。我們將演示如何創建類,並使用類來實例化對象。本文的主要內容如下:

創建Python類

數據屬性

實例方法

屬性

類和靜態方法

繼承

本文無法涵蓋這些主題的所有詳細信息。Python中的面向對象編程還包含其他很多方面。希望本文能夠為你學習Python及實現面向對象提供一個良好的開端。我們可以使用關鍵字class定義Python類,關鍵字後面緊跟類的名稱、分號和類的實現:

>>> class MyClass:
...     pass
...

按照慣例,Python類的命名採用首字母大寫(即PascalCase)。

現在讓我們創建這個新類的一個實例,名為MyClass:

>>> a = MyClass()
>>> a
<__main__.MyClass object at 0x7f32ef3deb70>

語句a = MyClass()創建了MyClass的一個實例,並將它的引用賦值給變量a。

我們可以通過Python內置的函數type()或直接通過屬性.__class__來獲取類型(即對象的類)。在拿到類(類型)之後,我們就可以利用屬性.__ name__獲取類的名字:

>>> type(a)
<class '__main__.MyClass'>
>>> a.__class__
<class '__main__.MyClass'>
>>> a.__class__.__name__
'MyClass'

順便提一句,Python類也是對象。它們是type的實例:

>>> type(MyClass)
<class 'type'>

下面,我們來定義一個方法。

Python中每個實例方法的第一個參數必須對應於該實例,即該對象本身。按照慣例,這個參數名為self。後面是其他參數(如果有需要的話)。在調用方法時,我們無需明確提供與參數self相對應的參數。通常,我們需要定義的一個最重要的方法是.__init__()。在類的實例創建後就會調用這個方法。該方法負責初始化類成員。我們定義的.__init__()如下:

>>> class MyClass:
...     def __init__(self, arg_1, arg_2, arg_3):
...         print(f'an instance of {type(self).__name__} created')
...         print(f'arg_1: {arg_1}, arg_2: {arg_2}, arg_3: {arg_3}')
...

下面,我們來創建一個MyClass實例,看看這個初始化方法的具體工作。我們的.__init__()方法需要三個參數(arg_1、arg_2和arg_3),記住我們不需要傳遞與self對應的第一個參數。所以,在實例化對象時,我們需要傳遞三個參數:

>>> a = MyClass(2, 4, 8)
an instance of MyClass created
arg_1: 2, arg_2: 4, arg_3: 8

上述聲明產生的結果如下:

現在我們得到了一個類,它有一個方法.__init__(),以及這個類的一個實例。我們利用.__init__()初始化和定義了實例,我們還可以在這個方法或其他實例方法中,通過給某個數據屬性賦值的方式改變屬性值:

>>> class MyClass:
...     def __init__(self, arg_1, arg_2, arg_3):
...         self.x = arg_1
...         self._y = arg_2
...         self.__z = arg_3
...

現在MyClass有三個數據屬性:

.x可以獲取arg_1的值

._y可以獲取arg_2的值

.__ z可以獲取arg_3的值

我們可以利用Python的解包機制,用更緊湊的形式編寫這段代碼:

>>> class MyClass:
...     def __init__(self, arg_1, arg_2, arg_3):
...         self.x, self._y, self.__z = arg_1, arg_2, arg_3
...

屬性名稱中的下劃線(_)是為了表明這些屬性是「私有」屬性:

開頭沒有下劃線的屬性(比如.x)通常可供對象外部的調用和修改。

開頭擁有一個下劃線的屬性(比如._y)通常也可以從對象外部調用和修改。然而,下劃線是一種慣用的標誌,即該類的創建者強烈建議不要使用該變量。應該僅通過類的功能成員(比如方法和屬性)調用和修改該變量。

開頭擁有雙下劃線的屬性(比如.__ z)將在名字修飾過程中被改名(在本例中它將被改名為._MyClass__z)。你也可以通過這個新名稱從對象外部調用和修改它們。但是,我強烈反對這種做法。應該盡通過類的功能成員以其原始名稱進行調用和修改。

Python對象的數據屬性通常存儲在名為.__ dict__的字典中,它也是對象的屬性之一。但是,你也可以將數據屬性存儲在其他地方。我們可以直接訪問__dict__,或利用Python的內置函數vars()獲取.__ dict__:

>>> a = MyClass(2, 4, 8)
>>> vars(a)
{'x': 2, '_y': 4, '_MyClass__z': 8}
>>> a.__dict__
{'x': 2, '_y': 4, '_MyClass__z': 8}

名字修飾過程把鍵'__z'變成了'_MyClass__z'。

我們可以把.__ dict__當成普通的Python字典使用。

>>> a.x
2
>>> a._y
4
>>> a.__z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute '__z'
>>> a.x = 16
>>> a.x
16
>>> vars(a)
{'x': 16, '_y': 4, '_MyClass__z': 8}

請注意,我們無法訪問.__ z,因為.__ dict__沒有鍵'__z'。

請記住,每個實例方法的第一個參數(按照約定名為self)引用對象本身,但我們無需在調用方法時指定這個參數:

>>> class MyClass:
...     def __init__(self, arg_1, arg_2, arg_3):
...         self.x, self._y, self.__z = arg_1, arg_2, arg_3
...     
...     def set_z(self, value):
...         self.__z = value
...     
...     def get_z(self):
...         return self.__z
...
>>> b = MyClass(2, 4, 8)

方法.get_z()和.set_z()提供了傳統的檢索和修改.__ z值的方法:

>>> b.get_z()
8
>>> b.set_z(16)
>>> vars(b)
{'x': 2, '_y': 4, '_MyClass__z': 16}

你也可以在.get_z()和.set_z()中添加其他功能,例如檢查數據的有效性。這種方法實現了面向對象編程中的一個主要概念:封裝。

還有一種方法(一種更Python的方式)訪問和修改數據屬性是使用屬性。屬性封裝了一系列方法:getter、setter和deleter,但其行為與普通的數據屬性相同。下面的代碼實現了屬性.z,其中還包含.get_z()和.set_z()的功能:

>>> class MyClass:
...     def __init__(self, arg_1, arg_2, arg_3):
...         self.x, self._y, self.__z = arg_1, arg_2, arg_3
...     
...     @property
...     def z(self):
...         return self.__z
...     
...     @z.setter
...     def z(self, value):
...         self.__z = value
...
>>> b = MyClass(2, 4, 8)

如下,我們利用相應的屬性.z來訪問和修改數據屬性.__ z:

>>> b.z
8
>>> b.z = 16
>>> vars(b)
{'x': 2, '_y': 4, '_MyClass__z': 16}

這段代碼比上述示例更精簡優雅。

除了實例方法和屬性之外,類還可以擁有類方法和靜態方法。

>>> class MyClass:
...     def __init__(self, arg_1, arg_2, arg_3):
...         self.x, self._y, self.__z = arg_1, arg_2, arg_3
...     
...     def f(self, arg):
...         print('instance method f called')
...         print(f'instance: {self}')
...         print(f'instance attributes:\n{vars(self)}')
...         print(f'class: {type(self)}')
...         print(f'arg: {arg}')
...     
...     @classmethod
...     def g(cls, arg):
...         print('class method g called')
...         print(f'cls: {cls}')
...         print(f'arg: {arg}')
...     
...     @staticmethod
...     def h(arg):
...         print('static method h called')
...         print(f'arg: {arg}')
...
>>> c = MyClass(2, 4, 8)

方法.f()是一個實例方法。實例方法的第一個參數是對象本身的引用。這些方法可以利用self訪問對象,利用vars(self)或self.__dict__訪問對象的數據屬性,還可以利用type(self)或self.__class__訪問對象對應的類,而且它們還可以擁有自己的參數。

方法.g()的開頭包含修飾器@classmethod,表明這是一個類方法。每個類方法的第一個參數都會指向類本身,按照約定該參數名為cls。與實例方法的情況一樣,我們不需要明確提供與cls對應的參數。而類方法可以利用cls和自己的參數訪問類本身。方法.h()的開頭包含修飾器@staticmethod,表明這是一個靜態方法。靜態方法只能訪問自己的參數。

>>> c.f('my-argument')
instance method f called
instance: <__main__.MyClass object at 0x7f32ef3def98>
instance attributes:
{'x': 2, '_y': 4, '_MyClass__z': 8}
class: <class '__main__.MyClass'>
arg: my-argument

通常,我們應該直接通過類(而不是實例)調用類方法和靜態方法:

>>> MyClass.g('my-argument')
class method g called
cls: <class '__main__.MyClass'>
arg: my-argument
>>> MyClass.h('my-argument')
static method h called
arg: my-argument

請記住,我們不需要傳遞類方法的第一個參數:與cls相對應的參數。

>>> c.g('my-argument')
class method g called
cls: <class '__main__.MyClass'>
arg: my-argument
>>> c.h('my-argument')
static method h called
arg: my-argument

當我們調用c.g或c.h,但實例成員沒有這樣的名稱時,Python會搜索類和靜態成員。

繼承是面向對象編程的另一個重要特性。在這個概念中,類(稱為子類或派生類)會繼承其他類(稱為超類或基類)的數據和函數成員。在Python中,所有類都會默認繼承Python自帶的類對象。但是,我們可以根據需要定義合適的類繼承層次結構。例如,我們可以創建一個名為MyOtherClass的新類,該類繼承了MyClass:

>>> class MyOtherClass(MyClass):
...     def __init__(self, u, v, w, x, y, z):
...         super().__init__(x, y, z)
...         self.__u, self.__v, self.__w = u, v, w
...     
...     def f_(self, arg):
...         print('instance method f_ called')
...         print(f'instance: {self}')
...         print(f'instance attributes:\n{vars(self)}')
...         print(f'class: {type(self)}')
...         print(f'arg: {arg}')
...
>>> d = MyOtherClass(1, 2, 4, 8, 16, 32)

如上,MyOtherClass擁有MyClass的成員:.x、._y、.__z以及.f()。你可以通過語句super().__init__(x, y, z)初始化基類的數據成員x、._y和.__z,該語句會調用基類的.__init__()方法。

除此之外,MyOtherClass還有自己的成員:.__u、.__v、.__w和.f_()。

>>> vars(d)
{'x': 8,
 '_y': 16,
 '_MyClass__z': 32,
 '_MyOtherClass__u': 1,
 '_MyOtherClass__v': 2,
 '_MyOtherClass__w': 4}

我們可以調用基類和派生類中的所有方法:

>>> d.f('some-argument')
instance method f called
instance: <__main__.MyOtherClass object at 0x7f32ef3e7048>
instance attributes:
{'x': 8,
 '_y': 16,
 '_MyClass__z': 32,
 '_MyOtherClass__u': 1,
 '_MyOtherClass__v': 2,
 '_MyOtherClass__w': 4}
class: <class '__main__.MyOtherClass'>
arg: some-argument
>>> d.f_('some-argument')
instance method f_ called
instance: <__main__.MyOtherClass object at 0x7f32ef3e7048>
instance attributes:
{'x': 8,
 '_y': 16,
 '_MyClass__z': 32,
 '_MyOtherClass__u': 1,
 '_MyOtherClass__v': 2,
 '_MyOtherClass__w': 4}
class: <class '__main__.MyOtherClass'>
arg: some-argument

但是,如果派生類包含的某個成員與基類同名,則優先使用派生類的成員。

面向對象編程是Python支持的編程範式之一。面向對象蘊含的抽象以及表徵的現實世界行為在某些時候會非常有幫助性。然而,有時也可能會違反直覺,並為開發過程帶來不必要的麻煩。在本文中,我們介紹了如何利用Python編寫基本的面向對象程序。Python中還有很多類和面向對象的功能,例如:現如今面向對象是非常流行的編程方式。如果你立志做一名Python開發人員,那麼就應該學習面向對象編程。但請不要忘記,Python還支持其他編程範式,例如過程式編程、函數式編程等,在某些情況下也許選用這些範例更為合適。原文:https://www.blog.duomly.com/object-oriented-programming-in-python/

【END】

 熱 文 推 薦 

☞2019雲棲大會:逍遙看巔峰,張勇提「百新」,平頭哥「再亮劍」

☞小米推出售價 19999 元的 MIX Alpha;高通已向華為重啟供貨;.NET Core 3.0 發布 | 極客頭條

點擊閱讀原文,即刻閱讀《程式設計師大本營》最新期刊。

相關焦點

  • Python黑帽編程2.9 面向對象編程
    Python黑帽編程2.9 面向對象編程我個人認為,計算機語言的發展,有兩個方向,一個是從低到高的發展過程,在這個過程中,語言的思考和解決問題的方式是面向硬體的。
  • 如何理解python中的類和對象?
    什麼是類和對象類和對象,在我們的生活中其實是很容易找例子的。類是一種把對象分組歸類的方法。比如動物,植物就可以看作是類,而大象,獅子就可以看作一個動物類中的對象;花,草可以看作是植物類中的對象。為什麼大象和獅子就劃分為動物類,花和草就劃分為植物類呢?
  • Python面向對象程式語言
    高層語言————當你用Python語言編寫程序的時候,你無需考慮諸如如何管理你的程序使用的內存一類的底層細節。可移植性————由於它的開源本質,Python已經被移植在許多平臺上(經過改動使它能夠工 作在不同平臺上)。
  • Python面向對象編程的基本概念
    九道門商業數據分析學院提供介紹在學習面向對象的編程時。我決定深入了解它的歷史,結果令人著迷。術語「面向對象程序設計」(OOP)是艾倫·凱(Alan Kay)在1966年讀研究生時提出的。名為Simula的語言是第一種具有面向對象編程功能的程式語言。它是在1967年開發的,用於製作仿真程序,其中最重要的信息稱為對象。
  • Python基礎知識——python面向對象的解釋型計算機程式語言
    python面向對象的解釋型計算機程式語言。,c語言,Java語言,Python語言,JavaScript語言高級計算機程式語言,分為:解釋型程式語言和編譯型程式語言Python編譯器有些混合型Python特性:1、開源、免費2、解釋型3、面向對象4、膠水語言
  • 史上最全 Python 面向對象編程
    作者:浪子燕青    來自:http://www.langzi.fun/Python面向對象編程.html面向對象編程和函數式編程
  • opencv-python獲取圖像:面向對象與面向過程
    下面是分別用面向過程與面向對象的編程方法實現讀取本地圖像和打開攝像頭兩段代碼:# -*- coding: utf-8 -*-"""面向過程的編程方法,用函數把解決問題的步驟一步一步實現。運行環境:win10系統 python==3.6 opencv-contrib-python== 4.1.0第一行「# -*- coding: utf-8 -*-」 告訴Python解釋器,按照UTF-8編碼讀取原始碼"""import
  • Python 面向對象編程(上篇)
    我的施工計劃圖已完成專題包括:1我的施工計劃2數字專題3字符串專題4列表專題5流程控制專題6編程風格專題7函數使用專題今天是面向對象編程的上篇:基礎專題Python 面向對象編程面向對象程序設計思想,首先思考的不是程序執行流程,它的核心是抽象出一個對象,然後構思此對象包括的數據,以及操作數據的行為方法。
  • 一文看懂Python面向對象編程(Python學習與新手入門必看)-絕對原創
    __score = score    # 定義列印學生信息的方法    def show(self):        print("Name: {}. Score: {}".format(self.name, self.
  • 談談 python 面向對象中的多重繼承
    什麼是多重繼承繼承是面向對象編程的一個重要的方式 ,通過繼承 ,子類就可以擴展父類的功能 。和 c++ 一樣 ,在 python 中一個類能繼承自不止一個父類 ,這叫做 python 的多重繼承(Multiple Inheritance )。多重繼承的語法與單繼承類似 。
  • python核心部分創建對象中各種名詞的定義及用法
    但是python被稱為面向對象的語言,所以創建對象才是python的核心部分,我們今天就走進python的核心部分-創建對象。接下來幾天的章節非常重要非常核心,非常重要非常核心,非常重要非常核心,重要的事情說是三次。首先說一下幾個名詞的定義,方便你在以後的學習中理解。
  • 如何使用JavaScript -面向對象編程
    學習目標理解面向對象開發思想掌握 JavaScript 面向對象開發相關模式面向對象介紹什麼是對象Everything is object (一切皆對象)面向對象編程 —— Object Oriented Programming,簡稱 OOP ,是一種編程開發思想。它將真實世界各種複雜的關係,抽象為一個個對象,然後由對象之間的分工與合作,完成對真實世界的模擬。在面向對象程序開發思想中,每一個對象都是功能中心,具有明確分工,可以完成接受信息、處理數據、發出信息等任務。
  • python面向對象三大特徵
    大概所有變成初學者初學者最頭疼的第一道坎就是面向對象的理解封裝從封裝本身去理解 就是把小貓小狗用袋子裝起來,然後把袋子的小口封上私有化方法:方法的私有化可以保護好一些核心的代碼,可以添加條件,是別人不能不滿足條件的更改,進行代碼的保護,python
  • python面向對象,小白從零開始,python基礎入門,你會了嗎?
    Python,是一種面向對象的解釋型電腦程式設計語言,以簡單、易學、速度快等優點,是大部分想進入IT行業的從業人的選擇。IEEE發布2017年程式語言排行榜:Python超過JAVA程式語言排名第一。所以Python非常熱門的程式語言!
  • 使用 Python 學習面向對象的編程 | Linux 中國
    在我上一篇文章中,我解釋了如何通過使用函數、創建模塊或者兩者一起來使 Python 代碼更加模塊化。函數對於避免重複多次使用的代碼非常有用,而模塊可以確保你在不同的項目中復用代碼。但是模塊化還有另一種方法:類。如果你已經聽過面向對象編程object-oriented programming(OOP)這個術語,那麼你可能會對類的用途有一些概念。
  • 高級篇PLC的面向對象編程
    一、 實現方式    面向對象編程在Step7中使用功能塊(即FB)編程,一談到此大家就會想到西門子提出的模塊化編程,不錯,就是這個模塊化編程,但西門子提出的模塊化、背景數據塊、多重背景等名詞並不能讓大家很明白的理解和使用這種優秀的設計理念。
  • 一篇非常全的Python 面向對象編程
    轉自:浪子燕青from:  Python編程開發http://www.langzi.fun/Python面向對象編程
  • 史上最全Python面向對象編程
    學神IT教育:XueGod-IT最負責任的線上直播教育平臺面向對象編程中,將函數和變量進一步封裝成類,類才是程序的基本元素
  • 【AICAMP —— Python】入門系列!(6. 面向對象)
    面向對象(Object Oriented)目前我們大部分語言的設計都是面向對象的,說到面向對象,其實說起來挺容易理解,但是在實際運用的時候就會發現還是有很多講究的。在面向對象基礎之上,還包括了面向對象設計(OOD), 面向對象分析(OOA),面向對象編程(Object Oriented Programming),反正就是一句話,面向對象!
  • R用戶Python指南:面向對象編程
    本文為R用戶Python指南系列第8篇,Python代碼主要取自《Python編程:從入門到實踐》第9章,R代碼根據Python代碼複寫。本文使用rmarkdown和prettydoc模板生成格式,代碼塊中#之後的內容為注釋,##之後的內容為代碼輸出結果。本文使用的R包主要為stringr和R6,需預先加載。