python的oop概述

python是面向對象的語言,那麼究竟什麼是面向對象?html

首先理解類

類:在中文中的定義,許多相同或類似事物的綜合。根據這個定義,類是許多相同或類似的實物聚在一塊兒的。譬如,人類,鳥類,花類等。python

面向對象的三個特徵

類的單個具體實例能夠稱之爲對象,把類具體化單個實體的過程,這個過程稱爲類的實例化!數據庫

面向對象程序設計中的術語對象基本上能夠看作數據(特性)以及由一系列能夠存取,操做這些數據的方法所組成的集合。swift

面向對象的三個基本特徵:封裝,繼承,多態。函數

建立對象的過程稱之爲實例化,當一個對象被建立以後,包含三個方面的特性:對象的句柄,屬性和方法。對象的句柄用於區分不一樣的對象,當對象被建立後,該對象會獲取一塊存儲空間,存儲空間的地址即爲對象的標識。測試

  • 多態:對不一樣的類的對象使用一樣的操做。
  • 封裝:對外部世界隱藏對象的工做細節。
  • 繼承:以普通的類爲基礎類創建專門的類對象。

經過實例理解面向對象的一些術語和三個基本特徵:

構造方法與析構函數

  • 構造方法:在實例化時作的一些初始化工做。
  • 析構函數:在實例銷燬時,執行的一些操做。
class People(object):
    def __init__(self,country, name,age=23):  #構造方法
        self.country = country  #實例屬性
        self.name = name
        self.__age = age        #私有屬性

    def __del__(self):  #析構函數
        print("%s  has died" % self.name)

    def get_info(self):  #實例方法
        print("The %s info".center(50,"-") % self.name)
        print("The %s comes from %s, is %d old" % (self.name, self.country, self.__age))

實例化上面的類,spa

>>> a = People("China","hitler",20)   #實例化一個類時,這時候構造函數會自動執行

>>> a.get_info()   #經過實例訪問類中的實例方法
-------------------The hitler info--------------------
The hitler comes from China, is 20 old

在類中定義屬性時,若屬性是以雙下劃線開始的則爲私有屬性,例如self.__age屬性,而像self.country和self.name屬性則是公有屬性,不管是私有屬性仍是公有屬性,每一個經過實例化獲得的類都有這些屬性。設計

在實例化時,咱們能夠像給函數傳入參數那樣,給類傳入參數,而這些參數的最終被賦值的操做就是在構造函數中執行的。構造函數在類實例化的時候會自動執行code

注意私有屬性和實例屬性的訪問方法的不一樣htm

>>> a.name      #訪問實例屬性
'hitler'
>>> a.country   #訪問實例屬性
'China'
>>> a.__age     #方位私有屬性
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'People' object has no attribute '__age'
>>> a._People__age   #私有屬性的訪問方法,實例化名._類名__私有屬性名
20
>>> del a        #刪除一個實例,這時候,析構函數會自動執行
hitler  has died
#析構函數:在實例銷燬的時候自動執行的,一般用於作一些收尾的工做,關閉一些數據庫鏈接或者關閉打開的臨時文件。

析構函數:在實例銷燬的時候自動執行的,一般用於作一些收尾的工做,關閉一些數據庫鏈接或者關閉打開的臨時文件

在上面的例子中,使用del刪除了實例a,而後會自動返回析構函數執行的結果。

 

能夠對實例進行增長,刪除,修改操做:

對象屬性的增刪改
>>> A = People("USA", "jobs", "53")  
>>> A.country #能夠經過實例修改對應的屬性值
'USA'
>>> A.country = "UKA" 
>>> A._People__age = 55
>>> A.get_info()  ##能夠看到實例的屬性值已經修改
-------------------The jobs info--------------------
The jobs comes from UKA, is 55 old
#能夠經過del刪除某個屬性
>>> del A.country
>>> A.get_info()  #報錯,沒有對應的country屬性
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "E:\pycharm\class_method.py", line 14, in get_info
    print("The %s comes from %s, is %d old" % (self.name, self.country, self.__age))
AttributeError: 'People' object has no attribute 'country'
-------------------The jobs info--------------------

>>> A.country = "China" #添加屬性
>>> A.get_info()  #能夠看到屬性添加成功
-------------------The jobs info--------------------
The jobs comes from China, is 55 old

