亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python函數(shù)和模塊的使用總結(jié)

 更新時間:2019年05月20日 15:21:30   投稿:laozhang  
在本文中小編給大家整理了關(guān)于Python函數(shù)和模塊的使用的相關(guān)知識點以及實例代碼內(nèi)容,需要的朋友們跟著學(xué)習(xí)下。

函數(shù)和模塊的使用

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

$$x_1 + x_2 + x_3 + x_4 = 8$$

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

$$C_M^N =\frac{M!}{N!(M-N)!}, \text{(M=7, N=3)} $$

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

"""
輸入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)

函數(shù)的作用

不知道大家是否注意到,在上面的代碼中,我們做了3次求階乘,這樣的代碼實際上就是重復(fù)代碼。編程大師Martin Fowler先生曾經(jīng)說過:“代碼有很多種壞味道,重復(fù)是最壞的一種!”,要寫出高質(zhì)量的代碼首先要解決的就是重復(fù)代碼的問題。對于上面的代碼來說,我們可以將計算階乘的功能封裝到一個稱之為“函數(shù)”的功能模塊中,在需要計算階乘的地方,我們只需要“調(diào)用”這個“函數(shù)”就可以了。

定義函數(shù)

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

在了解了如何定義函數(shù)后,我們可以對上面的代碼進(jìn)行重構(gòu),所謂重構(gòu)就是在不影響代碼執(zhí)行結(jié)果的前提下對代碼的結(jié)構(gòu)進(jìn)行調(diào)整,重構(gòu)之后的代碼如下所示。

def factorial(num):
  """
  求階乘
  
  :param num: 非負(fù)整數(shù)
  :return: num的階乘
  """
  result = 1
  for n in range(1, num + 1):
    result *= n
  return result


m = int(input('m = '))
n = int(input('n = '))
# 當(dāng)需要計算階乘的時候不用再寫循環(huán)求階乘而是直接調(diào)用已經(jīng)定義好的函數(shù)
print(factorial(m) // factorial(n) // factorial(m - n))

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

函數(shù)的參數(shù)

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

from random import randint


def roll_dice(n=2):
  """
  搖色子
  
  :param n: 色子的個數(shù)
  :return: n顆色子點數(shù)之和
  """
  total = 0
  for _ in range(n):
    total += randint(1, 6)
  return total


def add(a=0, b=0, c=0):
  return a + b + c


# 如果沒有指定參數(shù)那么使用默認(rèn)值搖兩顆色子
print(roll_dice())
# 搖三顆色子
print(roll_dice(3))
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
# 傳遞參數(shù)時可以不按照設(shè)定的順序進(jìn)行傳遞
print(add(c=50, a=100, b=200))

我們給上面兩個函數(shù)的參數(shù)都設(shè)定了默認(rèn)值,這也就意味著如果在調(diào)用函數(shù)的時候如果沒有傳入對應(yīng)參數(shù)的值時將使用該參數(shù)的默認(rèn)值,所以在上面的代碼中我們可以用各種不同的方式去調(diào)用add函數(shù),這跟其他很多語言中函數(shù)重載的效果是一致的。

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

# 在參數(shù)名前面的*表示args是一個可變參數(shù)
# 即在調(diào)用add函數(shù)時可以傳入0個或多個參數(shù)
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))

用模塊管理函數(shù)

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

def foo():
  print('hello, world!')


def foo():
  print('goodbye, world!')


# 下面的代碼會輸出什么呢?
foo()

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

module1.py

def foo():
  print('hello, world!')

module2.py

def foo():
  print('goodbye, world!')

test.py

from module1 import foo

# 輸出hello, world!
foo()

from module2 import foo

# 輸出goodbye, world!
foo()

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

test.py

import module1 as m1
import module2 as m2

m1.foo()
m2.foo()

但是如果將代碼寫成了下面的樣子,那么程序中調(diào)用的是最后導(dǎo)入的那個foo,因為后導(dǎo)入的foo覆蓋了之前導(dǎo)入的foo。

test.py

from module1 import foo
from module2 import foo

# 輸出goodbye, world!
foo()

test.py

from module2 import foo
from module1 import foo

# 輸出hello, world!
foo()

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

module3.py

def foo():
  pass


def bar():
  pass


# __name__是Python中一個隱含的變量它代表了模塊的名字
# 只有被Python解釋器直接執(zhí)行的模塊的名字才是__main__
if __name__ == '__main__':
  print('call foo()')
  foo()
  print('call bar()')
  bar()

test.py

import module3

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

練習(xí)

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

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)

練習(xí)2:實現(xiàn)判斷一個數(shù)是不是回文數(shù)的函數(shù)。

def is_palindrome(num):
  temp = num
  total = 0
  while temp > 0:
    total = total * 10 + temp % 10
    temp //= 10
  return total == num

練習(xí)3:實現(xiàn)判斷一個數(shù)是不是素數(shù)的函數(shù)。

def is_prime(num):
  for factor in range(2, num):
    if num % factor == 0:
      return False
  return True if num != 1 else False

練習(xí)4:寫一個程序判斷輸入的正整數(shù)是不是回文素數(shù)。

if __name__ == '__main__':
  num = int(input('請輸入正整數(shù): '))
  if is_palindrome(num) and is_prime(num):
    print('%d是回文素數(shù)' % num)

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

最后,我們來討論一下Python中有關(guān)變量作用域的問題。

def foo():
  b = 'hello'

  def bar(): # Python中可以在函數(shù)內(nèi)部再定義函數(shù)
    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()

上面的代碼能夠順利的執(zhí)行并且打印出100和“hello”,但我們注意到了,在bar函數(shù)的內(nèi)部并沒有定義a和b兩個變量,那么a和b是從哪里來的。我們在上面代碼的if分支中定義了一個變量a,這是一個全局變量(global variable),屬于全局作用域,因為它沒有定義在任何一個函數(shù)中。在上面的foo函數(shù)中我們定義了變量b,這是一個定義在函數(shù)中的局部變量(local variable),屬于局部作用域,在foo函數(shù)的外部并不能訪問到它;但對于foo函數(shù)內(nèi)部的bar函數(shù)來說,變量b屬于嵌套作用域,在bar函數(shù)中我們是可以訪問到它的。bar函數(shù)中的變量c屬于局部作用域,在bar函數(shù)之外是無法訪問的。事實上,Python查找一個變量時會按照“局部作用域”、“嵌套作用域”、“全局作用域”和“內(nèi)置作用域”的順序進(jìn)行搜索,前三者我們在上面的代碼中已經(jīng)看到了,所謂的“內(nèi)置作用域”就是Python內(nèi)置的那些隱含標(biāo)識符min、len等都屬于內(nèi)置作用域)。

再看看下面這段代碼,我們希望通過函數(shù)調(diào)用修改全局變量a的值,但實際上下面的代碼是做不到的。

def foo():
  a = 200
  print(a) # 200


if __name__ == '__main__':
  a = 100
  foo()
  print(a) # 100

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

def foo():
  global a
  a = 200
  print(a) # 200


if __name__ == '__main__':
  a = 100
  foo()
  print(a) # 200

我們可以使用global關(guān)鍵字來指示foo函數(shù)中的變量a來自于全局作用域,如果全局作用域中沒有a,那么下面一行的代碼就會定義變量a并將其置于全局作用域。同理,如果我們希望函數(shù)內(nèi)部的函數(shù)能夠修改嵌套作用域中的變量,可以使用nonlocal關(guān)鍵字來指示變量來自于嵌套作用域,請大家自行試驗。

在實際開發(fā)中,我們應(yīng)該盡量減少對全局變量的使用,因為全局變量的作用域和影響過于廣泛,可能會發(fā)生意料之外的修改和使用,除此之外全局變量比局部變量擁有更長的生命周期,可能導(dǎo)致對象占用的內(nèi)存長時間無法被垃圾回收。事實上,減少對全局變量的使用,也是降低代碼之間耦合度的一個重要舉措,同時也是對迪米特法則的踐行。減少全局變量的使用就意味著我們應(yīng)該盡量讓變量的作用域在函數(shù)的內(nèi)部,但是如果我們希望將一個局部變量的生命周期延長,使其在函數(shù)調(diào)用結(jié)束后依然可以訪問,這時候就需要使用閉包,這個我們在后續(xù)的內(nèi)容中進(jìn)行講解。

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

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

def main():
  # Todo: Add your code here
  pass


if __name__ == '__main__':
  main()

相關(guān)文章

  • 解決pyinstaller 打包exe文件太大,用pipenv 縮小exe的問題

    解決pyinstaller 打包exe文件太大,用pipenv 縮小exe的問題

    這篇文章主要介紹了解決pyinstaller 打包exe文件太大,用pipenv 縮小exe的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • Django項目的初步創(chuàng)建與簡單配置

    Django項目的初步創(chuàng)建與簡單配置

    本文主要介紹了Django項目的初步創(chuàng)建與簡單配置,詳細(xì)介紹了如何安裝和配置Django,包括創(chuàng)建項目、數(shù)據(jù)庫配置、路由等,通過本文可以了解如何使用Django創(chuàng)建自己的Web應(yīng)用程序
    2023-09-09
  • Python線程協(xié)作threading.Condition實現(xiàn)過程解析

    Python線程協(xié)作threading.Condition實現(xiàn)過程解析

    這篇文章主要介紹了Python線程協(xié)作threading.Condition實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • Python學(xué)習(xí)之基礎(chǔ)語法介紹

    Python學(xué)習(xí)之基礎(chǔ)語法介紹

    大家好,本篇文章主要講的是Python學(xué)習(xí)之基礎(chǔ)語法介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • Python?matplotlib實戰(zhàn)之雷達(dá)圖繪制

    Python?matplotlib實戰(zhàn)之雷達(dá)圖繪制

    雷達(dá)圖(Radar?Chart),也被稱為蛛網(wǎng)圖或星型圖,是一種用于可視化多個變量之間關(guān)系的圖表形式,本文主要為大家介紹了如何使用Matplotlib繪制雷達(dá)圖,需要的小伙伴可以參考下
    2023-08-08
  • 使用Python開發(fā)個京東上搶口罩的小實例(僅作技術(shù)研究學(xué)習(xí)使用)

    使用Python開發(fā)個京東上搶口罩的小實例(僅作技術(shù)研究學(xué)習(xí)使用)

    這篇文章主要介紹了使用Python開發(fā)個京東上搶口罩的小實例(僅作技術(shù)研究學(xué)習(xí)使用),需要的朋友可以參考下
    2020-03-03
  • 利用Python實現(xiàn)kNN算法的代碼

    利用Python實現(xiàn)kNN算法的代碼

    這篇文章主要介紹了利用Python實現(xiàn)kNN算法的代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • python數(shù)據(jù)類型_字符串常用操作(詳解)

    python數(shù)據(jù)類型_字符串常用操作(詳解)

    下面小編就為大家?guī)硪黄猵ython數(shù)據(jù)類型_字符串常用操作(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 用Python簡單實現(xiàn)Http服務(wù)端

    用Python簡單實現(xiàn)Http服務(wù)端

    這篇文章主要為大家介紹了使用Python簡單實現(xiàn)Http服務(wù)端示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • python編程普通及類和靜態(tài)方法示例詳解

    python編程普通及類和靜態(tài)方法示例詳解

    普通方法會將實例傳入方法當(dāng)中(通常用self表示),類方法會將類傳入方法當(dāng)中(通常用cls表示),靜態(tài)方法中傳入與類無關(guān)的變量。下面將舉例詳細(xì)說明
    2021-10-10

最新評論