Python基礎之 4. 函式

Py小五發表於2020-11-30

一、函式(一)

1. 函式介紹

函式就是一個具有獨立功能的程式碼塊,可以提高程式碼的複用性。

2. 函式定義和呼叫

1. 定義函式

定義函式的格式如下:

def 函式名():
    程式碼

demo:

# 定義一個函式,能夠完成列印資訊的功能
def printInfo():
    print('------------------------------------')
    print('         人生苦短,我用Python')
    print('------------------------------------')

2. 呼叫函式

定義了函式之後,就相當於有了一個具有某些功能的程式碼,想要讓這些程式碼能夠執行,需要呼叫它。
呼叫函式很簡單的,通過 函式名() 即可完成呼叫

demo:

# 定義完函式後,函式是不會自動執行的,需要呼叫它才可以
printInfo()

3. 注意:

每次呼叫函式時,函式都會從頭開始執行,當這個函式中的程式碼執行完畢後,意味著呼叫結束了,當然瞭如果函式中執行到了return也會結束函式。

3. 函式引數(一)

為了讓一個函式更通用,即想讓它計算哪兩個數的和,就讓它計算哪兩個數的和,在定義函式的時候可以讓函式接收資料,就解決了這個問題,這就是 函式的引數

1. 定義帶有引數的函式

示例如下:

def add2num(a, b):
    c = a+b
    print c

2. 呼叫帶有引數的函式

以呼叫上面的add2num(a, b)函式為例:

def add2num(a, b):
    c = a+b
    print c

add2num(11, 22) # 呼叫帶有引數的函式時,需要在小括號中,傳遞資料

3. 呼叫函式時引數的順序

>>> def test(a,b):
...     print(a,b)
... 
>>> test(1,2)
1 2
>>> test(b=1,a=2)
2 1
>>> 
>>> test(b=1,2)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

4. 小總結

  • 定義時小括號中的引數,用來接收引數用的,稱為 “形參”
  • 呼叫時小括號中的引數,用來傳遞給函式用的,稱為 “實參”

4. 函式返回值(一)

1. “返回值”介紹

所謂“返回值”,就是程式中函式完成一件事情後,最後給呼叫者的結果。

2. 帶有返回值的函式

想要在函式中把結果返回給呼叫者,需要在函式中使用return

如下示例:

def add2num(a, b):
    c = a+b
    return c

或者

def add2num(a, b):
    return a+b

3. 儲存函式的返回值

示例如下:

#定義函式
def add2num(a, b):
    return a+b

#呼叫函式,順便儲存函式的返回值
result = add2num(100,98)

#因為result已經儲存了add2num的返回值,所以接下來就可以使用了
print(result)

結果:

198

5. 函式的巢狀呼叫

def testB():
    print('---- testB start----')
    print('這裡是testB函式執行的程式碼...(省略)...')
    print('---- testB end----')

def testA():
    print('---- testA start----')
    testB()
    print('---- testA end----')

testA()

結果:

---- testA start----
---- testB start----
這裡是testB函式執行的程式碼...(省略)...
---- testB end----
---- testA end----

小總結:
函式巢狀

一個函式裡面又呼叫了另外一個函式,這就是所謂的函式巢狀呼叫 函式巢狀呼叫。
如果函式A中,呼叫了另外一個函式B,那麼先把函式B中的任務都執行完畢之後才會回到上次 函式A執行的位置。

6. 函式應用:列印圖形和數學計算

思考&實現1

寫一個函式列印一條橫線
列印自定義行數的橫線

參考程式碼1

# 列印一條橫線
def printOneLine():
    print("-"*30)

# 列印多條橫線
def printNumLine(num):
    i=0

    # 因為printOneLine函式已經完成了列印橫線的功能,
    # 只需要多次呼叫此函式即可
    while i<num:
        printOneLine()
        i+=1

printNumLine(3)

思考&實現2

寫一個函式求三個數的和
寫一個函式求三個數的平均值

參考程式碼2

# 求3個數的和
def sum3Number(a,b,c):
    return a+b+c # return 的後面可以是數值,也可是一個表示式

# 完成對3個數求平均值
def average3Number(a,b,c):

    # 因為sum3Number函式已經完成了3個數的就和,所以只需呼叫即可
    # 即把接收到的3個數,當做實參傳遞即可
    sumResult = sum3Number(a,b,c)
    aveResult = sumResult/3.0
    return aveResult

