09. Python語言的核心編程 · 第九章 Python語言的函數(中)

前情回顧:

  上一篇文章,看似講了不少,不過呢 講來講去圍繞的都還是 括號裏的一些內容( def xxx(): ),今天這篇文章呢,我們來講一些哪些括號之外的 神奇世界

  在開始今天的內容之前,我們先回顧一下我們上一篇主要講的核心案例:

# 求任意數的和

def fn(*nums):
    result = 0
    for x in nums:
        result += x

    print(result)

fn(2,9,7,3)		# 21

  向函數方法 fn() 內傳遞任意個數的參數,通過 for 循環將所有傳遞進來的參數 nums 通過 變量x 都 遍歷 出來,並通過在 for 循環外預先設定好的 變量result 將所有遍歷到的數據 相加,最後在 for 循環外將任意數的和 print(result) 出來。如果對這個開頭有什麼疑問的可以重新去看看我之前的文章。
  那麼,接下來我們要想哈:雖然我讓這個函數爲我們進行計算任意數的和,但是計算後的結果我們一定需要函數輸出嗎? 或者問:我們能不能把這個計算結果拿去 做別的我們需要的事情
  就上面的案例我們發現:我們把參數傳遞進去,計算完之後就通過 print( ) 語句把結果輸出了。就上面的案例,輸出的結果我們是否還無法拿去做別的事情;最起碼的上面的案例是做不到的。爲什麼?因爲這個 變量result 我們都沒拿到,它至始至終都在函數的內部;無法做到 我想讓它計算它就計算,我想讓它打印,它就打印,無法做到明確控制。
  講到這,下面就開始我們今天的要講幾個主要內容。

  

1. 函數的返回值

  返回值就是函數執行以後返回的結果
  通過 return 來指定函數的返回值;
  我們可以通過一個變量來接收函數的返回值,或者可以直接函數來使用函數的返回值;

  參考實例:

  1) 單純的打印一個有返回值的函數是不會有任何的結果的;

def fn():
    return 100

fn()						# 

  2) 我們可以通過一個變量來接收函數,直接打印變量裏的函數返回值;

def fn():
    return 100				# int

r = fn()
print(r)					# 100
print(fn())					# 100

#-------------------------------------------------------------------------------

def fn():
    return 'Python'			# str

r = fn()
print(r)					# Python
print(fn())					# Python

#-------------------------------------------------------------------------------

def fn():
    return [1, 2, 3]		# 列表

r = fn()
print(r)					# [1, 2, 3]
print(fn())					# [1, 2, 3]

#-------------------------------------------------------------------------------

def fn():
    return {'name':'張三'}	# 字典

r = fn()
print(r)					# {'name':'張三'}
print(fn())					# {'name':'張三'}

#-------------------------------------------------------------------------------

def fn():
    def fn2():
        print('Hello')

    return fn2

r = fn()
print(r)        			# <function fn.<locals>.fn2 at 0x000001648ED80940>
print(fn())     			# <function fn.<locals>.fn2 at 0x0000018DEE630A60>
r()             			# Hello

  通過以上實例,我們還得出一個結論:return 後面可以跟 任意對象 ,返回值 甚至 可以是一個 函數

  重點:如果函數裏僅僅只寫一個 return 或者不寫 return ,則相當於函數 return Noun。

def fn():

    return

r = fn()
print(r)					# None

#-------------------------------------------------------------------------------

def fn():
    print('Hello')
    print('123')

r = fn()
print(r)					# Hello
							# 123
							# None

  在函數中,執行到 return 以後就要 返回結果 了,換個解釋方式:return 以後的所有代碼塊將 不會執行;return 一旦執行,函數將 自動結束。(到這裏,大家有沒有發現:這個 return 和我們之前的 5. Python 條件控制語句細解 裏講到的循環函數 break 很相似啊)
  參考實例:

def fn():
    print('Hello')
    return
    print('123')

r = fn()					# Hello

#-------------------------------------------------------------------------------

def fn():

    for i in range(5):
        if i == 3:
            break
        print(i)
    print('循環執行完畢')

fn()
# 0
# 1
# 2
# 循環執行完畢

#-------------------------------------------------------------------------------

def fn():

    for i in range(5):
        if i == 3:
            return
        print(i)
    print('循環執行完畢')

fn()
# 0
# 1
# 2

  回到我們最初開始的案例,現在我們對它進行一點點簡單的補充和修改:

