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

2021-01-08 CSDN

現如今面向對象編程的使用非常廣泛,本文我們就來探討一下Python中的面向對象編程。

作者 | Radek Fabisiak

譯者 | 彎月,責編 | 郭芮

以下為譯文:

Python支持多種類型的編程範式,例如過程式編程、函數式編程、面向對象編程,而且還可以融合多種類型的範式。

現如今面向對象編程的使用非常廣泛。面向對象編程的基本元素是對象,其包含的數據成員稱為屬性,函數(例程、過程)稱為方法。

對象是類的實例。換句話說,類主要定義對象的結構,然後我們以類為模板創建對象。類不但包含方法定義,而且還包含所有實例共享的數據。

本文我們來探討一下Python中的面向對象編程。我們將演示如何創建類,並使用類來實例化對象。本文的主要內容如下:

創建Python類數據屬性實例方法屬性類和靜態方法繼承本文無法涵蓋這些主題的所有詳細信息。Python中的面向對象編程還包含其他很多方面。希望本文能夠為你學習Python及實現面向對象提供一個良好的開端。

創建Python類

我們可以使用關鍵字class定義Python類,關鍵字後面緊跟類的名稱、分號和類的實現:

>>> classMyClass:... 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__()如下:

>>> classMyClass:... 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 ofMyClass createdarg_1: 2, arg_2: 4, arg_3: 8

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

創建一個MyClass類型的對象的實例。自動調用該實例的方法.__init__()。我們傳遞給MyClass()方法的參數:(2,4和8)會被傳遞給.__init__()。.__init__()執行我們的請求,並輸出結果。它利用type(self).__name__獲取類的名稱。現在我們得到了一個類,它有一個方法.__init__(),以及這個類的一個實例。

數據屬性

下面我們來修改MyClass,增加一些數據屬性。

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

>>> classMyClass:... 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的解包機制,用更緊湊的形式編寫這段代碼:

>>> classMyClass:... 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.x2>>> a._y4>>> a.__zTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError:'MyClass' object has no attribute '__z'>>> a.x = 16>>> a.x16>>> vars(a){'x': 16, '_y': 4, '_MyClass__z': 8}

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

實例方法

下面,我們來創建兩個實例方法:

●.set_z():修改.__ z。

●.get_z():返回.__ z的值。

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

>>> classMyClass:... def__init__(self, arg_1, arg_2, arg_3):... self.x, self._y, self.__z = arg_1, arg_2, arg_3... ... defset_z(self, value):... self.__z = value... ... defget_z(self):... returnself.__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()的功能:

>>> classMyClass:... def__init__(self, arg_1, arg_2, arg_3):... self.x, self._y, self.__z = arg_1, arg_2, arg_3... ... @property... defz(self):... returnself.__z... ... @z.setter... defz(self, value):... self.__z = value...>>> b = MyClass(2, 4, 8)

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

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

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

類與靜態方法

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

下面讓我們為MyClass添加三個方法:

