1. 程式人生 > >第7章 面向對象

第7章 面向對象

python

面向過程的程序設計把計算機程序視為一系列的命令集合,即一組函數的順序執行。為了簡化程序設計,面向過程把函數繼續切分為子函數,即把大塊函數通過切割成小塊函數來降低系統的復雜度。


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


假設我們要處理學生的成績表,為了表示一個學生的成績,面向過程的程序可以用一個dict表示:


std1 = { ‘name‘: ‘Michael‘, ‘score‘: 98 }

std2 = { ‘name‘: ‘Bob‘, ‘score‘: 81 }


而處理學生成績可以通過函數實現,比如打印學生的成績:


def print_score(std):

print(‘%s: %s‘ % (std[‘name‘], std[‘score‘]))


如果采用面向對象的程序設計思想,我們首選思考的不是程序的執行流程,而是Student這種數據類型應該被視為一個對象,這個對象擁有name和score這兩個屬性(Property)。如果要打印一個學生的成績,首先必須創建出這個學生對應的對象,然後,給對象發一個print_score消息,讓對象自己把自己的數據打印出來。


class Student(object):


def __init__(self, name, score):

self.name = name

self.score = score


def print_score(self):

print(‘%s: %s‘ % (self.name, self.score))


給對象發消息實際上就是調用對象對應的關聯函數,我們稱之為對象的方法(Method)。面向對象的程序寫出來就像這樣:


bart = Student(‘Bart Simpson‘, 59)

lisa = Student(‘Lisa Simpson‘, 87)

bart.print_score()

lisa.print_score()




類與實例:

面向對象最重要的概念就是類(Class)和實例(Instance),必須牢記類是抽象的模板,比如Student類,而實例是根據類創建出來的一個個具體的“對象”,每個對象都擁有相同的方法,但各自的數據可能不同。


仍以Student類為例,在Python中,定義類是通過class關鍵字:


class Student(object):

pass


class後面緊接著是類名,即Student,類名通常是大寫開頭的單詞,緊接著是(object),表示該類是從哪個類繼承下來的,繼承的概念我們後面再講,通常,如果沒有合適的繼承類,就使用object類,這是所有類最終都會繼承的類。


定義好了Student類,就可以根據Student類創建出Student的實例,創建實例是通過類名+()實現的:


>>> bart = Student()

>>> bart

<__main__.Student object at 0x10a67a590>

>>> Student

<class ‘__main__.Student‘>


可以看到,變量bart指向的就是一個Student的實例,後面的0x10a67a590是內存地址,每個object的地址都不一樣,而Student本身則是一個類。


可以自由地給一個實例變量綁定屬性,比如,給實例bart綁定一個name屬性:


>>> bart.name = ‘Bart Simpson‘

>>> bart.name

‘Bart Simpson‘


由於類可以起到模板的作用,因此,可以在創建實例的時候,把一些我們認為必須綁定的屬性強制填寫進去。通過定義一個特殊的__init__方法,在創建實例的時候,就把name,score等屬性綁上去:


class Student(object):


def __init__(self, name, score):

self.name = name

self.score = score




註意到__init__方法的第一個參數永遠是self,表示創建的實例本身,因此,在__init__方法內部,就可以把各種屬性綁定到self,因為self就指向創建的實例本身。


有了__init__方法,在創建實例的時候,就不能傳入空的參數了,必須傳入與__init__方法匹配的參數,但self不需要傳,Python解釋器自己會把實例變量傳進去:


>>> bart = Student(‘Bart Simpson‘, 59)

>>> bart.name

‘Bart Simpson‘

>>> bart.score

59


和普通的函數相比,在類中定義的函數只有一點不同,就是第一個參數永遠是實例變量self,並且,調用時,不用傳遞該參數。除此之外,類的方法和普通函數沒有什麽區別,所以,你仍然可以用默認參數、可變參數、關鍵字參數和命名關鍵字參數




類的屬性:

# class OldboyStudent:

# school = ‘oldboy‘ #類的數據屬性

# def learn(self): #類的函數屬性

# print(‘is learning‘)

#

# def eat(self):

# print(‘is eating‘)

# print(‘======>‘)




#類體的代碼在類定義階段就會執行,理所應當會產生類的名稱空間,用__dict__屬性查看

# print(OldboyStudent.__dict__)

# print(OldboyStudent.__dict__[‘school‘])

# print(OldboyStudent.__dict__[‘learn‘])



#類的屬性操作

# print(OldboyStudent.school)

# print(OldboyStudent.learn)


#

# def func():pass

# print(func)

# OldboyStudent.learn(123)