# 求任意數的和

def fn(*nums):
    result = 0
    for x in nums:
        result += x

    return result

r = fn(2,9,7,3)
print(r)					# 21
print(r+17)					# 38

  通過剛講解完的函數的返回值 return 順帶着我們再重新的回顧一下我們上一篇文章裏提到的另一個問題:一個函數在調用的時候,它的後面 跟 () 是什麼意思,不跟 () 又是什麼意思。
  看參考實例:

def fn():

    return 100


print(fn)					# <function fn at 0x00000162FE0FE160>
print(fn())					# 100

  通過上面實例,我們再回顧一下結果:一個函數在調用的時候,它的後面跟 () 是 調用函數名爲 fn 的函數 的意思,不跟 () 是 對象 fn 的意思;解釋一下 參考案例 裏print(fn)打印出來的內容<function fn at 0x00000162FE0FE160>的意思:該對象是一個函數(function) 函數的名字叫fn 它的存在地址於(at)你電腦內存的 0x00000162FE0FE160。

  

2. 文檔字符串  help()

  help() 是Python中內置函數,我們可以通過help()函數可以查詢Python中 函數的用法
  參考實例:

help(print)


'''
輸出結果:

Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.
    
'''

  即然我們打印了 函數print 的功能,這裏呢加一個能讓你小小的秀一下操作的小技巧:

# 首先先常規的打印一段字符串:

print('www','baidu','com')				# www baidu com

#-------------------------------------------------------------------------------

# 修改以下 函數 print() 裏的屬性 sep=' ' 爲 sep='.'

print('www','baidu','com',sep='.')		# www.baidu.com

  在定義函數時,可以在函數內部編寫文檔字符串,文檔字符串就是對函數的說明。
  參考實例:

def fn(a:bool,b:int,c:str)->int:

    '''

    這個函數是一個文檔字符串實例
    參數
        :param a: 作用  類型  默認值  ...
        :param b: 作用  類型  默認值  ...
        :param c: 作用  類型  默認值  ...
        :return:

    '''

    return 100

help(fn)

'''
輸出結果:
Help on function fn in module __main__:

fn(a: bool, b: int, c: str) -> int
    這個函數是一個文檔字符串實例
    參數
        :param a: 作用  類型  默認值  ...
        :param b: 作用  類型  默認值  ...
        :param c: 作用  類型  默認值  ...
        :return:
        
'''

# 補充:解釋一下這段話的意思  fn(a: bool, b: int, c: str) -> int
# 函數fn 的輸入形參a要爲布爾值,輸入形參b要爲整型,輸入形參c要爲字符串;函數的返回值是一個 整形

  

3. 函數的作用域

3.1 作用域(scope)

  作用域指的是 變量生效的區域

def fn():
    a = 10       					 # 變量a 定義在了函數內部,所以它的作用域就是函數內部;函數外部是無法訪問到函數內部的變量a 的。
    print('函數內部變量 a =',a)       # 函數內部變量 a = 10
    return a

fn()
print('函數外部變量 a =',a)           # NameError: name 'a' is not defined

#-------------------------------------------------------------------------------

b = 50
def fn():
    a = 10
    print('函數內部變量 a =',a)       # 函數內部變量 a = 10
    print('函數內部變量 b =', b)      # 函數內部變量 b = 50

fn()
# print('函數外部變量 a =',a)         # NameError: name 'a' is not defined
print('函數外部變量 b =',b)           # 函數外部變量 b = 50

  通過上面的參考實例我們發現 函數在不同的位置它最終訪問到的結果是不一樣的。在Python中一共有兩種作用域:全局作用域函數作用域

3.2 全局作用域

  全局作用域在程序執行時創建,在程序執行結束時銷燬;
  所有函數以外的區域都是全局作用域;
  在全局作用域中定義的變量,都是全局變量,全局變量可以在程序的任意位置進行訪問。

3.3 函數作用域

  函數作用域在函數調用時創建,在調用結束時銷燬;
  函數每調用一次就會產生一個新的函數作用域;
  在函數作用域中定義的變量,都是局部變量,它只能在函數內部被訪問。

3.4 關鍵字 global

  如果希望 在函數內部 修改 全局變量,則使用 global 關鍵字來聲明變量。
  global 關鍵字的作用是:聲明在函數的內部使用的 變量a 是 全局變量,則此時再去修改 變量a 時,就是在修改全局變量。

  參考實例:

def fn():
    a = 10
    def fn2():
        print('函數 fn2 內部變量 a =',a)
    fn2()
fn()							# 函數 f2 內部變量 a = 10

#-------------------------------------------------------------------------------

def fn():
    a = 10
    def fn2():
        a = 50
        print('函數 fn2 內部變量 a =',a)
    fn2()
fn()							# 函數 f2 內部變量 a = 50

#-------------------------------------------------------------------------------

a = 1							# 全局變量
def fn():
    # global a					# 如果希望在函數內部修改全局變量,則使用 global 關鍵字來聲明變量。
    a = 10						# 聲明在函數的內部使用的變量a是全局變量,則此時再去修改變量a時,就是在修改全局變量。
    def fn2():
        # global a				# 如果希望在函數內部修改全局變量,則使用 global 關鍵字來聲明變量。
    	a = 20					# 聲明在函數的內部使用的變量a是全局變量,則此時再去修改變量a時,就是在修改全局變量。
        print('函數 fn2 內部變量 a =', a)
        def fn3():
            # global a			# 如果希望在函數內部修改全局變量,則使用 global 關鍵字來聲明變量。
    		a = 30				# 聲明在函數的內部使用的變量a是全局變量,則此時再去修改變量a時,就是在修改全局變量。
            print('函數 fn3 內部變量 a =', a)
        fn3()
    fn2()
    print('函數 fn 內部變量 a =',a)
fn()

print('函數 外部變量 a =',a)
# 函數 fn2 內部變量 a = 20
# 函數 fn3 內部變量 a = 30
# 函數 fn 內部變量 a = 10
# 函數 外部變量 a = 30

  

4. 命名空間

  Python一切皆對象,操作的數據不論是操作數字、字符串、函數、類、模塊 這些都是對象。在這一切對象當中有個非常重要的角色,它就是:命名空間
  命名空間,名字很高大上,實際上就是 字典 的一種操作方法;因爲它的名字很高大上,所以除了偶爾裝X的時候可以拿出來秀秀技術以外,就是在 面試 的時候 常常都會被問到
  命名空間實際上就是一個 字典,是一個專門用來 存儲變量 的字典;
  函數 locals() 用來 獲取當前作用域的命名空間,函數locals() 的 返回值 是一個 字典
  我們先打印操作以下,看下函數 locals() 的返回值。參考實例:

a = 2

def fn():
    global a
    a = 50
    print('函數內部:a =',a)

s = locals()

print(s)
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000026B63FC0910>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'G:/lianxi/測試2.py', '__cached__': None, 'a': 2, 'fn': <function fn at 0x0000026B65C8E160>, 's': {...}}

  以上面的參考實例爲基礎,變量 a = 2 它被加載到內存當中,它是需要被調用或是需要被引用的。Python語言此時的操作就類似於 C語言 裏的 指針 去指向了這個對象,這個“指針”就是我們所說的 命名空間,或者叫 名稱空間;嚴格意義來說,Python裏也有這麼類似的一個“指針”,或者說是這麼的一種對 對象引用雖然它很重要,但是大家也別想的那麼的複雜。我們通過這個 指針 就可以引用這個 指針 所指向的對象內存地址值中的代碼塊。

  不論是操作數字、字符串、函數、類、模塊 這些都是對象對象對象,說白了就是 我們去內存引用來的一塊區域。任你千變萬化,你都只是 在內存空間裏 的,都只是預先設定好的一個代碼塊。只是此時,我們的代碼在執行的時候是 以命名空間爲單位進行執行 的代碼。

  做了那麼多的解釋,接下來我們嘗試着來看看 命名空間 怎麼使用:
  基於開始 命名空間 最初的案例我們知道以下這段代碼最後的兩個輸出結果都是 2 :

a = 2

def fn():
    global a
    a = 50
    print('函數內部:a =',a)

s = locals()

print(a)					# 2
print(s['a'])				# 2

  基於上面的實例,如果我想打印一個 變量b ,最後會是什麼結果?我們來嘗試一下:

a = 2

def fn():
    global a
    a = 50
    print('函數內部:a =',a)

s = locals()

print(b)					# NameError: name 'b' is not defined

  是不是出現 NameError 這個提示了,是不是沒有這個變量啊。只能在打印 變量b 前設定好相對應的 變量和值 纔可以正常的打印啊。如:

a = 2