# 呼叫函式,完成對3個數求平均值
result = average3Number(11,2,55)
print("average is %d"%result)

二、函式(二)

1. 區域性變數

1. 什麼是區域性變數

如下例項所示:

def func1():
    a = 3
    print('test1----修改前:a=%d' % a)
    a = 2
    print('test2----修改後:a=%d' % a)


def func2():
    a = 4
    print('test3---:a=%d' % a)

# 呼叫函式
func1()
func2()

結果:

test1----修改前:a=3
test2----修改後:a=2
test3---:a=4

2. 小總結

  • 區域性變數,就是在函式內部定義的變數
  • 作用範圍是這個函式內部,即只能在這個函式中使用,在函式的外部是不能使用的。因為其作用範圍只是在自己的函式內部,所以不同的函式可以定義相同名字的區域性變數(打個比方,把你、我是當做成函式,把區域性變數理解為每個人手裡的手機,你可有個iPhone12,我當然也可以有個iPhone12了, 互不相關)
  • 區域性變數的作用,為了臨時儲存資料需要在函式中定義變數來進行儲存
  • 函式呼叫時,區域性變數被建立,當函式呼叫完成後這個變數就不能夠使用了

2. 全域性變數

1. 什麼是全域性變數

demo如下:

# 定義全域性變數
a = 100
def test1():
    print(a)  # 雖然沒有定義變數a但是依然可以獲取其資料

def test2():
    print(a)  # 雖然沒有定義變數a但是依然可以獲取其資料

# 呼叫函式
test1()
test2()

結果:

100
200

小總結:

  • 在函式外邊定義的變數叫做全域性變數
  • 全域性變數能夠在所有的函式中進行訪問

2. 全域性變數和區域性變數名字相同問題

如下例項:

a = 5  # 全域性變數
def func1():
    a = 3
    print('test1----修改前:a=%d' % a)
    a = 2
    print('test2----修改後:a=%d' % a)


def func2():
    print('test3---:a=%d' % a)

# 呼叫函式
func1()
func2()

結果:

test1----修改前:a=3
test2----修改後:a=2
test3---:a=5

小總結

  • 當函式內出現區域性變數和全域性變數相同名字時,函式內部中的 變數名 = 資料 此時理解為定義了一個區域性變數,而不是修改全域性變數的值。

3. 修改全域性變數

函式中使用全域性變數時進行修改:

a = 5  # 全域性變數
def func1():
    global a
    print('test1----修改前:a=%d' % a)
    a = 2
    print('test2----修改後:a=%d' % a)


def func2():
    print('test3---:a=%d' % a)

# 呼叫函式
func1()
func2()

結果:

test1----修改前:a=5
test2----修改後:a=2
test3---:a=5

小總結:

  • 如果在函式中出現 global 全域性變數的名字 那麼這個函式中即使出現和全域性變數名相同的變數名 = 資料 也理解為對全域性變數進行修改,而不是定義區域性變數。
  • 如果在一個函式中需要對多個全域性變數進行修改,那麼可以使用:
# 可以使用一次global對多個全域性變數進行宣告
global a, b
# 還可以用多次global宣告都是可以的
global a
global b

3. 多函式程式的基本使用流程

1. 使用全域性變數

g_num = 0

def test1():
    global g_num
    # 將處理結果儲存到全域性變數g_num中.....
    g_num = 100

def test2():
    # 通過獲取全域性變數g_num的值, 從而獲取test1函式處理之後的結果
    print(g_num)

# 1. 先呼叫test1得到資料並且存到全域性變數中
test1()

# 2. 再呼叫test2,處理test1函式執行之後的這個值
test2()  # 返回 50

2. 使用函式的返回值、引數

def test1():
     # 通過return將一個資料結果返回
     return 50

def test2(num):
    # 通過形參的方式儲存傳遞過來的資料,就可以處理了
    print(num)

# 1. 先呼叫test1得到資料並且存到變數result中
result = test1()
print(result)  # 將變數result列印出來

# 2. 呼叫test2時,將result的值傳遞到test2中,從而讓這個函式對其進行處理
test2(result)

3. 函式巢狀呼叫

def test1():
    # 通過return將一個資料結果返回
    return 20

def test2():
    # 1. 先呼叫test1並且把結果返回來
    result = test1()
    # 2. 對result進行處理
    print(result)

