D6 函數和模塊的使用

函數和模塊的使用

在講解本章節(jié)的內容之前,我們先來研究一道數學題阎肝,請說出下面的方程有多少組正整數解。

?

事實上,上面的問題等同于將8個蘋果分成四組每組至少一個蘋果有多少種方案牛欢。想到這一點問題的答案就呼之欲出了。

?

可以用Python的程序來計算出這個值淆游,代碼如下所示傍睹。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n7" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> """
?
輸入M和N計算C(M,N)
?
"""
?
m = int(input('m = '))
n = int(input('n = '))
fm = 1
for num in range(1, m + 1):
fm *= num
fn = 1
for num in range(1, n + 1):
fn *= num
fmn = 1
for num in range(1, m - n + 1):
fmn *= num
print(fm // fn // fmn)
?</pre>

函數的作用

不知道大家是否注意到,在上面的代碼中犹菱,我們做了3次求階乘拾稳,這樣的代碼實際上就是重復代碼。編程大師Martin Fowler先生曾經說過:“代碼有很多種壞味道已亥,重復是最壞的一種熊赖!”,要寫出高質量的代碼首先要解決的就是重復代碼的問題虑椎。對于上面的代碼來說震鹉,我們可以將計算階乘的功能封裝到一個稱之為“函數”的功能模塊中,在需要計算階乘的地方捆姜,我們只需要“調用”這個“函數”就可以了传趾。

定義函數

在Python中可以使用def關鍵字來定義函數,和變量一樣每個函數也有一個響亮的名字泥技,而且命名規(guī)則跟變量的命名規(guī)則是一致的浆兰。在函數名后面的圓括號中可以放置傳遞給函數的參數,這一點和數學上的函數非常相似,程序中函數的參數就相當于是數學上說的函數的自變量簸呈,而函數執(zhí)行完成后我們可以通過return關鍵字來返回一個值榕订,這相當于數學上說的函數的因變量。

在了解了如何定義函數后蜕便,我們可以對上面的代碼進行重構劫恒,所謂重構就是在不影響代碼執(zhí)行結果的前提下對代碼的結構進行調整,重構之后的代碼如下所示轿腺。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n13" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> def factorial(num):
"""
求階乘

:param num: 非負整數

:return: num的階乘
"""
result = 1
for n in range(1, num + 1):
result *= n
return result
?
?
m = int(input('m = '))
n = int(input('n = '))

當需要計算階乘的時候不用再寫循環(huán)求階乘而是直接調用已經定義好的函數

print(factorial(m) // factorial(n) // factorial(m - n))
?</pre>

說明:Python的math模塊中其實已經有一個factorial函數了两嘴,事實上要計算階乘可以直接使用這個現(xiàn)成的函數而不用自己定義。下面例子中的某些函數其實Python中也是內置了族壳,我們這里是為了講解函數的定義和使用才把它們又實現(xiàn)了一遍憔辫,實際開發(fā)中不建議做這種低級的重復性的工作。

函數的參數

函數是絕大多數編程語言中都支持的一個代碼的“構建塊”仿荆,但是Python中的函數與其他語言中的函數還是有很多不太相同的地方贰您,其中一個顯著的區(qū)別就是Python對函數參數的處理。在Python中拢操,函數的參數可以有默認值枉圃,也支持使用可變參數,所以Python并不需要像其他語言一樣支持函數的重載庐冯,因為我們在定義一個函數的時候可以讓它有多種不同的使用方式孽亲,下面是兩個小例子。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n19" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> from random import randint
?
?
def roll_dice(n=2):
"""
搖色子

:param n: 色子的個數