注意上面的經過實例對屬性的增長,刪除,修改操做僅對當前的實例有效;而對於類的其他實例則沒有效果。能夠作以下測試以證實:

>>> a = People("USA","swift",29)  #實例化一個對象
>>> a.pos = "singer"                #給對象添加一個pos屬性
>>> a.pos                           #對象a具備pos屬性
'singer'

>>> B = People("UKA","king",80)   #再實例化一個對象B

>>> B.pos
Traceback (most recent call last):  #對象B沒有pos屬性
  File "<input>", line 1, in <module>
AttributeError: 'People' object has no attribute 'pos'

>>> a.get_info()
-------------------The swift info--------------------
The swift comes from USA, is 29 old
>>> b.get_info()
-------------------The king info--------------------
The king comes from UKA, is 80 old

解釋

  建立類的時候python會在內存中爲類開闢一段內存空間,實例化的時候,python會爲每個實例開闢一段內存空間,每一個實例的內存空間都是相互獨立的,所以更改了a的內存空間,並不會影響B的內存空間。
  若想使更改的效果,對類的每個實例都生效,可使用類變量。

在類變量以前,先說一下self參數。在類中定義的方法,每一個方法都有一個self參數,那麼self參數該如何理解?

  • 在上面的實例中,經過類實例化了兩個對象a和b,那麼這兩個對象都有get_info()方法,可是在調用的時候並無出錯,咱們只能經過某一個具體對象獲得這個對象的信息,也就是說咱們只能經過a的get_info()方法獲得對象a的相關信息,而不是獲得b的信息。這個的實現就是由於self參數的做用。
  • 在實例化的過程時,python會執行構造函數,作一些初始化的工做,這時候python會爲這個實例開闢一段內存空間,會把這個實例名(經過self參數傳遞)和一些屬性信息一塊兒存入內存,這樣調用的時候,經過self參數來區分不一樣的實例能夠準確的調用到對應的屬性信息。

類變量:

  首先知足上面提到的,讓更改對每個實例都生效。

class People(object):
    addr = "Earth"  # 類變量

    def __init__(self, country, name, age=23):
        self.country = country
        self.name = name
        self.__age = age

而後對上面的類進行實例化操做,以下:

>>> a = People("USA","swift", 29)  #實例化兩個類
>>> b = People("China","wxz", 24)  
>>> a.addr                         #這兩個類都有一個addr屬性,注意addr類變量在類中定義的方法
'Earth'
>>> b.addr
'Earth'

>>> a.addr = "Moon"                #注意這樣作只是在實例a中添加了實例屬性addr,而不是修改類變量addr。
>>> a.addr                         #實例a訪問的是實例屬性中的addr。
'Moon'         
>>> b.addr                         #而實例b訪問的是類變量addr。所以結果不一樣
'Earth'
>>> People.addr = "Moon"           #修改類變量,這時候實例a仍然訪問的是實例屬性addr,而實例b訪問的是類變量addr。
>>> a.addr
'Moon'
>>> b.addr
'Moon'
#再實例化一個實例對象c,能夠發現c的addr屬性已是修改以後的屬性。
>>> c = People("UKA", "King",88)
>>> c.addr                        #實例對象c訪問的是類變量addr。
'Moon'

在上面的實例中,咱們給實例a添加一個實例屬性addr,而這時候類變量也有一個屬性addr,那麼在訪問的時候實例會怎麼去調用對應的值呢?

經過以上的例子能夠得出以下結論:屬性查找,首先查找實例自己是否有對應的屬性,若找到則返回結果,中止查找;不然就繼續查找類中的屬性變量。

在這裏實例a由於添加了add實例r屬性,所以實例a只會返回實例自己的addr結果;而實例b和實例c,由於自己的沒有addr實例屬性(構造函數中沒有定義),所以會返回類變量addr的值。

類變量是類的各個實例共有的屬性。固然這個屬性也能夠放在構造函數中,在每一個實例初始化的時候,就會自動生成這個屬性。
可是上面提到過python會爲每一個實例開闢一個內存空間,所以當實例很是巨大的時候,這樣作會佔用存儲空間。採用類變量的形式更節省空間。