# 呼叫test2時,完成所有的處理
test2()

4. 函式返回值(二)

1. 說明

  • 一個函式中可以有多個return語句,但是隻要有一個return語句被執行到,那麼這個函式就會結束了,因此後面的return沒有什麼用處。
  • 如果程式設計為如下,是可以的因為不同的場景下執行不同的return:
def create_nums(num):
      print("---1---")
      if num == 100:
          print("---2---")
          return num+1  # 函式中下面的程式碼不會被執行,因為return除了能夠將資料返回之外,還有一個隱藏的功能:結束函式
      else:
          print("---3---")
          return num+2
      print("---4---")

  result1 = create_nums(100)
  print(result1)  # 列印101
  result2 = create_nums(200)
  print(result2)  # 列印202

2. 一個函式返回多個資料的方式

def calc_num(a, b):
    num1 = a//b
    num2 = a%b 
    return num1, num2  #預設是元組

result = calc_num(5, 2)
print(result)  # 輸出(2, 1)

總結

  • return後面可以是元組,列表、字典等,只要是能夠儲存多個資料的型別,就可以一次性返回多個資料
def function():
    # return [1, 2, 3]
    # return (1, 2, 3)
    return {"num1": 1, "num2": 2, "num3": 3}
  • 如果return後面有多個資料,那麼預設是元組
In [1]: a = 1, 2
In [2]: a
Out[2]: (1, 2)

In [3]:
In [3]: b = (1, 2)
In [4]: b
Out[4]: (1, 2)

In [5]:

5. 函式引數(二)

1. 預設引數

呼叫函式時,預設引數的值如果沒有傳入,則取預設值。

下例會列印預設的age,如果age沒有被傳入:

def printinfo(name, age=35):
   # 列印任何傳入的字串
   print("name: %s" % name)
   print("age %d" % age)

# 呼叫printinfo函式
printinfo(name="miki")  # 在函式執行過程中 age去預設值35
printinfo(age=9 ,name="miki")

以上例項輸出結果:

name: miki
age: 35
name: miki
age: 9

總結:

  • 在形參中預設有值的引數,稱之為預設引數
  • 注意:帶有預設值的引數一定要位於引數列表的最後面。
  >>> def printinfo(name, age=35, sex):
  ...     print name
  ...
    File "<stdin>", line 1
  SyntaxError: non-default argument follows default argument

2. 不定長引數

有時可能需要一個函式能處理比當初宣告時更多的引數, 這些引數叫做不定長引數,宣告時不會命名。

基本語法如下:

def functionname([formal_args,] *args, **kwargs):
   """函式_文件字串"""
   function_suite
   return [expression]

注意:

  • 加了星號(*)的變數args會存放所有未命名的變數引數,args為元組;
  • 而加**的變數kwargs會存放命名引數,即形如key=value的引數, kwargs為字典。
>>> def fun(a, b, *args, **kwargs):
...     """不定長引數演示示例"""
...     print("a =%d" % a)
...     print("b =%d" % b)
...     print("args:")
...     print(args)
...     print("kwargs: ")
...     for key, value in kwargs.items():
...         print("key=%s" % value)
...
>>> fun(1, 2, 3, 4, 5, m=6, n=7, p=8)  # 注意傳遞的引數對應
a = 1
b = 2
args:
(3, 4, 5)
kwargs: 
p = 8
m = 6
n = 7
>>>
>>>
>>>
>>> c = (3, 4, 5)
>>> d = {"m":6, "n":7, "p":8}
>>> fun(1, 2, *c, **d)    # 注意元組與字典的傳參方式
a = 1
b = 2
args:
(3, 4, 5)
kwargs: 
p = 8
m = 6
n = 7
>>>
>>>
>>>
>>> fun(1, 2, c, d) # 注意不加星號與上面的區別
a = 1
b = 2
args:
((3, 4, 5), {'p': 8, 'm': 6, 'n': 7})
kwargs:
>>>
>>>

3. 預設引數在*args後面

def sum_nums_3(a, *args, b=22, c=33, **kwargs):
    print(a)
    print(b)
    print(c)
    print(args)
    print(kwargs)

sum_nums_3(100, 200, 300, 400, 500, 600, 700, b=1, c=2, mm=800, nn=900)
# a = 100, b = 1, c = 2, *args = 200, 300, 400, 500, 600, 700, **kwargs = mm=800,  nn=900
# *args 為元組型別;**kwargs 為字典型別