>>> classMyClass:... def__init__(self, arg_1, arg_2, arg_3):... self.x, self._y, self.__z = arg_1, arg_2, arg_3... ... deff(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... defg(cls, arg):... print('class method g called')... print(f'cls: {cls}')... print(f'arg: {arg}')... ... @staticmethod... defh(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,表明這是一個靜態方法。靜態方法只能訪問自己的參數。

Python中常見的調用實例方法的方法如下:

>>> c.f('my-argument')instance method f calledinstance: <__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')classmethodgcalledcls: <class '__main__.MyClass'>arg: my-argument>>> MyClass.h('my-argument')static method h calledarg: my-argument

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

但是,我們可以像下面這樣調用類方法和靜態方法:

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

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

繼承

繼承是面向對象編程的另一個重要特性。在這個概念中,類(稱為子類或派生類)會繼承其他類(稱為超類或基類)的數據和函數成員。

在Python中,所有類都會默認繼承Python自帶的類對象。但是,我們可以根據需要定義合適的類繼承層次結構。

例如,我們可以創建一個名為MyOtherClass的新類,該類繼承了MyClass:

>>> classMyOtherClass(MyClass):... def__init__(self, u, v, w, x, y, z):... super().__init__(x, y, z)... self.__u, self.__v, self.__w = u, v, w... ... deff_(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()獲取數據成員:

>>> 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 calledinstance: <__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_ calledinstance: <__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中還有很多類和面向對象的功能,例如:

方法:.__repr__()和.__str__()方法:.__new__()操作符方法:.__getattribute__()、.__getattr__()、.__setattr__()和.__delattr__()生成器可調用性創建序列描述器上下文管理抽象類和成員多重繼承使用super()拷貝序列化slot類修飾器數據類等等……

現如今面向對象是非常流行的編程方式。如果你立志做一名Python開發人員,那麼就應該學習面向對象編程。但請不要忘記,Python還支持其他編程範式,例如過程式編程、函數式編程等,在某些情況下也許選用這些範例更為合適。

盡情享受編程的快樂!

原文:https://www.blog.duomly.com/object-oriented-programming-in-python/

本文為 CSDN 翻譯,轉載請註明來源出處。

相關焦點

  • Python 面向對象編程
    除此之外,這種編程技術已經被包括Python在內的各種程式語言所採用,它的應用幾乎遍及所有領域,如實時系統、人工智慧、專家系統、CS系統、面向對象資料庫等等。因此,在本文中,我將解釋Python中面向對象編程的基本概念。目錄什麼是面向對象編程?
  • 如何學習面向對象的編程思想?理解原理,快速成長
    今天我們主要來學習一下面向對象的編程思想是什麼?如何從原理上來學習達到快速成長的效果,能夠運用各種程式語言開發軟體項目。首先,我們來了解一下學習面向對象編程需要具備哪些基礎。也就是說我們學習面向對象的編程都有哪些概念,以及如何把我們的編程思想逐步轉變成一種面向對象的思想來考慮問題,是今天我們要學習的核心內容。什麼是面向對象?
  • Python面向對象編程的基本概念
    名為Simula的語言是第一種具有面向對象編程功能的程式語言。它是在1967年開發的,用於製作仿真程序,其中最重要的信息稱為對象。之後,這種編程技術已被包括Python在內的各種程式語言所採用,如今它的應用幾乎遍及各個領域,例如實時系統,人工智慧和專家系統,客戶端伺服器系統,面向對象的資料庫以及許多其他領域。更多。因此,在本文中,我將解釋Python中的面向對象編程的基本概念。
  • 深入淺出理解面向過程與面向對象編程
    前言有過編程的經歷的讀者可能經常會聽到面向過程編程和面向對象編程,然後你是否去深入了解過這兩個概念,它們之間有什麼區別,下面我就來簡單介紹一下。面向過程會要求去掌控每一個細節,而面向對象則只需要挑選合適的工具即可。
  • Python面向對象編程的一些見解
    另外,我們也需要一種學習方法保持我們的學習熱情, Python作為一門程式語言,涉及很多領域,所以它也包含了眾多的知識點,不同的領域涉及到的知識點也有所不同。正文:閒話說完,進入正題,Python語言是一門面向對象的語言,今天我們就講一下什麼是面向對象。面向對象編程已經成為一種現代程式設計師不可或缺的技能。那到底什麼是面向對象編程呢?這讓很多初學者不是很理解,進而導致他們放棄深入學習編程。
  • 詳解Python面向對象知識點
    目前代碼技能已經成了測試同學面試考核的剛需,對於測試開發來講需求最大的是java和python兩門語言,二者也都是面向對象語言。對於剛入門代碼的同學來說面向對象相關的概念比較難於理解,而面向對象編程相關的知識點偏偏又是面試中的高頻問題,所以本文我以python為例,帶大家快速搞定面向對象中的核心概念並通過代碼實現的方式來幫助大家對其加深理解!
  • 面向對象的程式語言
    在剛開始介紹到JAVA時,我們就提到說JAVA是一種面向對象的程式語言。我們在代碼編寫的時候用到的說到的最多的就是new一個對象,那麼什麼是對象,面向對象有哪些特點,與面向過程的編程有什麼區別。對象和類的理解萬物皆對象,現實世界是由很多很多對象組成的,我們可以理解為每一種事物就是一個對象,對象就是事物存在的個體。比如一輛車、一個人等都是一個對象。每一個對象都有屬於自己的屬性和行為方法,如人類都有自己的姓名、性別、年齡等屬性,還會有學習、工作等屬性。不過不同的對象有著不同的屬性。類定義了一種抽象數據類型,代表了一個類別,一類個體。
  • opencv-python獲取圖像:面向對象與面向過程
    下面是分別用面向過程與面向對象的編程方法實現讀取本地圖像和打開攝像頭兩段代碼:# -*- coding: utf-8 -*-"""面向過程的編程方法,用函數把解決問題的步驟一步一步實現。運行環境:win10系統 python==3.6 opencv-contrib-python== 4.1.0第一行「# -*- coding: utf-8 -*-」 告訴Python解釋器,按照UTF-8編碼讀取原始碼"""import cv2image=cv2.imread('lena.JPG') #讀取本地圖片,
  • 趣味解讀Python面向對象編程 (類和對象)
    面向過程:根據業務邏輯從上到下寫代碼。面向對象:將數據與函數綁定到一起,進行封裝,這樣能夠更快速的開發程序,減少了重複代碼的重寫過程。面向過程編程最易被初學者接受,其往往用一長段代碼來實現指定功能,開發過程的思路是將數據與函數按照執行的邏輯順序組織在一起,數據與函數分開考慮。
  • python面向對象這些概念不了解你怎麼學
    在常見的編程範式裡面有兩種比較常用的,一種是函數式編程、一種是面向對象, 面向對象是一個非常大的話題,筆者不敢亂言, 本文只是面向對象一些概念的理解,然後聊聊復用這回事廣義上類的組成在之前的文章中函數介紹中提過,函數是一個控制抽象,同時也提到面向對象是數據抽象, 其實從上面我們可以看出
  • 資料|Python面向對象編程課件
    from=leiphonecolumn_res0928內容簡介Python從設計之初就已經是一門面向對象的語言,正因為如此,在Python中創建一個類和對象是很容易的。如果你以前沒有接觸過面向對象的程式語言,那你可能需要先了解一些面向對象語言的一些基本特徵,在頭腦裡頭形成一個基本的面向對象的概念,這樣有助於你更容易的學習Python的面向對象編程。
  • python核心部分創建對象中各種名詞的定義及用法
    但是python被稱為面向對象的語言,所以創建對象才是python的核心部分,我們今天就走進python的核心部分-創建對象。接下來幾天的章節非常重要非常核心,非常重要非常核心,非常重要非常核心,重要的事情說是三次。首先說一下幾個名詞的定義,方便你在以後的學習中理解。對象(object):包括特性和方法。
  • 如何使用JavaScript -面向對象編程
    學習目標理解面向對象開發思想掌握 JavaScript 面向對象開發相關模式面向對象介紹什麼是對象Everything is object (一切皆對象)我們可以從兩個層次來理解對象:(1) 對象是單個事物的抽象。
  • 在.NET中,C#舉例深度理解面向對象編程中的封裝、繼承和多態
    C#核心開發-第15單元-接口和繼承-第6節:面向對象編程C#核心開發-面向對象編程1. 什麼是面向對象編程?我們在沒有接觸類之前,所有的代碼都是堆在一起的,沒有面向對象的概念,但接觸了類/對象/繼承/接口之後,我們要建立自己的面向對象編程的概念,在編碼過程中,要讓自己編寫的程序是面向對象的,而不是堆代碼。微軟在.NET框架中推出的C#語言是面向對象的強類型程式語言。
  • 初識Python面向對象
    面向對象or面向過程面向對象編程——Object Oriented Programming,簡稱OOP,是一種程序設計思想。OOP把對象作為程序的基本單 元,一個對象包含了數據和操作數據的函數。面向過程的程序設計把電腦程式視為一系列的命令集合,即一組函數的順序執行。
  • 面向對象的工業編程(OOIP)
    本文將展示其中一種工具的示例,展示工程師如何通過掌握一小部分OOP概念來利用這些好處,並展示如何使用對象進行編程是一種自然而直觀的技術,用於控制基於對象的物理世界。為了避免在本文中造成混淆,我們將把工業控制項解釋稱為面向對象的工業編程(OOIP),並將其區別如下: 面向對象編程(OOP)包括完整的計算機科學OOP功能主要基於文本
  • 如何理解Python類中的self?
    許多python初學者,在接觸到python面向對象的時候,就被類中包含的方法中的self打敗了,不知道self是何物?既然寫在方法中,是必須參數,為何在調用方法的時候不給它傳參數還能正常運行?和我們前面學的函數傳參這塊矛盾麼?勇哥在這裡給慢慢大家揭開self的神秘面紗。
  • 當談論面向對象的時候,要搞清編程和語言的關係
    面向對象程式語言是支持類或對象的語法機制,並有現成的語法機制,能方便地實現面向對象編程四大特性(封裝、抽象、繼承、多態)的程式語言。寫出來的代碼也不一定是面向對象編程風格的,也有可能是面向過程編程風格。除此之外,從定義中,我們還可以發現,理解面向對象編程及面向對象程式語言兩個概念,其中最關鍵的一點就是理解面向對象編程的四大特性。
  • 面向過程和面向對象程式語言有何不同
    首先,面向對象程式語言和面向過程程式語言都是操作計算機的方式,從本質上來說也都是操作計算機執行任務的工具,只是方式上的不同而已。面向過程程式語言故名思議,以業務流程為考慮問題的出發點,從上到下按照解決問題的流程來組織代碼結構,把功能封裝成函數,然後依次調用就可以了。
  • 面向對象編程
    面向對象編程(OOP)對於初學者來說可能是一個很難理解的概念。很多書籍都是從解釋OOP開始,討論三大術語:封裝、繼承和多態性,但是解釋的效果往往讓人失望。本文希望讓程式設計師、數據科學家和python愛好者們更容易理解這個概念。我們去掉所有的行話,通過一些例子來做解說。這篇文章是關於解釋OOP的外行方式。