面向對象,類的引入

面向對象

編程方式

  • 面向過程
  • 函數式編程
  • 面向對象

面向過程

  • 之前所用的,按照解決問題的步驟,一步步的按流程進行,有先後之分。整個設計流水線式的,思維比較機械化。

  • 優缺點:

    • 優點 : 複雜的問題流程化,將問題分解簡化。
    • 缺點:拓展性不足

面向對象

定義

核心是對象.對象是一個數據以及其相關行爲的集合,

面對對象是功能上指向建模對象,通過數據和行爲方式來描述交互對象的集合.

在python中,一切皆爲對象.

優缺點
  • 優點

可以解決程序的拓展性

  • 缺點

就是複雜度遠高於面向過程.

交互式解決問題無法準確預測結果

內容
  • 類(Class): 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例。
  • **方法:**類中定義的函數。
  • **類變量:**類變量在整個實例化的對象中是公用的。類變量定義在類中且在函數體之外。類變量通常不作爲實例變量使用。
  • **數據成員:**類變量或者實例變量用於處理類及其實例對象的相關的數據。
  • **方法重寫:**如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆蓋(override),也稱爲方法的重寫。
  • **局部變量:**定義在方法中的變量,只作用於當前實例的類。
  • **實例變量:**在類的聲明中,屬性是用變量來表示的。這種變量就稱爲實例變量,是在類聲明的內部但是在類的其他成員方法之外聲明的。
  • **繼承:**即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作爲一個基類對象對待。例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關係(例圖,Dog是一個Animal)。
  • **實例化:**創建一個類的實例,類的具體對象。
  • **對象:**通過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法。

舉例

object1:Tom
   特徵:
     scool=zucc
     name=tom
     age=21
     sex=male
     技能:ballgame  study ...
object2:Bob
     scool=zucc
     name=bob
     age=22
     sex=male
     技能:tennis  study ...

類就是類別,種類.

對象就是特徵和技能的統一體.

類就是這一系列相似對象的特徵和技能的結合.

對應現實生活,先有個體(對象),纔有類別;但是對於程序,必須先有類,然後纔有對象.

面向對象編程引入

定義

OOP(object oriented programming)即面向對象編程

是一種程序設計思想.OOP把對象作爲程序的一個基本單元,一個對象就包含了數據和操作數據的函數.

在python中,所有數據類型都可以視爲對象,當然也可以自定義對象.

自定義對象的數據類型就是面向對象中類的概念

舉例

如要處理我們的成績.爲了表示學生的成績:

  • 面向過程的方式
st1={'name':'jack','score':80}
st2={'name':'bob','score':97}...
def show_score(st):
	print(st['name'],st['score'])
show(st1)
  • 面向對象
class student:
    def __init__(self,name,score):
        self.name=name
        self.score=score
    def show_score(self):
        print(self.name,':',self.score)
st1=student('bob',97)
st1.show_score()

類的定義

面向對象設計的思想,先抽象出類,再根據類創建實例.

命名類名時 變量名稱各個單詞首字母大寫

創建一個空類

class MyFirstClass:
	pass

創建一個普通類

class ClassName(object):
	'''dicstring(說明文檔)'''
	class_statement
class Student:
    school='ZUCC'#所有對象的固有屬性
    def __init__(self,name,score):
        self.name=name
        self.score=score
    def show_score(self):
        print(self.name,':',self.score)
st1=Student('bob',97)#實例化
print((st1.name,st1.score,st1.school))
('bob', 97, 'ZUCC')
總結

類的作用是一個模板.我們可以在創建實例的時候,把一些我們認爲必須要綁定的屬性填寫進去.這時就通過特殊的__init__方法.在創建實例的時候,綁定相關的屬性.

和普通函數相比,在類中定義方法時,第一個參數必須是self.除第一個參數外,其他的與普通函數沒有什麼區別.

self代表的是實例,而非類

__init__方法

  • 爲對象初始化自己獨有的特徵
  • 該方法中可以有任意的代碼,但是不能有返回值
數據封裝
class Student:
    school='ZUCC'#所有對象的固有屬性
    def __init__(self,name,score):
        self.name=name
        self.score=score