結果:

100
1
2
(200, 300, 400, 500, 600, 700)
{'mm': 800, 'nn': 900}

說明:

  • 如果很多個值都是不定長引數,那麼這種情況下,可以將預設引數放到 *args的後面, 但如果有**kwargs的話,**kwargs必須是最後的。

6. 拆包、交換變數的值

1. 對返回的資料直接拆包

def get_my_info():
    high = 178
    weight = 100
    age = 18
    return high, weight, age
result = get_my_info()
print(result)
print('***********')
my_high, my_weight, my_age = get_my_info()
print(my_high)
print(my_weight)
print(my_age)

結果:

(178, 100, 18)
***********
178
100
18

總結:

  • 拆包時要注意,需要拆的資料的個數要與變數的個數相同,否則程式會異常;
  • 除了對元組拆包之外,還可以對列表、字典等拆包。
  In [17]: a, b = (11, 22)
  In [18]: a
  Out[18]: 11
  In [19]: b
  Out[19]: 22

  In [20]: a, b = [11, 22]
  In [21]: a
  Out[21]: 11
  In [22]: b
  Out[22]: 22

  In [23]: a, b = {"m":11, "n":22}  # 取出來的是key,而不是鍵值對
  In [24]: a
  Out[24]: 'm'
  In [25]: b
  Out[25]: 'n'

2. 交換2個變數的值

# 第3種方式
a = 4
b = 5
a, b = b, a

print(a)  # 5
print(b)  # 4

7. 引用

1. 引用介紹

在python中,值是靠引用來傳遞來的。

我們可以用id()來判斷兩個變數是否為同一個值的引用。 我們可以將id值理解為那塊記憶體的地址標示。

>>> a = 1
>>> b = a
>>> id(a) 
13033816
>>> id(b)   # 注意兩個變數的id值相同
13033816
>>> a = 2
>>> id(a)   # 注意a的id值已經變了
13033792
>>> id(b)   # b的id值依舊
13033816
>>> a = [1, 2]
>>> b = a
>>> id(a)
139935018544808
>>> id(b)
139935018544808
>>> a.append(3)
>>> a
[1, 2, 3]
>>> id(a)
139935018544808
>>> id(b)       # 注意a與b始終指向同一個地址
139935018544808

引用

總結:

  • 之前為了更好的理解變數,我們們可以把a=100理解為變數a中存放了100,事實上變數a儲存是100的引用(可理解為在記憶體中的一個編號)

2. 引用當做實參

def test1(b):  	# 變數b一定是一個區域性變數,就看它指向的是誰?可變還是不可變
    b += b  	# += 是直接對b指向的空間進行修改,而不是讓b指向一個新的
    # b = b+b  	# xx = xx+yyy 先把=號右邊的結果計算出來,然後讓b指向這個新的地方,不管原來b指向誰,現在b一定指向這個新的地方

# a = [11, 22]
a = 100
test1(a)
print(a)

總結:

  • Python中函式引數是引用傳遞(注意不是值傳遞)
  • 對於不可變型別,因變數不能修改,所以運算不會影響到變數自身
  • 而對於可變型別來說,函式體中的運算有可能會更改傳入的引數變數

8. 可變、不可變型別

![可變和不可變型別](https://img-blog.csdnimg.cn/20201130153414445.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTU3OTAyNg==,size_16,color_FFFFFF,t_70)
總結

  • 所謂可變型別與不可變型別是指:資料能夠直接進行修改,如果能直接修改那麼就是可變,否則是不可變
  • 可變型別有: 列表、字典、集合
  • 不可變型別有: 數字、字串、元組

9. 函式使用注意事項

1. return注意事項

  • 一個函式到底有沒有返回值,就看有沒有return關鍵字,因為只有return才可以返回資料。
  • 當執行完return語句,那麼就意味著這個函式的呼叫完成,return語句後面的程式碼不會執行。

2. 函式名不能重複

  • 如果在同一個程式中出現了多個相同函式名的函式,那麼後面的函式會覆蓋前面的函式,在呼叫函式時就可能出現問題,所以要避免名字相同

3. 作用域

  • 在一個函式中定義的變數,只能在本函式中用(區域性變數)
  • 在函式外定義的變數,可以在所有的函式中使用(全域性變數)

相關文章