面向對象編程


面向對象編程

23、面向對象編程

一. 對象的概念

”面向對象“的核心是“對象”二字,而對象的精髓在於“整合“,什么意思?

所有的程序都是由“數據”與“功能”組成,因而編寫程序的本質就是定義出一系列的數據,然后定義出一系列的功能來對數據進行操作。在學習“對象”之前,程序中的數據與功能分離開的,如下

#數據:name,age,sex
name='lili'
age=18
sex='female'

#功能:tell_info
def tell_info(name,age,sex):
   print('<%s:%S:%s>' %(name,age,sex))
   
#此時若想執行查看個人信息的功能,需要同時拿到兩樣東西,一類是功能tell_info,另一類則是多個數據name,age,sex,然后才能執行,非常麻煩
tell_info(name,age,sex)

在學習了“對象”之后,我們就有了一個容器,該容器可以盛放數據與功能,所以我們可以說:對象是把數據與功能整合到一起的產物,或者說”對象“就是一個盛放數據與功能的容器/箱子/盒子。

在了解了對象的基本概念之后,理解面向對象的編程方式就相對簡單很多了,面向對象編程就是要造出一個個的對象,把原本分散開的相關數據與功能整合到一個個的對象里,這么做既方便使用,也可以提高程序的解耦合程度,進而提升了程序的可擴展性(需要強調的是,軟件質量屬性包含很多方面,面向對象解決的僅僅只是擴展性問題)

img

二. 類與對象

類即類別/種類,是面向對象分析和設計的基石,如果多個對象有相似的數據與功能,那么該多個對象就屬於同一種類。有了類的好處是:我們可以把同一類對象相同的數據與功能存放到類里,而無需每個對象都重復存一份,這樣每個對象里只需存自己獨有的數據即可,極大地節省了空間。所以,如果說對象是用來存放數據與功能的容器,那么類則是用來存放多個對象相同的數據與功能的容器。

img

綜上所述,雖然我們是先介紹對象后介紹類,但是需要強調的是:在程序中,必須要事先定義類,然后再調用類產生對象(調用類拿到的返回值就是對象)。產生對象的類與對象之間存在關聯,這種關聯指的是:對象可以訪問到類中共有的數據與功能,所以類中的內容仍然是屬於對象的,類只不過是一種節省空間、減少代碼冗余的機制,面向對象編程最終的核心仍然是去使用對象。

三. 面向對象編程

3.1 類的定義與實例化

我們以開發一個清華大學的選課系統為例,來簡單介紹基於面向對象的思想如何編寫程序。面向對象的基本思路就是把程序中要用到的、相關聯的數據與功能整合到對象里,然后再去使用,但程序中要用到的數據以及功能那么多,如何找到相關連的呢?我需要先提取選課系統里的角色:學生、老師、課程等,然后顯而易見的是:學生有學生相關的數據於功能,老師有老師相關的數據與功能,我們單以學生為例,

#學生的數據有
學校
名字
年齡
性別

#學生的功能有
選課

詳細的

# 學生1:
  數據:
      學校=清華大學
      姓名=李建剛
      性別=男
      年齡=28
  功能:
      選課

# 學生2:
  數據:
      學校=清華大學
      姓名=王大力
      性別=女
      年齡=18
  功能:
      選課

# 學生3:
  數據:
      學校=清華大學
      姓名=牛嗷嗷
      性別=男
      年齡=38
  功能:
      選課

我們可以總結出一個學生類,用來存放學生們相同的數據與功能

#學生類
相同的特征:
學校=清華大學
相同的功能:
選課

基於上述分析的結果,我們接下來需要做的就是在程序中定義出類,然后調用類產生對象

class Student: #類的命名應該使用“駝峰體”
   school='清華大學' #數據
   
   def choose(self): #功能
       print('%s is choosing a course' %self.name)

類體最常見 的是變量的的定義和函數的定義,但其實類體可以包含任意python代碼,類體的代碼在類定義階段就會執行,因而會產生新的名稱空間用來存放類中定義的名字,可以打印Student.__ dict __來查看類這個盛放的東西

print(Student.__dict__)
>>>{..., 'school': '清華大學', 'choose': <function Student.choose at 0x1018a2950>, ...}

調用類的過程稱為將類實例化,拿到的返回值就是程序中的對象,或稱為一個實例

stu1=Student() # 每實例化一次Student類就得到一個學生對象
stu2=Student()
stu3=Student()

如此stu1、stu2、stu3全都一樣了(只有類中共有的內容,而沒有各自獨有的數據),想在實例化的過程中就為三位學生定制各自獨有的數據:姓名,性別,年齡,需要我們在類內部新增一個__ init __方法,該方法是在對象產生之后才會執行,只用來為對象進行初始化操作。可以有任意代碼,但一定不能有返回值。如下

class Student:
school='清華大學'
   
   #該方法會在對象產生后自動執行,專門為對象進行初始化操作,可以有任意代碼,但一定不能返回非None的值
   def __init__(self,name,sex,age):
       self.name=name
       self.sex=sex
       self.age=age
       
   def choose(self):
       print('%s is choosing a course' %self.name)