st1=Student('bob',97)#實例化

我們通過__init__st1實例本身有了相關的數據,我們可以直接在Student類的內部定義相關的函數來訪問數據,以此封裝數據.

這些封裝數據的函數和Student類本身是關聯起來的,他們被稱之爲方法.

類的兩個作用

  • 類名引用

    • 類名.屬性
  • 實例化

​ 類名加上一個括號就是實例化,它能夠自動觸發__init__函數,進而爲每個實例定製自己的特徵

  • 類屬性的補充

類屬性的查看

  • dir()來查看對應類包含的屬性(返回列表)

  • 類名.__dict__返回一個字典,key爲屬性名,value爲屬性值

特殊的類屬性

類名.__name__返回類的名字

類名.__doc__返回類的文檔字符串

類名.__base__返回類的第一個父類

類名.__bases__返回類的所有父類(元組)

類名.__module__返回類定義所在的模塊

類名.__class__返回實例對應的類

對象之間的交互

定義2個類,Person,Dog,都有體力及攻擊值,可以進行攻擊

class Person:
    def __init__(self,name,aggressivity,life_value):
        self.name=name
        self.aggre=aggressivity
        self.life_values=life_value
    def attack(self,dog):
        dog.life_values-=self.aggre

class Dog:
    def __init__(self,name,breed,aggressivity,life_vale):
        self.name=name
        self.breed=breed
        self.aggre=aggressivity
        self.life_values=life_vale
    def bite(self,people):
        people.life_values-=self.aggre

per=Person('bob',10,888)
dog=Dog('white','husky',12,480)
print('dog:',dog.life_values,',person:',per.life_values,sep='')
per.attack(dog)
dog.bite(per)
print('dog:',dog.life_values,',person:',per.life_values,sep='')

dog:480,person:888
dog:470,person:876

類命名空間與對象實例的空間

創建一個類就會創建一個類的名稱空間,用來存儲我們定義的所有的變量名。這些名字就是屬性。

類的屬性有兩種

  • 靜態 :直接在類中定義的變量

  • 動態 : 在類中定義的方法

靜態屬性是共享給所有對象的,動態屬性是綁定到所有對象的

class Student:
    school='ZUCC'#所有對象的固有屬性(靜態)
    def __init__(self,name,score):
        self.name=name
        self.score=score
    def find_score(self): ##(動態)
        print(self.name,":",self.score)