# OldboyStudent.x=1111111111111111111111

# OldboyStudent.school=‘Oldboy‘

# del OldboyStudent.school

# print(OldboyStudent.__dict__)


# OldboyStudent.__dict__[‘x‘]=1111111111111111111111




#產生程序中的對象:類名加括號,調用類,產生一個該類的實際存在的對象,該調用過程稱為實例化,產生的結果又可以成為實例

# class OldboyStudent:

# school = ‘oldboy‘

# #obj1,‘李大炮‘,18,‘女‘

# def __init__(self,name,age,sex): #在實例化時,產生對象之後執行

# # if not isinstance(name,str):

# # raise TypeError(‘名字必須是字符串類型‘)

# self.name=name

# self.age=age

# self.sex=sex

# # return None #__init__方法必須返回None

# #obj1.name=‘李大炮‘

# #obj1.age=18

# #obj1.sex=‘女‘

#

# def learn(self):

# print(‘is learning‘)

#

# def eat(self):

# print(‘is eating‘)


# obj1=OldboyStudent(‘李大炮‘,18,‘女‘) #

# 分兩步:

# 第一步:先產生一個空對象obj1

# 第二步:OldboyStudent.__init__(obj1,‘李大炮‘,18,‘女‘)

# print(obj1.__dict__)

#

# obj2=OldboyStudent(‘張全蛋‘,28,‘男‘)

# obj3=OldboyStudent(‘牛榴彈‘,18,‘女‘)

#

# print(obj2.__dict__)

# print(obj3.__dict__)

#

#

#

# print(obj1.name)#obj1.__dict__[‘name‘]

#

# obj1.name=‘大炮‘

# print(obj1.__dict__)

# obj1.__dict__[‘name‘]=‘炮‘

# print(obj1.name)

#

# obj1.__dict__.pop(‘name‘)

# # print(obj1.name)

# print(obj1.__dict__)




#繼承的基本形式

當我們定義一個class的時候,可以從某個現有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)。

定義

# class ParentClass1(object): #定義父類

# pass

#

# class ParentClass2: #定義父類

# pass

#

# class SubClass1(ParentClass1): #單繼承,基類是ParentClass1,派生類是SubClass

# pass

#

# class SubClass2(ParentClass1,ParentClass2): #python支持多繼承,用逗號分隔開多個繼承的類

# pass

#

#

#

#

# print(SubClass1.__bases__)

# print(SubClass2.__bases__)

# print(ParentClass1.__bases__)


比如,我們已經編寫了一個名為Animal的class,有一個run()方法可以直接打印:


class Animal(object):

def run(self):

print(‘Animal is running...‘)


當我們需要編寫Dog和Cat類時,就可以直接從Animal類繼承:


class Dog(Animal):

pass


class Cat(Animal):

pass


對於Dog來說,Animal就是它的父類,對於Animal來說,Dog就是它的子類。Cat和Dog類似。


繼承有什麽好處?最大的好處是子類獲得了父類的全部功能。由於Animial實現了run()方法,因此,Dog和Cat作為它的子類,什麽事也沒幹,就自動擁有了run()方法:


dog = Dog()

dog.run()


cat = Cat()

cat.run()


運行結果如下:


Animal is running...

Animal is running..




子類方法重用父類的功能

# class OldboyPeople:

# school = ‘oldboy‘

# def __init__(self,name,age,sex):

# self.name=name

# self.age=age

# self.sex=sex

#

# def eat(self):

# print(‘is eating‘)

# def teach(self):

# print(‘這是父類的teach‘)

#

# class OldboyTeacher(OldboyPeople):

# def __init__(self,name,age,sex,salary,title):

# # OldboyPeople.__init__(self,name,age,sex)

# #在Python2中需要寫全:super(OldboyTeacher,self)

# super().__init__(name,age,sex)

# self.salary=salary

# self.title=title

#

# def teach(self):

# # OldboyPeople.teach(self)

# super().teach()

# print(‘%s is teaching‘ %self.name)

# print(OldboyTeacher.mro())

#

# egon_obj=OldboyTeacher(‘egon‘,18,‘male‘,3.1,‘沙河霸道金牌講師‘)

# # print(egon_obj.title)

# # print(egon_obj.__dict__)

# egon_obj.teach()




總結:

1 繼承的功能之一:解決類與類之間的代碼重復問題

2 繼承是類與類之間的關系,是一種,什麽是什麽的關系

3 在子類派生出的新的屬性,已自己的為準

4 在子類派生出的新的方法內重用父類的功能的方式:指名道姓法OldboyPeople.__init__

這種調用方式本身與繼承是沒有關系


第7章 面向對象