Python 面向對象(類,類的繼承)

Python 面向對象

記住一句話:類是模板,而實例則是根據類建立的對象。html

初學時對類的理解是從類的字面上,能夠片面的認爲它是一個種類,它是類似特徵的抽像,也就是類似的東西,能夠把類似特徵的事務抽象成一個類。(事務能夠是具體的物體或行爲)python

以圓爲例,圓是具備圓周率(pi)和半徑(r)兩個類似特徵的屬性。根據類似特徵抽象出圓類,每一個圓的半徑能夠不一樣,那麼半徑能夠做爲圓的實例屬性;而每一個圓的圓周率pi是相同的,那麼圓周率pi就能夠做爲類屬性,這樣就定義出了一個圓類。而咱們要知道圓的面積,周長等能夠經過類方法計算出來。編程

(看完整篇文章,仍是對類不理解,回過頭在來看這部分,對照列子多理解。)數據結構

Python 面向對象(類,類的繼承)

類的應用場景:

零散代碼(代碼塊)-->函數(方法)-->類-->模塊(文件)
類:表示抽象(模糊)的事物
對象:表示具體(清晰)的事物編程語言

一、面向對象技術簡介

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

二、建立類

使用 class 語句來建立一個新類,class 以後爲類的名稱並以冒號結尾:ide

class ClassName:
   '類的幫助信息'   #類文檔字符串
   class_suite  #類體

類的幫助信息能夠經過ClassName.doc查看。函數

class_suite 由類成員,方法,數據屬性組成。ui

(1)例子

描述人類的文件
類的結構:
一、動態的行爲(動詞):speak、sing
二、靜態的屬性(名詞):gender、user_name
(1)全局:在類中的任何地方都能使用
(2)局部:只可以在方法內部使用
使用類:
實例化對象:對象名 = 類名 ( 參數【可選的】)翻譯

class Human():
    """模擬人類"""
    def __init__(self, sex, name):
        """初始化屬性:gender和user_name"""
        self.gender = sex
        self.user_name = name

    def speak(self):
        """模擬人類說話"""
        print(self.user_name.title() + "正在說話。")

    def sing(self):
        """模擬人類唱歌"""
        print(self.user_name.title() + "正在唱歌。")
  • empCount 變量是一個類變量,它的值將在這個類的全部實例之間共享。你能夠在內部類或外部類使用 Employee.empCount 訪問。
  • 第一種方法__init__()方法是一種特殊的方法,被稱爲類的構造函數或初始化方法,當建立了這個類的實例時就會調用該方法
  • self 表明類的實例,self 在定義類的方法時是必須有的,雖然在調用時沒必要傳入相應的參數。
輸出結果以下:
# 使用類
man = Human('男','xgp')
man.speak()

lz = Human('男','kk')
lz.sing()

(2)修改初始值

class Pet():

    def __init__(self,sex,strain):
        """給屬性賦初始值(默認值)"""
        self.nick_name = '咪咪'
        self.gender = sex
        self.stain = strain

cat = Pet('公','土貓')
# 修改初始值
cat.nick_name = '妙妙'
print(cat.nick_name)
輸出結果以下:
妙妙

三、self表明類的實例,而非類

類的方法與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱, 按照慣例它的名稱是 self。設計

class Test:
    def prt(self):
        print(self)
        print(self.__class__)

t = Test()
t.prt()
輸出結果以下:
<__main__.Test instance at 0x10d066878>
__main__.Test

從執行結果能夠很明顯的看出,self 表明的是類的實例,表明當前對象的地址,而 self.__class__ 則指向類。

self 不是 python 關鍵字,咱們把他換成 runoob 也是能夠正常執行的:

class Test:
    def prt(runoob):
        print(runoob)
        print(runoob.__class__)

t = Test()
t.prt()
輸出結果以下:
<__main__.Test instance at 0x10d066878>
__main__.Test

四、建立實例對象

實例化類其餘編程語言中通常用關鍵字 new,可是在 Python 中並無這個關鍵字,類的實例化相似函數調用方式。

如下使用類的名稱 Dn 來實例化,並經過 __init__ 方法接收參數。