然后我們重新實例出三位學生

stu1=Student('李建剛','男',28)
stu2=Student('王大力','女',18)
stu3=Student('牛嗷嗷','男',38)

單拿stu1的產生過程來分析,調用類會先產生一個空對象stu1,然后將stu1連同調用類時括號內的參數一起傳給Student.__ init __(stu1,’李建剛’,’男’,28)

def __init__(self,name,sex,age):
self.name=name #stu1.name='李建剛'
self.sex=sex #stu1.sex='男'
self.age=age #stu1.age=28

會產生對象的名稱空間,同樣可以用__ dict __查看

print(stu1.__dict__)

>>>{'name': '李建剛', 'sex': '男', 'age': 28}

至此,我們造出了三個對象與一個類,對象存放各自獨有的數據,類中存放對象們共有的內容

img

3.2 屬性訪問

3.2.1 類屬性與對象屬性

在類中定義的名字,都是類的屬性,細說的話,類有兩種屬性:數據屬性和函數屬性,可以通過__ dict __訪問屬性的值

print(Student.school)	#訪問數據屬性,等同於Student.__dict__['school']
>>>'清華大學'

print(Student.choose) #訪問函數屬性,等同於Student.__dict__['choose']
>>><function Student.choose at 0x1018a2950>
#除了查看屬性外,我們還可以使用Student.attrib=value(修改或新增屬性),用del Student.attrib刪除屬性。

操作對象的屬性也是一樣

print(stu1.name)	#查看,等同於obj.__dict__['name']
>>>'李建剛'

print(stu1.course='python') #新增,等同於obj1.__dict__['course']='python'

print(stu1.age=18) #修改,等同於obj1.__dict__['age']=18

del obj1.course #刪除,等同於del obj1.__dict__['course']

3.2.2 屬性查找順序與綁定方法

對象的名稱空間里只存放着對象獨有的屬性,而對象們相似的屬性是存放於類中的。對象在訪問屬性時,會優先從對象本身中查找,未找到,則去類中查找。

1、類中定義的變量是類的數據屬性,是共享給所有對象用的,指向相同的內存地址

#id都是一樣
print(id(Student.school)) #4301108704

print(id(stu1.school)) #4301108704
print(id(stu2.school)) #4301108704
print(id(stu3.school)) #4301108704

2、類中定義的函數是類的函數屬性,類可以使用,但必須遵循函數的參數規則,有幾個參數需要傳幾個參數

Student.choose(stu1) # 李建剛 is choosing a course
Student.choose(stu2) # 王大力 is choosing a course
Student.choose(stu3) # 牛嗷嗷 is choosing a course

但其實類中定義的函數主要是給對象使用的,而且是綁定給對象的,雖然所有對象指向的都是相同的功能,但是綁定到不同的對象就是不同的綁定方法,內存地址各不相同

print(id(Student.choose)) # 4335426280

print(id(stu1.choose)) # 4300433608
print(id(stu2.choose)) # 4300433608
print(id(stu3.choose)) # 4300433608

綁定到對象的方法特殊之處在於,綁定給誰就應該由誰來調用,誰來調用,就會將’誰’本身當做第一個參數自動傳入(方法__ init __也是一樣的道理)

stu1.choose()  # 等同於Student.choose(stu1)
stu2.choose() # 等同於Student.choose(stu2)
stu3.choose() # 等同於Student.choose(stu3)

綁定到不同對象的choose技能,雖然都是選課,但李建剛選的課,不會選給王大力,這正是”綁定“二字的精髓所在。

#注意:綁定到對象方法的這種自動傳值的特征,決定了在類中定義的函數都要默認寫一個參數self,self可以是任意名字,但命名為self是約定俗成的。

Python中一切皆為對象,且Python3中類與類型是一個概念,因而綁定方法我們早就接觸過

#類型list就是類
>>> list
<class 'list'>

#實例化的到3個對象l1,l2,l3
>>> l1=list([1,2,3])
>>> l2=list(['a','b','c'])
>>> l3=list(['x','y'])

#三個對象都有綁定方法append,是相同的功能,但內存地址不同
>>> l1.append
<built-in method append of list object at 0x10b482b48>
>>> l2.append
<built-in method append of list object at 0x10b482b88>
>>> l3.append
<built-in method append of list object at 0x10b482bc8>

#操作綁定方法l1.append(4),就是在往l1添加4,絕對不會將4添加到l2或l3
>>> l1.append(4) #等同於list.append(l1,4)
>>> l1
[1,2,3,4]
>>> l2
['a','b','c']
>>> l3
['x','y']

3.2.3 小結

在上述介紹類與對象的使用過程中,我們更多的是站在底層原理的角度去介紹類與對象之間的關聯關系,如果只是站在使用的角度,我們無需考慮語法“對象.屬性"中”屬性“到底源自於哪里,只需要知道是通過對象獲取到的就可以了,所以說,對象是一個高度整合的產物,有了對象,我們只需要使用”對象.xxx“的語法就可以得到跟這個對象相關的所有數據與功能,十分方便且解耦合程度極高。

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM