1. 程式人生 > >Python基礎(16)_面向對象程序設計(類、繼承、派生、組合、接口)

Python基礎(16)_面向對象程序設計(類、繼承、派生、組合、接口)

特征 abc 有效 相同 現實 父類 student 需求 ict

一、面向過程程序設計與面向對象程序設計

面向過程的程序設計:核心是過程,過程就解決問題的步驟,基於該思想設計程序就像是在設計一條流水線,是一種機械式的思維方式
優點:復雜的問題的簡單化,流程化
缺點:擴展性差

面向對象的程序設計:核心是對象,對象是特征(變量)與技能(函數)的結合體,是一種上帝式的思維方式

優點:解決了程序的擴展性

缺點:可控性差

二、類和對象

  以遊戲舉例,基於面向對象設計一個款遊戲:英雄聯盟,每個玩家選一個英雄,每個英雄都有自己的特征和和技能,特征即數據屬性,技能即方法屬性,特征與技能的結合體就一個對象

從一組對象中提取相似的部分就是類所有對象都具有的特征和技能的結合體

  在python中,用變量表示特征,用函數表示技能,因而類是變量與函數的結合體,對象是變量與方法(指向類的函數)的結合體

在現實世界中:對象--(共同的特征與技能)-->類
在程序中:先定義類----(實例化)----->對象

1、類的定義

定義類的語法
class 類名:
‘‘‘註釋‘‘‘
類體

#定義一個學生類:類名通常首字母大寫表示
class Student:
    school = ‘oldboy‘
    def __init__(self,name,age):
        #只用來初始化的,並且一定不能有返回值,
        self.name=name
        self.age=age
    def study(self):
        print(‘is studying‘)
    def fly(self,x):
        print(x)
        print(‘%s is flying‘ %self.name)
    def foo(self):
        print(‘===========》‘)

2、類的作用

  類的的用法一:實例化產生對象
  類的的用法二:屬性引用

3、對象的作用:

  對象/實例只有一種作用:屬性引用

#類的作用一:實例化對象
s1=Student(‘egon1‘,84)
s2=Student(‘egon2‘,84)

#類的作用二:類的屬性引用
print(Student.school) #引用類的數據屬性
print(Student.study) #引用類的函數屬性


#對象的用法:屬性引用
print(s1.name)
print(s1.age)

  對象/實例本身只有數據屬性,但是python的class機制會將類的函數綁定到對象上,稱為對象的方法,或者叫綁定方法

,綁定方法唯一綁定一個對象,同一個類的方法綁定到不同的對象上,屬於不同的方法,內存地址都不會一樣

4、類的名稱空間與對象名稱空間

  創建一個類就會創建一個類的名稱空間,用來存儲類中定義的所有名字,這些名字稱為類的屬性

  類有兩種屬性:數據屬性和函數屬性,

  其中類的數據屬性是共享給所有對象的

>>> id(s1.school) #本質就是在引用類的Student屬性,二者id一樣
4315241024
>>> id(s2.school)
4315241024

  而類的函數屬性是綁定到所有對象的:

>>> id(s1.study) 
4302501512
>>> id(s2.study)
4315244200 

創建一個對象/實例就會創建一個對象/實例的名稱空間,存放對象/實例的名字,稱為對象/實例的屬性

在obj.name會先從obj自己的名稱空間裏找name,找不到則去類中找,類也找不到就找父類...最後都找不到就拋出異常

類屬性的補充

一:我們定義的類的屬性到底存到哪裏了?有兩種方式查看
dir(類名):查出的是一個名字列表
類名.__dict__:查出的是一個字典,key為屬性名,value為屬性值

二:特殊的類屬性
類名.__name__# 類的名字(字符串)
類名.__doc__# 類的文檔字符串
類名.__base__# 類的第一個父類(在講繼承時會講)
類名.__bases__# 類所有父類構成的元組(在講繼承時會講)
類名.__dict__# 類的字典屬性
類名.__module__# 類定義所在的模塊
類名.__class__# 實例對應的類(僅新式類中)

  

三、繼承與派生

1、繼承的概念:繼承是一種創建新類的方式,在python中,新建的類可以繼承一個或多個父類,父類又可稱為基類或超類,新建的類稱為派生類或子類

  python中類的繼承分為:單繼承和多繼承

class ParentClass1: #定義父類
    pass
class ParentClass2: #定義父類
    pass
class SubClass1(ParentClass1): #單繼承,基類是ParentClass1,派生類是SubClass
    pass
class SubClass2(ParentClass1,ParentClass2): #python支持多繼承,用逗號分隔開多個繼承的類
    pass

  查看繼承 

>>> SubClass1.__bases__ #__base__只查看從左到右繼承的第一個子類,__bases__則是查看所有繼承的父類
(<class ‘__main__.ParentClass1‘>,)
>>> SubClass2.__bases__
(<class ‘__main__.ParentClass1‘>, <class ‘__main__.ParentClass2‘>)

  註:在python3中所有類默認繼承object,

    1、只要是繼承了object類的子類,以及該子類的子類,都稱為新式類(在python3中的類都是新式類)

    2、沒有繼承object類的子類稱為經典類(在python2中,沒有集成object的類,以及它的子類,都是經典類)

‘‘繼承+派生‘‘‘
class People:
    def __init__(self, name, age,sex):
        self.name = name
        self.age = age
        self.sex=sex
    def walk(self):
        print(‘%s is walking‘ % self.name)
    def foo(self):
        print(‘from father %s‘ %self.name)

class Teacher(People):
    school = ‘偶的博愛‘
    #__init__(t,‘egon‘,18,‘male‘,10,3000)
    def __init__(self, name, age,sex,level,salary):
        People.__init__(self,name,age,sex)
        self.level=level
        self.salary=salary
    def teach(self):
        print(‘%s is teaching‘ %self.name)
    def foo(self):
        People.foo(self)
        print(‘from teacher‘)

class Student(People):
    def __init__(self, name, age,sex,group):
        People.__init__(self, name, age, sex)
        self.group=group
    def study(self):
        print(‘%s is studying‘ %self.name)

t=Teacher(‘egon‘,18,‘male‘,10,3000)

四、組合與重用性

組合指的是,在一個類中以另外一個類的對象作為數據屬性,稱為類的組合

組合與繼承都是有效地利用已有類的資源的重要方式。但是二者的概念和使用場景皆不同,

1.繼承的方式

  通過繼承建立了派生類與基類之間的關系,它是一種‘是‘的關系,比如白馬是馬,人是動物。

  當類之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好,比如教授是老師

>>> class Teacher:
...     def __init__(self,name,gender):
...         self.name=name
...         self.gender=gender
...     def teach(self):
...         print(‘teaching‘)
... 
>>> 
>>> class Professor(Teacher):
...     pass
... 
>>> p1=Professor(‘egon‘,‘male‘)
>>> p1.teach()
teaching

2.組合的方式

  用組合的方式建立了類與組合的類之間的關系,它是一種‘有’的關系,比如教授有生日,教授教python課程

class BirthDate:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day

class Couse:
    def __init__(self,name,price,period):
        self.name=name
        self.price=price
        self.period=period

class Teacher:
    def __init__(self,name,gender):
        self.name=name
        self.gender=gender
    def teach(self):
        print(‘teaching‘)
class Professor(Teacher):
    def __init__(self,name,gender,birth,course):
        Teacher.__init__(self,name,gender)
        self.birth=birth
        self.course=course

p1=Professor(‘egon‘,‘male‘,
             BirthDate(‘1995‘,‘1‘,‘27‘),
             Couse(‘python‘,‘28000‘,‘4 months‘))

print(p1.birth.year,p1.birth.month,p1.birth.day)
print(p1.course.name,p1.course.price,p1.course.period)
‘‘‘
運行結果:
1 27
python 28000 4 months
‘‘‘

繼承+派生+組合應用舉例:

class People:
    def __init__(self, name, age, year, mon, day):
        self.name = name
        self.age = age
        self.birth = Date(year, mon, day)

    def walk(self):
        print(‘%s is walking‘ % self.name)

class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day

    def tell_birth(self):
        print(‘出生於<%s>年 <%s>月 <%s>日‘%(self.year,self.mon,self.day))

class Teacher(People):
    def __init__(self, name, age, year, mon, day,level,salary):
        People.__init__(self,name,age,year,mon,day)
        self.level=level
        self.salary=salary

    def teach(self):
        print(‘%s is teaching‘ %self.name)

class Student(People):
    def __init__(self, name, age, year, mon, day,group):
        People.__init__(self,name,age,year,mon,day)
        self.group=group
    def study(self):
        print(‘%s is studying‘ %self.name)

總結:當類之間有顯著不同,並且較小的類是較大的類所需要的組件時,用組合比較好 

五、接口

繼承有兩種用途:

一:繼承基類的方法,並且做出自己的改變或者擴展(代碼重用)

二:聲明某個子類兼容於某基類,定義一個接口類Interface,接口類中定義了一些接口名(就是函數名)且並未實現接口的功能,子類繼承接口類,並且實現接口中的功能

class Interface:#定義接口Interface類來模仿接口的概念,python中壓根就沒有interface關鍵字來定義一個接口。
    def read(self): #定接口函數read
        pass

    def write(self): #定義接口函數write
        pass


class Txt(Interface): #文本,具體實現read和write
    def read(self):
        print(‘文本數據的讀取方法‘)

    def write(self):
        print(‘文本數據的讀取方法‘)

class Sata(Interface): #磁盤,具體實現read和write
    def read(self):
        print(‘硬盤數據的讀取方法‘)

    def write(self):
        print(‘硬盤數據的讀取方法‘)

class Process(Interface):
    def read(self):
        print(‘進程數據的讀取方法‘)

    def write(self):
        print(‘進程數據的讀取方法‘)

  實踐中,繼承的第一種含義意義並不很大,甚至常常是有害的。因為它使得子類與基類出現強耦合。

繼承的第二種含義非常重要。它又叫“接口繼承”。
  接口繼承實質上是要求“做出一個良好的抽象,這個抽象規定了一個兼容接口,使得外部調用者無需關心具體細節,可一視同仁的處理實現了特定接口的所有對象”——這在程序設計上,叫做歸一化。

  歸一化使得高層的外部使用者可以不加區分的處理所有接口兼容的對象集合——就好象linux的泛文件概念一樣,所有東西都可以當文件處理,不必關心它是內存、磁盤、網絡還是屏幕(當然,對底層設計者,當然也可以區分出“字符設備”和“塊設備”,然後做出針對性的設計:細致到什麽程度,視需求而定)。

接口的好處:

  接口提取了一群類共同的函數,可以把接口當做一個函數的集合。然後讓子類去實現接口中的函數。

  這麽做的意義在於歸一化,什麽叫歸一化,就是只要是基於同一個接口實現的類,那麽所有的這些類產生的對象在使用時,從用法上來說都一樣。

  歸一化,讓使用者無需關心對象的類是什麽,只需要的知道這些對象都具備某些功能就可以了,這極大地降低了使用者的使用難度。

‘‘‘
(抽象類):
		#父類要限制
		#1;子類必須要有父類的方法
		#2:子類實現的方法必須跟父類的方法的名字一樣
‘‘‘

import abc
class File(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def read(self):
        pass

    @abc.abstractmethod
    def write(self):
        pass


class Txt(File): #文本,具體實現read和write
    def read(self):
        pass
    def write(self):
        pass
t=Txt()

  

Python基礎(16)_面向對象程序設計(類、繼承、派生、組合、接口)