st1=Student('bob',95)
st2=Student('jack',89)
print(id(st1.school),id(st2.school))
print(id(st1.find_score),id(st2.find_score),id(Student.find_score

4365888 4365888
4014768 4014768 12138368

類的三大特性

繼承

在面向對象編程中,當我們定義一個新的類後,可以從某個現有的類,繼承,新的類就被稱爲子類

SubClass,而被繼承的類則被稱爲基類,父類,超累(Base Class,Father Class,Super Class)

#定義一個動物類(Animal),它有一個run()方法
class Animal:  #定義父類
    def run(self):
        print('Animal is running.')
class Dog(Animal): #括號內爲所繼承的類
    pass
class Cat(Animal): #單繼承
    pass
class Husky(Animal,Dog): #多繼承用逗號分隔開
    pass
Dog().run()    #繼承Animal的run
Cat().run()
print(Dog.__bases__) #查看該類繼承的父類
print(Animal.__bases__)

Animal is running.
Animal is running.
(<class '__main__.Animal'>,)
(<class 'object'>,)

如果不指定類,python類會默認繼承object類

object是所有python類的基類,提供一些常見方法的實現

多態

當子類和父類存在相同名稱的方法時,子類的方法會覆蓋父類的方法,在運行代碼時,總會調用子類的方法。

這樣就是繼承的另外一個好處,多態。

理解多態,首先要對數據類型再進行說明。定義一個類的時候實際上就是定義了一種數據類型。我們自定義的數據類型和python自帶的數據類型(str,list,dict)等相同。

class Animal:
    def run(self):
        print('Animal is running.')
class Dog(Animal):
    def run(self):
        print('Dog is Running')
class Cat(Animal):
    def run(self):
        print('Cat is Running')

dog=Dog()
cat=Cat()
dog.run()
cat.run()

Dog is Running
Cat is Running
###isinstance判斷所給的對象是不是所給的數據類型
li=[]
print(isinstance(li,list))
print(isinstance(dog,Animal))
print(isinstance(Dog,object))
True
True
True

對於一個變量,只要知道其父類型,無需確切知道其子類型,就可以調用相關的方法。運行時具體的方法是作用於子類型上還是作用於父類型上,由我們運行的對象決定。也就是說,在調用時只管調用,無需注意細節

當我們新增一個子類時,只要保證相關的方法編寫正確,就不用再管原來的代碼是怎麼調用的

開閉原則
  • 對拓展開放:允許新增子類
  • 對修改封閉:不需要修改依賴父類類型的函數
總結

繼承可以一級一級的繼承下來

任何類都可以追溯到根類object

私有屬性

在類的內部,可以有屬性和方法,而外部代碼就可以通過直接調用實例變量的方法來操作數據.這樣,隱藏了內部的複雜邏輯

class Student:
    school='ZUCC'#所有對象的固有屬性(靜態)
    def __init__(self,name,score):
        self.name=name
        self.score=score
    def find_score(self): ##(動態)
        print(self.name,":",self.score)
st1=Student('bob',95)
st1.find_score()
st1.score=92
st1.find_score()

bob : 95
bob : 92

由上可知,外部代碼可以自由修改一個實例的屬性(name,score).

如果要讓內部屬性不被外部訪問,我們可以在屬性名稱前面加__(2個下劃線.)

在python中如果實例的變量名以雙下劃線開頭,就變成了一個私有變量,只允許內部訪問.

class Student:
    school='ZUCC'#所有對象的固有屬性(靜態)
    def __init__(self,name,score):
        self.name=name
        self.__score=score
    def find_score(self): ##(動態)
        print(self.name,":",self.__score)
st1=Student('bob',95)
st1.find_score()
print(st1.name)
print(st1.__score)
bob : 95 #成績只能通過內部函數訪問
bob    #可以直接外部訪問
AttributeError: 'Student' object has no attribute '__score' #報錯,無法直接無法及更改分數

如果想要更改私有變量,可以通過在類內定義更改該變量的函數,再在外部調用函數

class Student:
    school='ZUCC'#所有對象的固有屬性(靜態)
    def __init__(self,name,score):
        self.name=name
        self.__score=score
    def find_score(self): ##(動態)
        print(self.name,":",self.__score)
    def change_score(self,score):
        self.__score=score
st1=Student('bob',17)
st1.find_score()
st1.change_score(89)
st1.find_score()

bob : 17
bob : 89
########注:並非絕對無法從外部訪問私有變量
print(st1._Student__score)
89
#可以以以上方式訪問私有屬性,但是不推薦這種方式.

封裝

定義

隱藏對象的屬性和實現細節,僅對外提供公共訪問的方式

優點
  • 可以將變化隔離
  • 便於使用
  • 提高安全性
  • 提高複用性
原則
  • 將不需要對外提供的內容隱藏

  • 隱藏屬性,提供公共方法對其進行訪問

————>私有方法,私有變量------->私有屬性

用雙下劃線開頭標記私有屬性

鴨子類型

解釋

關於鴨子類型,在百科中是這麼描述的:“鴨子類型”的語言是這麼推斷的:一隻鳥走起來像鴨子、遊起泳來像鴨子、叫起來也像鴨子,那它就可以被當做鴨子。也就是說,它不關注對象的類型,而是關注對象具有的行爲(方法)。對於C++來說,我們要調用某個以類A爲參數的函數,則我們傳入的類型必須是類A類型,或者是類A的子類類型。但在Python中,卻沒有這個要求,它只要求我們在函數體中實現部分,在類B中同樣也能實現,那麼B就能傳入函數中。

class obj1:
   def run(self):
       print('this is first')
class obj2:
   def run(self):
       print('this is second')
def runs(obj1):
   obj1.run()
StuA=obj1()
runs(StuA)
infA=obj2()
runs(infA)

this is first
this is second
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章