"""
小名和小紅各自買了一臺筆記本電腦,
其中小名的電腦品牌是聯想, CPU8核, 512G固態硬盤,雙飛燕鼠標
省紅的電腦品牌是機械師, CPU4核, 256G固態硬盤+1T普通硬盤,機械師鼠標
使用面向對象的思惟,編寫代碼完成以 上描述。
"""
class Dn():

    def __init__(self,name,brand,cpu,disk,mouse):
        self.nice_name = name
        self.nice_pp = brand
        self.nice_cpu = cpu
        self.nice_disk = disk
        self.nice_mouse = mouse
    def xgp(self):
        print(self.nice_name + '的電腦配置:「'
              + '品牌:' + self.nice_pp + ','
              + 'cpu:' +self.nice_cpu + ','
              + '硬盤:' +self.nice_disk + ','
              + '鼠標:' + self.nice_mouse + ','
              + '」。')
# 可使用點號 . 來訪問對象的屬性。使用以下類的名稱訪問類變量
Dn1 = Dn('小名','聯想','8核','512固態硬盤','雙飛燕')
Dn1.xgp()

Dn2 = Dn('小米','機械師','4核','256G固態硬盤+1T普通硬盤','機械師鼠標')
Dn2.xgp()
輸出結果以下:
小名的電腦配置:「品牌:聯想,cpu:8核,固態硬盤:512固態硬盤,鼠標:雙飛燕」。
小名的電腦配置:「品牌:機械師,cpu:4核,固態硬盤:256G固態硬盤,機械硬盤1T普通硬盤,鼠標:機械師鼠標」。

五、類的繼承

Python 面向對象(類,類的繼承)

面向對象的編程帶來的主要好處之一是代碼的重用,實現這種重用的方法之一是經過繼承機制。

經過繼承建立的新類稱爲子類或派生類,被繼承的類稱爲基類父類超類

繼承語法

class 派生類名(基類名)
    ...

在python中繼承中的一些特色:

  • 一、若是在子類中須要父類的構造方法就須要顯示的調用父類的構造方法,或者不重寫父類的構造方法。詳細說明可查看:python 子類繼承父類構造函數說明
  • 二、在調用基類的方法時,須要加上基類的類名前綴,且須要帶上 self 參數變量。區別在於類中調用普通函數時並不須要帶上 self 參數
  • 三、Python 老是首先查找對應類型的方法,若是它不能在派生類中找到對應的方法,它纔開始到基類中逐個查找。(先在本類中查找調用的方法,找不到纔去基類中找)。

若是在繼承元組中列了一個以上的類,那麼它就被稱做"多重繼承" 。

語法:

派生類的聲明,與他們的父類相似,繼承的基類列表跟在類名以後,以下所示:

class SubClassName (ParentClass1[, ParentClass2, ...]):
    ...

(1)例子

class Parent:        # 定義父類
   parentAttr = 100
   def __init__(self):
      print ("調用父類構造函數")

   def parentMethod(self):
      print('調用父類方法')

   def setAttr(self, attr):
      Parent.parentAttr = attr

   def getAttr(self):
      print ("父類屬性 :", Parent.parentAttr)

class Child(Parent): # 定義子類
   def __init__(self):
      print ("調用子類構造方法")

   def childMethod(self):
      print ('調用子類方法')

c = Child()          # 實例化子類
c.childMethod()      # 調用子類的方法
c.parentMethod()     # 調用父類方法
c.setAttr(200)       # 再次調用父類的方法 - 設置屬性值
c.getAttr()          # 再次調用父類的方法 - 獲取屬性值
輸出結果以下:
調用子類構造方法
調用子類方法
調用父類方法
父類屬性 : 200

(2)例子

"""
小名和小紅各自買了一臺筆記本電腦,
其中小名的電腦品牌是聯想, CPU8核, 512G固態硬盤,雙飛燕鼠標
省紅的電腦品牌是機械師, CPU4核, 256G固態硬盤+1T普通硬盤,機械師鼠標
使用面向對象的思惟,編寫代碼完成以 上描述。
"""
class Dn():

    def __init__(self,brand,cpu,disk,mouse):
        self.nice_pp = brand
        self.nice_cpu = cpu
        self.nice_disk = disk
        self.nice_mouse = mouse