def fn():
    global a
    a = 50
    print('函數內部:a =',a)

s = locals()

b = 100

print(b)					# 100

  接下來,我們用 命名空間 的方法來演示操作一下:如何在 不以常規的命名變量 的前提下能讓我們正常的打印出 變量b。
  參考實例:

a = 2

def fn():
    global a
    a = 50
    print('函數內部:a =',a)

s = locals()

s['b'] = 100

print(b)					# 100

  看我文章的朋友,如果你們在使用我在文章 2. Python要點 裏推薦的 Python編輯工具 PyCharm 操作上面這段的代碼的話,你們會發現:最後 print(b) 的 b 編輯器給的提示還是報錯的呢,爲什麼最後卻還是能打印出一個結果呢?
  回到前面我們說過: 命名空間 實際上就是一個 字典,是一個專門用來 存儲變量 的字典;函數 locals() 用來 獲取當前作用域的命名空間,函數locals() 的 返回值 是一個 字典。代碼 s['b'] = 100 實際的意思是:向 命名空間 s = locals() 裏傳遞進一個 鍵·值對,這個 鍵·值對 的鍵是b,值是 100;整個 print(b) 的操作完整的解析是:打印 字典s 裏的鍵爲 b 的值。
  現在,我們再重新的打印一下 s 來看看它最新的結果:

a = 2

def fn():
    global a
    a = 50
    print('函數內部:a =',a)

s = locals()

s['b'] = 100

print(s)
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001CB407D0910>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'G:/lianxi/測試2.py', '__cached__': None, 'a': 2, 'fn': <function fn at 0x000001CB4097D160>, 's': {...}, 'b': 100}

  此時,我們再打印 s 的時候,字典s 的最後是不是多了一個'b': 100
  解釋完了 函數 locals() 以及如何操作 locals()的打印值後,我們再回顧上一段內容遺留的一個沒有解釋的問題:最後 print(b) 的 b 在 PyCharm 編輯器給的提示還是報錯,爲什麼最後卻還是能打印出一個結果呢?原因呢其實也很簡單,Python解釋器其實不認可這種操作的。你這麼操作沒什麼錯,但是這種操作你知道就可以了,一般不建議這麼的操作;這是一種非常規的操作。畫蛇添足,反而麻煩了。

  另外呢,還有一點:如果在全局作用域中調用 函數locals() 則獲取全局命名空間,如果在函數作用域中調用 函數locals() 則獲取函數命名空間
  參考實例:

def fn2():

    s = locals()			# 獲取函數內部的命名空間
    print(s)

fn2()						# {}

#-----------------------------------------------------------------------------------

def fn2():
    a = 10
    s = locals()
    s['b'] = 50
    print(s)

fn2()						# {'a': 10, 'b': 50}

#-----------------------------------------------------------------------------------

# 如何實現在函數的內部獲取 全局的命名空間 ?

a = 2

def fn():
    global a
    a = 50
    print('函數內部:a =',a)

s = locals()

print(a)					# 2

s['b'] = 100
print(b)					# 100
print(s)					# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000027C26000910>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'G:/lianxi/測試2.py', '__cached__': None, 'a': 2, 'fn': <function fn at 0x0000027C27C9D160>, 's': {...}, 'b': 100}


def fn2():
    global_s = globals()
    global_s['a'] = 390
    print(global_s)
fn2()						# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000027C26000910>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'G:/lianxi/測試2.py', '__cached__': None, 'a': 390, 'fn': <function fn at 0x0000027C27C9D160>, 's': {...}, 'b': 100, 'fn2': <function fn2 at 0x0000027C27CB0940>}

print(a)					# 390

  

5. 遞歸函數

  指數級增長 我相信大家應該都聽過,所謂的“指數”就是 xxx 的 nn 次方;但是,相比於 指數級增長 還有一中更可怕的增長方式不知道大家聽過沒有,那就是“階乘式遞增”。在介紹什麼是“階乘式遞增”之前,讓我們先認識一下計算機實現“階乘式遞增”的語法:“遞歸”。

  接下來我們來通過一系列的案例來理解什麼是 遞歸

  案例:嘗試求 10 的階乘 (10!)
  在嘗試實現“10 的階乘”之前我們先分析一下:什麼是“10 的階乘”?
  接下來我們來看什麼是 階乘
    1 的階乘:1! = 1
    2 的階乘:2! = 1 * 2
    3 的階乘:3! = 1 * 2 * 3
    10 的階乘:10! = 1 * 2 * 3…* 8 * 9 * 10 = 3628800
  即然現在我們知道什麼是 階乘 了,那麼怎麼實現“10 的階乘”也就簡單了:
  參考實例:

print(1*2*3*4*5*6*7*8*9*10)		# 3628800

  手動實現“10 的階乘”當然 So easy 了,那如果需要實現 “1000 的階乘” ,我們該怎麼操作呢?此時此刻我們是不是需要循環了。(小提示:while 、 for 、 *=)
  參考實例:

b = 1000
for x in range(1,b):		# 嘗試一下:和 for x in range(a) 有啥區別 :)
    b *= x
print(b)					# 結果還是由你親自實現吧,別被震撼到喲。反正,我第一眼看到的時候直接哭了~

  接下來 “任意數 的階乘”我想你不需要怎麼思考心裏馬上就有答案了吧。
  參考實例:定義一個函數,函數功能 “實現任意數 的階乘”

def fn(n):
    # 參數n:要求階乘的數字
    # n = a
    # 定義一個變量,保存結果
    result = n
    for i in range(1,n):	# 嘗試一下:和 for i in range(n): 有啥區別 :)
        result *= i
    return result

fn(20)            #
# print(fn())     # TypeError: fn() missing 1 required positional argument: 'n'
# print(fn)       # <function fn at 0x0000012591FEE160>
print(fn(20))     # 2432902008176640000

# 爲什麼我要打印這麼多的結果,因爲我之前的語法不嚴謹 導致了這次我在這一段裏的醜態百出。寫在此處,引以爲戒。有些語法爲什麼這麼寫,都是有它合乎邏輯的道理的。

  到此呢,我們也知道什麼是 階乘 了,也知道怎麼通過代碼來實現 階乘 了,可是現在廢話了半天,這些和現在講的 遞歸 又有什麼關係呢?
  我們現在一直在說的 遞歸,完整的叫法應該叫做 遞歸式函數。那 遞歸式函數 又是什麼呢? 遞歸 簡單的理解就是:自己 引用 自己遞歸式函數:在函數中,自己 調用 自己。用一個通俗而且我們小時候都講過的一個小故事來直接打通這個問題:從前有座山,山裏有座廟,廟裏有個老和尚在給小和尚講故事,講什麼故事呢?從前有座山,山裏有座廟,廟裏有個老和尚……
  參考實例:無窮遞歸

def fn():
    fn()
fn()

  這種“無窮遞歸”,只要你的電腦性能稍微差點,就會導致死機;類似於“死循環”。

  不過呢,我們也沒必要妖魔化 遞歸 ,它只是一個 解決問題的方式,和 循環 很像;它的 整體思想 是:將一個大問題 分解 爲一個個的 小問題,直到問題 無法分解 時,再去解決問題。
  遞歸式函數有 2個條件
  1. 基線條件:問題可以被分解爲 最小問題,當滿足基線條件時,遞歸就 不執行 了;
  2. 遞歸條件:可以將問題 繼續分解 的條件。

  那我們現在再回到最初的問題:用 遞歸 的方式求“任意數的階乘”。
  我們現在先拆解一下用 遞歸 的方式求“任意數的階乘”的 2個條件:

  2. 遞歸條件:10! = 10 * 9!
         9! = 9 * 8!
         8! = 8 * 7!
         ………
  1. 基線條件:1! = 1

  參考實例:

def fn(n):
    # 參數 n 要求階乘的數字

    # 1. 基線條件
    if n == 1:
        return 1

    # 2. 遞歸條件
    return n * fn(n-1)		# return 10 * 9!

print(fn(10))				# 3628800

  
  
  

總結小便條