封裝

  在這個實例中有一個簡單的方法就是get_info()。對於一個對象也就是實例來講,要想獲得這個對象的具體信息,只須要調用get_info()這個方法便可,而後就會返回對象的具體信息。可是具體是怎麼樣獲得這些信息的,這個實例是不知道的。這種形式就是封裝。把一些功能實現的細節不對外暴露,隱藏起來就是封裝。

經典類與新式類:

  • python2中默認建立的都是經典類,但建立類時使用object參數時,就是新式類。
  • python3中建立的類都是新式類,但習慣上使用object參數。
  • 經典類與新式類的區別在多種繼承中能夠用到,附上一片博文連接,經典類與新式類的異同

繼承

  • 繼承就是一個類繼承了另外一個類,繼承的新類擁有父類屬性和方法,實現代碼的重複使用和代碼的擴展。
  • 再繼承時,能夠對父類的一些屬性和方法進行重寫。
  • 須要特別注意的是構造方法的重寫。
class People(object):
    def __init__(self,name,pos=None):
        self.name = name
        self.pos = pos

    def get_info(self):
        print("My name is %s, I have not a work" % self.name)


class Teacher(People):
    def __init__(self,name, pos, school):
        super(Teacher,self).__init__(name, pos) #重寫構造方法的兩種形式,推薦使用super的形式,構造方法重寫時注意參數傳遞。
        # People.__init__(self, name, pos)
        self.school = school
    def get_info(self):
        print("My name is %s, I am a %s" % (self.name, self.pos))
        print("The colleage is %s" % self.school)

class Student(People):
    def __init__(self,name,pos, score, course):
        super(Student, self).__init__(name, pos)
        self.score = score
        self.course = course

    def get_info(self):
        print("My name is %s, I am a %s" % (self.name, self.pos))
        print("My score is %d" % self.score)
        print("I have learned the %s %s %s" % self.course)

上面定義了一個父類People,兩個子類teacher和student,都繼承了people。

實例化操做:

a = People("wxz")
b = Teacher(name="steve", pos="teacher", school="Peking university")
d = Student(name="job", pos="Stuent", score=88, course=("數學","語文","物理"))

In [6]: a.get_info()
My name is wxz, I have not a work

In [7]: b.get_info()
My name is steve, I am a teacher
The colleage is Peking university

In [8]: d.get_info()
My name is job, I am a Stuent
My score is 88
I have learned the 數學 語文 物理

實例化的每個對象均可以調用get_info()方法,獲得其對應的信息。這三個對象是不同的,分別爲people, teacher,student對象。
如有一個函數,只要傳入對應的對象,而後就能夠調用函數獲得對應的信息。以下這種形式:

In [9]: def print_info(obj):   ##在只要傳入對象信息,咱們不知道這個對象是什麼類型,可是他依然能夠獲得對象的信息
   ...:     obj.get_info()
   ...:     

In [10]: print_info(a)
My name is wxz, I have not a work

In [11]: print_info(b)
My name is steve, I am a teacher
The colleage is Peking university

In [12]: print_info(d)
My name is job, I am a Stuent
My score is 88
I have learned the 數學 語文 物理

在這個例子中,並不知道a,b,d是什麼樣的對象,要作的只是把這三個對象傳入了print_intfo函數,而後函數會自動返回對應的對象信息。

這裏只有一個print_info的接口,可是不一樣的對象均可以調用這個接口,這種行爲就叫作多態

多態就是一種接口的多種使用。

下面一個簡單的多態實例

list1
Out[22]: ['a', 'f', 'd', 's', 'f', 'a', 's', 'd', 'f'] #列表

tuple1
Out[23]: ('f', 'g', 'a', 'g', 'f', 'd', 'g', 'd', 'f') #元組

len(list1)
Out[24]: 9

len(tuple1)
Out[25]: 9

對於len()函數來講並不知道list1是列表,tuple1是元組,len()函數只是接受一個參數對象,而後返回這個參數對象的長度。也能夠理解爲多態的一種使用。

 

面向對象的三個基本特徵:封裝,繼承,多態。

面向的對象的屬性:

  • 靜態屬性
    •   私有屬性
    •        實例屬性
    •        類屬性(類變量)

       

  • 動態屬性(就是方法)
    •   實例方法
    •        私有方法--和私有屬性同樣是雙下劃線開始的,調用形式和私有屬性同樣,只能經過類中的方法調用
相關文章
相關標籤/搜索