# 繼承:共享某個類的代碼
class XiaoMing(Dn):

    def __init__(self,brand,cpu,disk,mouse):
        super().__init__(brand,cpu,disk,mouse)

    def xgp(self,name):
        print(name + '的電腦配置:「'
                      + '品牌:' + self.nice_pp + ','
                      + 'cpu:' +self.nice_cpu + ','
                      + '固態硬盤:' +self.nice_disk + ','
                      + '鼠標:' + self.nice_mouse
                      + '」。')
class XiaoHong(Dn):
    def __init__(self,brand,cpu,disk,sim_disk,mouse):
        self.sim_disk = sim_disk
        super() . __init__(brand,cpu,disk,mouse)

    def wsd(self,name):
        print(name + '的電腦配置:「'
              + '品牌:' + self.nice_pp + ','
              + 'cpu:' + self.nice_cpu + ','
              + '固態硬盤:' + self.nice_disk + ','
              + '機械硬盤' + self.sim_disk + ','
              + '鼠標:' + self.nice_mouse
              + '」。')

xiaoming = XiaoMing('聯想','8核','512固態硬盤','雙飛燕')
xiaoming.xgp('小名')
xiaohong = XiaoHong('機械師','4核','256G固態硬盤','1T普通硬盤','機械師鼠標')
xiaohong.wsd('小名')
輸出結果以下:
小名的電腦配置:「品牌:聯想,cpu:8核,固態硬盤:512固態硬盤,鼠標:雙飛燕」。
小名的電腦配置:「品牌:機械師,cpu:4核,固態硬盤:256G固態硬盤,機械硬盤1T普通硬盤,鼠標:機械師鼠標」。

(3)方法重寫(員工自我介紹)

class Empoyee():
    """員工類"""

    def __init__(self,name,years_old,money):
        """初始化普通員工屬性"""
        self.user_name = name
        self.user_years_old = years_old
        self.user_money = money

    def say_hi(self):
        """模擬員工自我介紹的方法"""
        print('我叫'+self.user_name
              +',工齡' + self.user_years_old
              +'年,年工資爲' + self.user_money
              +'元。'
              )

class SE(Empoyee):

    def __init__(self,name,years_old,money):
        super().__init__(name,years_old,money)

    def say_hi(self):
        """模擬員工自我介紹的方法"""
        print('我叫'+self.user_name
              +',工齡' + self.user_years_old
              +'年,年工資爲' + self.user_money
              +'元。'
              )

class PM(Empoyee):

    def __init__(self,name,years_old,money,bonus):
        super().__init__(name,years_old,money)
        # 編寫子類特有的屬性
        self.pm_bonus = bonus

    def say_hi(self):
        """模擬項目經理自我介紹的方法"""
        print('我叫'+self.user_name
              +',工齡' + self.user_years_old
              +'年,月工資爲' + self.user_money
              +'元,'
              + '管理獎金' + self.pm_bonus + '元。'
              )

class CTO(Empoyee):

    def __init__(self,name,years_old,money,bonus,annual_bonus):
        super().__init__(name,years_old,money)
        self.cto_bonus = bonus
        self.cto_annual_bonus = annual_bonus

    def say_hi(self):
        """模擬項目經理自我介紹的方法"""
        print('我叫'+self.user_name
              +',工齡' + self.user_years_old
              +'年,月工資爲' + self.user_money
              +'元,'
              + '管理獎金' + self.cto_bonus + '元,'
              + '年終獎' + self.cto_annual_bonus + '元。'
              )

# 使用類:實例化對象
se = SE('xgp','4','8k')
se.say_hi()

pm = PM('wsd','6','10000','5000')
pm.say_hi()

cto = CTO('xgp','10','30000','6000','12000')
cto.say_hi()
輸出結果以下:
我叫xgp,工齡4年,年工資爲8k元。
我叫wsd,工齡6年,月工資爲10000元,管理獎金5000元。
我叫xgp,工齡10年,月工資爲30000元,管理獎金6000元,年終獎12000元。

