1. 程式人生 > >python遞歸 及 面向對象初識及編程思想

python遞歸 及 面向對象初識及編程思想

類型 ren def flow 構建 全局 num arch 指向

遞歸 及 面向對象初識及編程思想

一、遞歸

1、定義:

  在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。

  (1)遞歸就是在過程或函數裏調用自身;
  (2)在使用遞歸策略時,必須有一個明確的遞歸結束條件,稱為遞歸出口。

技術分享
1 def age(n):
2     if n ==1:   #條件判定
3         return 10  #返回一個結果
4     else:
5         return age(n-1)+2  #重復調用函數本身,系統會將運算的結果存放到棧,然後再依次的進行取值調用。
6 print(age(5))   #打印結果
技術分享

 執行結果:18

2、優缺點:  

  遞歸函數的優點是定義簡單,邏輯清晰。理論上,所有的遞歸函數都可以寫成循環的方式,但循環的邏輯不如遞歸清晰。

  遞歸的缺點:遞歸算法解題的運行效率較低。在遞歸調用的過程當中系統為每一層的返回點、局部量等開辟了棧來存儲。遞歸次數過多容易造成棧溢出等。

技術分享
def func():
    print("*******")
    func()
func()

#執行結果
 [Previous line repeated 993 more times]
*******
  File "F:/py_fullstack_s4/day26/遞歸.py", line 8, in func
*******
    print("*******")
*******
RecursionError: maximum recursion depth exceeded while calling a Python object
技術分享

3、遞歸編程的註意點:

  1. 必須有一個明確的結束條件。

  2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少。

  3.遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)。

4、此處引出一個新的知識點:二分法

  二分法,是一種快速查找的方法,時間復雜度低,邏輯簡單易懂,總的來說就是不斷的除以2除以2...

  他主要應用於有序序列中,原理是每次查找都將原序列折半,逐漸縮小查找範圍的一種算法。應用於遞歸,循環之中,直到找到結果。

技術分享
#運用 遞歸 和 二分法 的運算方式,查找列表中的某個值
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
num = int(input("please input your want to find number:"))
def search(num,data):
    if len(data) > 1:      #排除列表分割,僅剩一個元素的情況
         #二分法#
        a = int(len(data)//2)   #將計算列表的長度,除以2  取整數
        mid_value = data[a]     #取當前中間的值
        if num > mid_value:     #要找的值 大於 中間的值
            data = data[a:]     #將原列表從中間值往後,取出來,構建一個新列表
            search(num,data)    #遞歸判斷
        elif num < mid_value:   #要找的值 小於 中間的值
            data = data[:a]     #將原列表開始到中間值,取出來,構建一個新列表
            search(num,data)    #遞歸判斷
        else:                   #正好是這個值
            print("find it!!",num)
            return          #打印
    else:                         #判斷列表分割,僅剩一個元素的情況
        if data[0] == num:
            print(‘find it!! %s‘%data[0])
        else:                     #列表中沒有這個值
            print(‘not this num %s‘%num)

search(num,data)

#執行結果:
please input your want to find number:18
find it!! 18
技術分享

二、函數式編程介紹

1、用def模仿數學中函數的方式,傳一個值,就得一個結果。不會修改外部的狀態。
2、代碼非常的精簡,直接導致可讀性非常差。

三、面向對象的程序設計

1、前提鋪墊:

  python中一切皆為對象,python 3統一了類與類型的概念,類型即是類。例如:int,str,list,等等……

  編程語言中,是先有了類,然後再產生一個個對象。而現實生活中正好相反。

  明確一點:面向對象編程是一種編程方式,此編程方式的功能需要使用 “類” 和 “對象” 來實現,所以,面向對象編程其實就是對 “類” 和 “對象” 的使用

  類就是一個模板,模板裏可以包含創建多個函數,函數裏實現自定義的功能

  對象則是根據模板創建的實例,通過實例(對象)可以執行類中定義的函數

2、語法:

  1)創建類:class是關鍵字,表示類 class *** #創建類
  2)創建對象:類名稱後加括號 將結果賦給一個變量 即可 x = ***() #創建對象