本篇文章主要講了以下幾點內容:

  1. 函數的返回值:
    • 返回值就是函數執行以後返回的結果;
    • 通過 return 來指定函數的返回值;
    • return 後面可以跟任意對象,返回值甚至可以是一個函數。
  2. 文檔字符串:
    • help() 是 Python 中內置函數,通過 help() 函數可以查詢Python中函數的用法;
    • 在定義函數時,可以在函數內部編寫文檔字符串,文檔字符串就是對函數的說明。
  3. 函數的作用域:
    • 作用域(scope);
      作用域指的是變量生效的區域;
      在Python中一共有兩種作用域。
    • 全局作用域:
      全局作用域在程序執行時創建,在程序執行結束時銷燬;
      所有函數以外的區域都是全局作用域;
      在全局作用域中定義的變量,都是全局變量,全局變量可以在程序的任意位置進行訪問。
    • 函數作用域:
      函數作用域在函數調用時創建,在調用結束時銷燬;
      函數每調用一次就會產生一個新的函數作用域;
      在函數作用域中定義的變量,都是局部變量,它只能在函數內部被訪問。
  4. 命名空間:
    • 命名空間實際上就是一個字典,是一個專門用來存儲變量的字典;
    • locals()用來獲取當前作用域的命名空間;
    • 如果在全局作用域中調用locals()則獲取全局命名空間,如果在函數作用域中調用locals()則獲取函數命名空間;
    • 返回值是一個字典。
  5. 遞歸函數:
    • 遞歸是解決問題的一種方式,它的整體思想,是將一個大問題分解爲一個個的小問題,直到問題無法分解時,在去解決問題;
    • 遞歸式函數有2個條件:
      1. 基線條件 問題可以被分解爲最小問題,當滿足基線條件時,遞歸就不執行了;
      2. 遞歸條件 可以將問題繼續分解的條件。

  本章回顧暫時就到這了,如果還有點暈,那就去完成作業吧。拜拜~

  
  
  

作業

  1. 創建一個函數,爲任意數做任意次冪運算
  2. 定義一個函數,用來檢測一個任意字符是否是迴文。如果是,返回True;如果不是,返回Falsse。
  3. 漢諾塔遊戲,現在有ABC三根柱子。要求:將A柱所有的圓盤放到C柱。在移動的過程中可以藉助B柱。並且規定大圓盤不能放小圓盤上面,每次只能移動一個盤子。用遞歸的方式來解決漢諾塔問題。

  
  
  

參考答案

def fn(n,i):                      			# 參數n要做冪運算的數字;參數i要做冪運算的次數

    if i == 1:                    			# 1. 基數條件
        return n

    # return n * n ** (i-1)       			# 2. 遞歸條件
    return n * fn(n,i-1)

print(fn(5,4))
print(5**4)

#-----------------------------------------------------------------------------------

# 先檢查首字符和尾字符是否一致,如果不一致 Falsse ,一定不是迴文;
# 如果是,後續則一次檢查
# abcdefedcba   檢查是否是 迴文
# bcdefedcb
# cdefedc
# defed
# efe
# f

# 方法一:
def fn(s):									# 參數 s 就是要檢查的字符串。
    
    if len(s) < 2:							# 1. 基數條件       # 字符串長度小於2,則該字符串一定爲 迴文。
        return True
    
    elif s[0] != s[-1]:						# 首字符 和 尾字符不相同,則一定不是迴文
        return False

    return fn(s[1:-1])						# 2. 遞歸條件       # 切片

print(fn('aba'))

# 方法二:

def fn(s):									# 參數 s 就是要檢查的字符串。

    if len(s)<2:							# 1. 基數條件       # 字符串長度小於2,則該字符串一定爲 迴文。
        return True

    return s[0] == s[-1] and fn(s[1:-1])	# 2. 遞歸條件       # 首字符 和 尾字符不相同,則一定不是迴文      # 切片

print(fn('Hallo'))

#-----------------------------------------------------------------------------------

# 1. 如果只有一個盤子: A --> C
# 2. 如果盤子數 >= 2,我們統一看成2個盤子,分別是“底盤”和“盤堆”。
# 2.1 把最上面的盤子    A --> B
# 2.2 把最下面的盤子    A --> C
# 2.3 把B柱的盤子放到C  B --> C



num = int(input('請輸入羅馬盤的數量:'))		# 定義一個函數,解決 漢諾塔 問題

def hannuoTower(num,a,b,c):					# 參數:num:盤子數;a:a柱;b:b柱;c:c柱。
    
    if num == 1:							# 基數條件
        print('第 1 個盤從',a,'->',c)
    else:									# 遞歸條件          	    # num >= 2
        hannuoTower(num-1,a,c,b)			# 2.1 把最上面的盤子     A --> B
        print('第',num,'個盤從',a,'->',c)	# 2.2 把最下面的盤子     A --> C
        hannuoTower(num-1,b,a,c)			# 2.3 把B柱的盤子放到C   B --> C

hannuoTower(num,'A','B','C')
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章