分析以上代碼

Python 面向對象(類,類的繼承)
Python 面向對象(類,類的繼承)

六、Python內置類屬性

  • __dict__ : 類的屬性(包含一個字典,由類的數據屬性組成)
  • ~ :類的文檔字符串
  • __name__: 類名
  • __module__: 類定義所在的模塊(類的全名是'__main__.className',若是類位於一個導入模塊mymod中,那麼className.__module__ 等於 mymod)
  • __bases__ : 類的全部父類構成元素(包含了一個由全部父類組成的元組)

Python內置類屬性調用實例以下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Employee:
   '全部員工的基類'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1

   def displayCount(self):
     print "Total Employee %d" % Employee.empCount

   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary

print "Employee.__doc__:", Employee.__doc__
print "Employee.__name__:", Employee.__name__
print "Employee.__module__:", Employee.__module__
print "Employee.__bases__:", Employee.__bases__
print "Employee.__dict__:", Employee.__dict__
輸出結果以下:
Employee.__doc__: 全部員工的基類
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0x10a939c80>, 'empCount': 0, 'displayEmployee': <function displayEmployee at 0x10a93caa0>, '__doc__': '\xe6\x89\x80\xe6\x9c\x89\xe5\x91\x98\xe5\xb7\xa5\xe7\x9a\x84\xe5\x9f\xba\xe7\xb1\xbb', '__init__': <function __init__ at 0x10a939578>}

七、python對象銷燬(垃圾回收)

Python 使用了引用計數這一簡單技術來跟蹤和回收垃圾。

在 Python 內部記錄着全部使用中的對象各有多少引用。

一個內部跟蹤變量,稱爲一個引用計數器。

當對象被建立時, 就建立了一個引用計數, 當這個對象再也不須要時, 也就是說, 這個對象的引用計數變爲0 時, 它被垃圾回收。可是回收不是"當即"的, 由解釋器在適當的時機,將垃圾對象佔用的內存空間回收。

a = 40      # 建立對象  <40>
b = a       # 增長引用, <40> 的計數
c = [b]     # 增長引用.  <40> 的計數

del a       # 減小引用 <40> 的計數
b = 100     # 減小引用 <40> 的計數
c[0] = -1   # 減小引用 <40> 的計數

垃圾回收機制不只針對引用計數爲0的對象,一樣也能夠處理循環引用的狀況。循環引用指的是,兩個對象相互引用,可是沒有其餘變量引用他們。這種狀況下,僅使用引用計數是不夠的。Python 的垃圾收集器其實是一個引用計數器和一個循環垃圾收集器。做爲引用計數的補充, 垃圾收集器也會留心被分配的總量很大(及未經過引用計數銷燬的那些)的對象。 在這種狀況下, 解釋器會暫停下來, 試圖清理全部未引用的循環。

實例

析構函數 __del____del__在對象銷燬的時候被調用,當對象再也不被使用時,__del__方法運行:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Point:
   def __init__( self, x=0, y=0):
      self.x = x
      self.y = y
   def __del__(self):
      class_name = self.__class__.__name__
      print class_name, "銷燬"

pt1 = Point()
pt2 = pt1
pt3 = pt1
print id(pt1), id(pt2), id(pt3) # 打印對象的id
del pt1
del pt2
del pt3
輸出結果以下:
3083401324 3083401324 3083401324
Point 銷燬

注意:一般你須要在單獨的文件中定義一個類

八、總結

參數的傳遞圖,翻譯與pythoncentral

Python 面向對象(類,類的繼承)

  • In 1 and 2, the arguments are passed to the method.
  • 1和2參數傳遞給init方法中的data參數
  • On 3, the self argument refers to the instance.
  • 3**self 參數指向當前實例自身,self表明建立的實例變量 ik1 或者 Kls('arun')。**
  • At 4, we do not need to provide the instance to the method, as it is handled by the interpretor itself.
  • 4 咱們不須要傳遞實例自身給方法,Python解釋器本身會作這些操做的;ik14 會自動做爲第一個實例參數(self)傳入方法中。

Python 面向對象(類,類的繼承)

相關文章
相關標籤/搜索