技術分享
 1 class hello:  #任意定義一個類
 2     camp = ‘hello world‘
 3     def f(self):
 4         print("f")
 5 h = hello() # 類實例化
 6 print(h) #打印
 7 
 8 #執行結果:
 9 
10 <__main__.hello object at 0x00000000026C9630>
技術分享

3、類與對象

1)什麽是對象:
  以遊戲舉例:英雄聯盟,每個玩家選一個英雄,每個英雄都有自己的特征和和技能,特征即數據屬性,技能即方法屬性,特征與技能的結合體就一個對象。

2)什麽是類:
  從一組對象中提取對象共同的 特征,技能,構成一個類。類也是特征與技能的結合體,特征即數據並且是所有對象共享的數據,技能即函數屬性並且是所有對象共享的函數屬性。 

  ①優點:解決了程序的擴展性,對某個對象進行修改,會立刻反映到整個體系中
  ②缺點:可控性差,無法預測最終的結果。
  面向對象的程序設計並不是程序全部。對於軟件質量來說,面向對象的程序設計只是用來解決擴展性的問題。

def 或是 class 都是在定義一個函數名。class 定義 類    camp 陣營    attack(self) 技能    nickname昵稱    init 開始,初始

3)如何使用類:
 一、實例化

  類的實例化就會產生一個實例(對象)。 可以理解為類加()把虛擬的東西實例化,得到具體存在的值,叫做類的實例化。

技術分享
class Garen:  #定義一個類
    camp = ‘Demacia‘
def attack(self):
    print(‘attack‘)
g1 = Garen() #類的實例化,產生一個對象,可以調用類內包括的所有特征(共性)。
print(g1)  #打印

#執行結果:
<__main__.Garen object at 0x00000000028C9CC0>
技術分享

 二、類通過.(點)的方式引用特征(類的變量)和技能(類的函數(類內部還是定義的函數,調用的話還是需要傳入參數))

技術分享
class Garen:
    camp=‘Demacia‘
    def attack(self):
        print(‘attack‘)
print(Garen.camp)  #查看camp
print(Garen.attack)   #打印數據類型
Garen.attack(‘nihao‘) #由於是調用有參函數,需要傳值

#執行結果:
Demacia
<function Garen.attack at 0x000000000229C950>
attack
技術分享

2、對象之間也有不同,及除了同性也有特性。例如昵稱!

技術分享
class Garen:
    camp=‘Demacia‘

    def __init__(self,nickname):
        self.nick=nickname  #給實例自己定義一個別名,由外部傳入 #g1.nick = ‘草叢倫‘
    def attack(self,enemy):
        # print(‘---------->‘,self.nick) #g1.nick
        print(‘%s attack %s‘ %(self.nick,enemy))


g1=Garen(‘草叢倫‘) #類實例化,類Garen觸發調用_init_ #Garen._init_(self,‘NB‘)
g2=Garen(‘劉下‘)
print(g1.nick)
g1.attack(‘alex‘)

#執行結果:
草叢倫
草叢倫 attack alex
技術分享

self 指自己。

註意:類的實例化就會自動觸發類內_init_函數的執行。

3、怎麽調用類的特征與技能

註意:類與對象之間的綁定方法。調用綁定方法,python 會自動傳值,會將調用者本身當作參數傳給self,第一值。
print(gi.attack) #調用綁定方法,類綁定給g1
print(Garen.attack) #函數

技術分享
class Garen:
    camp=‘Demacia‘

    def __init__(self,nickname):
        self.nick=nickname  #給實例自己定義一個別名,由外部傳入 #g1.nick = ‘草叢倫‘
    def attack(self,enemy):
        # print(‘---------->‘,self.nick) #g1.nick
        print(‘%s attack %s‘ %(self.nick,enemy))


g1=Garen(‘草叢倫‘) #類實例化,類Garen觸發調用_init_ #Garen._init_(self,‘NB‘)
g2=Garen(‘劉下‘)

print(g1.nick)  #昵稱
print(g1.camp)  #陣營
print(g1.attack)  #打印 查看綁定方法
print(Garen.attack)  # 打印 函數

#執行結果:
草叢倫
Demacia
<bound method Garen.attack of <__main__.Garen object at 0x0000000002299D68>>
<function Garen.attack at 0x000000000229C9D8>
技術分享