:return: n顆色子點數之和
"""
total = 0
for _ in range(n):
total += randint(1, 6)
return total
?
?
def add(a=0, b=0, c=0):
return a + b + c
?
?

如果沒有指定參數那么使用默認值搖兩顆色子

print(roll_dice())

搖三顆色子

print(roll_dice(3))
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))

傳遞參數時可以不按照設定的順序進行傳遞

print(add(c=50, a=100, b=200))
?</pre>

我們給上面兩個函數的參數都設定了默認值展父,這也就意味著如果在調用函數的時候如果沒有傳入對應參數的值時將使用該參數的默認值返劲,所以在上面的代碼中我們可以用各種不同的方式去調用add函數,這跟其他很多語言中函數重載的效果是一致的栖茉。

其實上面的add函數還有更好的實現(xiàn)方案篮绿,因為我們可能會對0個或多個參數進行加法運算,而具體有多少個參數是由調用者來決定吕漂,我們作為函數的設計者對這一點是一無所知的亲配,因此在不確定參數個數的時候,我們可以使用可變參數惶凝,代碼如下所示吼虎。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n22" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> # 在參數前使用*表示args是可變參數

也就是說調用add函數時傳入的參數個數可以是0個或多個

def add(*args):
total = 0
for val in args:
total += val
return total
?
?
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
print(add(1, 3, 5, 7, 9))
?</pre>

用模塊管理函數

對于任何一種編程語言來說,給變量苍鲜、函數這樣的標識符起名字都是一個讓人頭疼的問題思灰,因為我們會遇到命名沖突這種尷尬的情況。最簡單的場景就是在同一個.py文件中定義了兩個同名函數混滔,由于Python沒有函數重載的概念洒疚,那么后面的定義會覆蓋之前的定義歹颓,也就意味著兩個函數同名函數實際上只有一個是存在的。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n25" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> def foo():
print('hello, world!')
?
?
def foo():
print('goodbye, world!')
?
?
foo() # 輸出goodbye, world!
?</pre>

當然上面的這種情況我們很容易就能避免油湖,但是如果項目是由多人協(xié)作進行團隊開發(fā)的時候巍扛,團隊中可能有多個程序員都定義了名為foo的函數,那么怎么解決這種命名沖突呢乏德?答案其實很簡單电湘,Python中每個文件就代表了一個模塊(module),我們在不同的模塊中可以有同名的函數鹅经,在使用函數的時候我們通過import關鍵字導入指定的模塊就可以區(qū)分到底要使用的是哪個模塊中的foo函數,代碼如下所示怎诫。

module1.py

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n28" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> def foo():
print('hello, world!')</pre>

module2.py

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n30" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> def foo():
print('goodbye, world!')</pre>

test.py

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n32" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> from module1 import foo
?
foo() # 輸出hello, world!
?
from module2 import foo
?
foo() # 輸出goodbye, world!
?</pre>

也可以按照如下所示的方式來區(qū)分到底要使用哪一個foo函數瘾晃。

test.py

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n35" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> import module1 as m1
import module2 as m2
?
m1.foo()
m2.foo()
?</pre>

但是如果將代碼寫成了下面的樣子,那么程序中調用的是最后導入的那個foo幻妓,因為后導入的foo覆蓋了之前導入的foo蹦误。

test.py

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n38" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> from module1 import foo
from module2 import foo
?
foo() # 輸出goodbye, world!
?</pre>

test.py

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n40" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> from module2 import foo
from module1 import foo
?
foo() # 輸出hello, world!
?</pre>

需要說明的是,如果我們導入的模塊除了定義函數之外還中有可以執(zhí)行代碼肉津,那么Python解釋器在導入這個模塊時就會執(zhí)行這些代碼强胰,事實上我們可能并不希望如此,因此如果我們在模塊中編寫了執(zhí)行代碼妹沙,最好是將這些執(zhí)行代碼放入如下所示的條件中偶洋,這樣的話除非直接運行該模塊,if條件下的這些代碼是不會執(zhí)行的距糖,因為只有直接執(zhí)行的模塊的名字才是“main”玄窝。

module3.py

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n43" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> def foo():
pass
?
?
def bar():
pass
?
?

name是Python中一個隱含的變量它代表了模塊的名字

只有被Python解釋器直接執(zhí)行的模塊的名字才是main

if name == 'main':
print('call foo()')
foo()
print('call bar()')
bar()
?</pre>

test.py

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n45" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> import module3
?

導入module3時 不會執(zhí)行模塊中if條件成立時的代碼 因為模塊的名字是module3而不是main

?</pre>

練習

練習1:實現(xiàn)計算求最大公約數和最小公倍數的函數。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n48" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> def gcd(x, y):
(x, y) = (y, x) if x > y else (x, y)
for factor in range(x, 0, -1):
if x % factor == 0 and y % factor == 0:
return factor
?
?
def lcm(x, y):
return x * y // gcd(x, y)</pre>

練習2:實現(xiàn)判斷一個數是不是回文數的函數悍引。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n50" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> def is_palindrome(num):
temp = num
total = 0
while temp > 0:
total = total * 10 + temp % 10
temp //= 10
return total == num</pre>

練習3:實現(xiàn)判斷一個數是不是素數的函數恩脂。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="Python" cid="n52" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 0px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> def is_prime(num):
for factor in range(2, num):
if num % factor == 0:
return False
return True if num != 1 else False</pre>

練習4:寫一個程序判斷輸入的正整數是不是回文素數。

<pre spellcheck="false" class="md-fences mock-cm md-end-block md-fences-with-lineno" lang="Python" cid="n54" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 8px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">if name == 'main':
num = int(input('請輸入正整數: '))
if is_palindrome(num) and is_prime(num):
print('%d是回文素數' % num)
</pre>

通過上面的程序可以看出趣斤,當我們將代碼中重復出現(xiàn)的和相對獨立的功能抽取成函數后俩块,我們可以組合使用這些函數來解決更為復雜的問題,這也是我們?yōu)槭裁匆x和使用函數的一個非常重要的原因浓领。

最后玉凯,我們來討論一下Python中有關變量作用域的問題。

<pre spellcheck="false" class="md-fences mock-cm md-end-block md-fences-with-lineno" lang="Python" cid="n57" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 8px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">def foo():
b = 'hello'

def bar():  # Python中可以在函數內部再定義函數
    c = True
    print(a)
    print(b)
    print(c)

bar()
# print(c)  # NameError: name 'c' is not defined

if name == 'main':
a = 100
# print(b) # NameError: name 'b' is not defined
foo()
</pre>

上面的代碼能夠順利的執(zhí)行并且打印出100和“hello”联贩,但我們注意到了壮啊,在bar函數的內部并沒有定義ab兩個變量,那么ab是從哪里來的撑蒜。我們在上面代碼的if分支中定義了一個變量a歹啼,這是一個全局變量(global variable)玄渗,屬于全局作用域,因為它沒有定義在任何一個函數中狸眼。在上面的foo函數中我們定義了變量b藤树,這是一個定義在函數中的局部變量(local variable),屬于局部作用域拓萌,在foo函數的外部并不能訪問到它岁钓;但對于foo函數內部的bar函數來說,變量b屬于嵌套作用域微王,在bar函數中我們是可以訪問到它的屡限。bar函數中的變量c屬于局部作用域,在bar函數之外是無法訪問的炕倘。事實上钧大,Python查找一個變量時會按照“局部作用域”、“嵌套作用域”罩旋、“全局作用域”和“內置作用域”的順序進行搜索啊央,前三者我們在上面的代碼中已經看到了,所謂的“內置作用域”就是Python內置的那些隱含標識符min涨醋、len等都屬于內置作用域)瓜饥。

再看看下面這段代碼,我們希望通過函數調用修改全局變量a的值浴骂,但實際上下面的代碼是做不到的乓土。

<pre spellcheck="false" class="md-fences mock-cm md-end-block md-fences-with-lineno" lang="Python" cid="n60" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 8px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">def foo():
a = 200
print(a) # 200

if name == 'main':
a = 100
foo()
print(a) # 100
</pre>

在調用foo函數后,我們發(fā)現(xiàn)a的值仍然是100溯警,這是因為當我們在函數foo中寫a = 200的時候帐我,是重新定義了一個名字為a的局部變量,它跟全局作用域的a并不是同一個變量愧膀,因為局部作用域中有了自己的變量a拦键,因此foo函數不再搜索全局作用域中的a。如果我們希望在foo函數中修改全局作用域中的a檩淋,代碼如下所示芬为。

<pre spellcheck="false" class="md-fences mock-cm md-end-block md-fences-with-lineno" lang="Python" cid="n62" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 8px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">def foo():
global a
a = 200
print(a) # 200

if name == 'main':
a = 100
foo()
print(a) # 200
</pre>

我們可以使用global關鍵字來指示foo函數中的變量a來自于全局作用域,如果全局作用域中沒有a蟀悦,那么下面一行的代碼就會定義變量a并將其置于全局作用域媚朦。同理,如果我們希望函數內部的函數能夠修改嵌套作用域中的變量日戈,可以使用nonlocal關鍵字來指示變量來自于嵌套作用域询张,請大家自行試驗。

在實際開發(fā)中浙炼,我們應該盡量減少對全局變量的使用份氧,因為全局變量的作用域和影響過于廣泛唯袄,可能會發(fā)生意料之外的修改和使用,除此之外全局變量比局部變量擁有更長的生命周期蜗帜,可能導致對象占用的內存長時間無法被垃圾回收恋拷。事實上,減少對全局變量的使用厅缺,也是降低代碼之間耦合度的一個重要舉措蔬顾,同時也是對迪米特法則的踐行。減少全局變量的使用就意味著我們應該盡量讓變量的作用域在函數的內部湘捎,但是如果我們希望將一個局部變量的生命周期延長诀豁,使其在函數調用結束后依然可以訪問,這時候就需要使用閉包窥妇,這個我們在后續(xù)的內容中進行講解舷胜。

說明:很多人經常會將“閉包”一詞和“匿名函數”混為一談,但實際上它們是不同的概念秩伞,如果想提前了解這個概念,推薦看看維基百科或者知乎上對這個概念的討論欺矫。

說了那么多纱新,其實結論很簡單,從現(xiàn)在開始我們可以將Python代碼按照下面的格式進行書寫穆趴,這一點點的改進其實就是在我們理解了函數和作用域的基礎上跨出的巨大的一步脸爱。

<pre spellcheck="false" class="md-fences mock-cm md-end-block md-fences-with-lineno" lang="Python" cid="n68" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Cascadia Code", "Microsoft YaHei", Cousine, Consolas, monospace; font-size: 0.75rem; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(251, 251, 251); position: relative !important; padding-left: 8px; width: auto; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">def main():
# Todo: Add your code here
pass

if name == 'main':
main()
</pre>

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市未妹,隨后出現(xiàn)的幾起案子簿废,更是在濱河造成了極大的恐慌,老刑警劉巖络它,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件族檬,死亡現(xiàn)場離奇詭異,居然都是意外死亡化戳,警方通過查閱死者的電腦和手機单料,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來点楼,“玉大人扫尖,你說我怎么就攤上這事÷永” “怎么了换怖?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蟀瞧。 經常有香客問我沉颂,道長条摸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任兆览,我火速辦了婚禮屈溉,結果婚禮上,老公的妹妹穿的比我還像新娘抬探。我一直安慰自己子巾,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布小压。 她就那樣靜靜地躺著线梗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怠益。 梳的紋絲不亂的頭發(fā)上仪搔,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音蜻牢,去河邊找鬼烤咧。 笑死,一個胖子當著我的面吹牛抢呆,可吹牛的內容都是我干的煮嫌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼抱虐,長吁一口氣:“原來是場噩夢啊……” “哼昌阿!你這毒婦竟也來了?” 一聲冷哼從身側響起恳邀,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤懦冰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谣沸,有當地人在樹林里發(fā)現(xiàn)了一具尸體刷钢,經...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年乳附,在試婚紗的時候發(fā)現(xiàn)自己被綠了闯捎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡许溅,死狀恐怖瓤鼻,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情贤重,我是刑警寧澤茬祷,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站并蝗,受9級特大地震影響祭犯,放射性物質發(fā)生泄漏秸妥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一沃粗、第九天 我趴在偏房一處隱蔽的房頂上張望粥惧。 院中可真熱鬧,春花似錦最盅、人聲如沸突雪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咏删。三九已至,卻和暖如春问词,著一層夾襖步出監(jiān)牢的瞬間督函,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工激挪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辰狡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓垄分,卻偏偏與公主長得像宛篇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锋喜,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348