Garen.attack(參數)# 調用的是函數,需要傳參
g1.attack(‘alex‘) #self = g1;enemy = ‘alex‘若是函數有多個值,就在賦值的時候,傳入其他的參數。

print(g1.nick)

只要是對象觸發的,調用的時候就會自動給調用的函數傳值,將自身傳到第一個參數self。若是函數有多個值,就在賦值的時候,對應的傳入其他的參數。

技術分享
class Garen:
    camp=‘Demacia‘

    def __init__(self,nickname):
        self.nick=nickname  #給實例自己定義一個別名,由外部傳入 #g1.nick = ‘草叢倫‘
    def attack(self,enemy):
        # print(‘---------->‘,self.nick) #g1.nick
        print(‘%s attack %s‘ %(self.nick,enemy))


g1=Garen(‘草叢倫‘) #類實例化,類Garen觸發調用_init_ #Garen._init_(self,‘NB‘)
g2=Garen(‘劉下‘)
print(g2.nick)
print(g2.camp)

#執行結果:
劉下
Demacia
技術分享

三、總結:
1、類:一:實例化,二:引用名字(類名.變量名,類名.函數名) 得到一個內存地址,加()就能運行。

2、實例(對象):引用名字(實例名.類的變量,實例名.綁定方法,實例名.實例自己的變量名)

3、類:
 優點:解決了程序的擴展性,對某個對象進行修改,會立刻反映到整個體系中
 缺點:可控性差,無法預測最終的結果。
  面向對象的程序設計並不是全部。對於軟件質量來說,面向對象的程序設計只是用來解決擴展性的問題。

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

4、類屬性:特征(變量)和方法(函數)

5、類有兩種方法:1.類的實例化;2.屬性引用
  1.實例化:
    類名加括號就是實例化,會自動觸發__init__函數的運行,可以用它來為每個實例定制自己的特征
  2.屬性引用:
    類名.方法

6、對象也稱為實例

  對象的屬性:對象本身就自有特征(變量)

  對象的只有一種用法:屬性引用

7、類的名稱空間和對象的名稱空間

創建一個類,就會創建一個類的名稱空間,存放類中定義的屬性:特征(數據)和方法(函數)
創建一個對象,及類的實例化,就會創建一個類的名稱空間,存放對象的屬性。

註意:對象就是類的實例化,類完成實例化的操作就已經將類的方法綁定到對象上,對象調用方法會現在自己的名稱空間去找,找不到會去類的名稱空間去找,再找不到會拋異常。它不會去找全局的定義。

查看類的名稱空間 類名._dict_
查看對象的名稱空間 對象名._dict_

綁定方法的核心在於‘綁定’,唯一綁定到一個確定的對象

可以調用:查
print(Garen.camp) #查

可以更改:改
Garen.camp=‘aaaaaa‘ #改
print(Garen.camp)

可以刪除: 刪
del Garen.camp #刪除
print(Garen.camp)

可以添加: 增
Garen.x=1 #增加特征
print(Garen.x)

關於對象(實例)

可以調用: 查
g1=Garen(‘alex‘)
print(g1.nick) #查

可以更改: 改
g1.nick=‘asb‘ #改
print(g1.nick)

可以刪除: 刪
del g1.nick
print(g1.nick) #刪

可以增加: 增
g1.sex=‘female‘
print(g1.sex) #增加

四、面向對象的軟件開發:

分為五部:

1、面向對象分析(object oriented analysis,OOA):
產品經理調研市場,考察,明確軟件的用途和應用場景。
2、面向對象設計(object oriented design,OOD):
根據需求,對每一部分進行具體的設計,例如:類的設計
3、面向對象編程(object oriented programming,OOP):
將設計編程成代碼
4、面向對象測試(object oriented test,OOT):
對寫好的代碼進行測試,發現錯誤並改正。面向對象的測試是用面向對象的方法進行測試,以類為測試的基本單元。
5、面向對象維護(object oriented soft maintenance,OOSM):
解決用戶使用產品過程中出現的問題,或是增加新的功能。

面向對象編程思想:
1、設計的時候,一定要明確應用場景

2、由對象分析定義類的時候,找不到共同特征和技能不用強求

python遞歸 及 面向對象初識及編程思想