1. 程式人生 > >Python開發【第四篇】函數

Python開發【第四篇】函數

鍵值 utf-8 nonlocal auth for循環 lambda test 覆蓋 我會

函數的作用

函數可以讓編程邏輯結構化以及模塊化

無論是C、C++,Java還是Python,函數是必不可少的知識點,也是很重要的知識點,函數是完成一個功能的代碼塊,使用函數可以使邏輯結構變得更加清晰以及程序模塊化設計

先來看看Python函數相關知識

 1 def test(x):
 2     """我是用來描述這個函數的"""
 3     x += 1
 4     return x
 5 
 6 # def : 定義函數的關鍵字
 7 # test: 函數名
 8 # (): 裏面定義形參
 9 # """ """: 用來描述這個函數的功能以及所傳函數,返回值,
10 # x+= 1: 函數執行的代碼塊 11 # return :定義返回值

函數的的運行:函數名() 只有加上這個括號才是運行這個函數

函數運行的結束

  當函數執行遇到return,後面所有的代碼都是無效的,都不會執行

def test():
    print(我會打印)
    return
    print(我不會被打印)
test()
"""
我會打印
"""

函數參數:

  1. 形參:只在函數內部有效
  2. 實參:
  3. 位置參數和關鍵字參數
  4. 默認參數
  5. 參數組
__author__ = "Tang"

# 形參:x y z
def test(x,y,z): print(x) print(y) print(z) test(1,2,3) # 實參:1,2,3 # 位置參數 一一對應 def test(x,y,z): print(x) print(y) print(z) test(1,2,3) # # test(1,2) # 缺一不可 報錯 # test(1,2,3,4) # 多一不可 報錯 # 關鍵字參數 def test(x,y,z): print(x) # 2 print(y) # 1 print
(z) # 3 test(y=1,x=2,z=3) # 位置參數 & 關鍵字參數 混搭 # 位置參數一定要在關鍵字的左邊 def test(x,y,z): print(x) # 2 print(y) # 1 print(z) # 3 # test(1,3,y=2) # 報錯 位置參數必須一一對應 test(1,y=3,z=2) # test(1,3,z=2,y=3) # 報錯,傳入參數比形參多 沒有覆蓋一說 # x,z 為默認參數 def test(x,y=1,z=3): print(x,y,z) test(10) # 10 1 3默認參數不傳 使用默認的 test(10,20,30) # 10 20 30 如果傳了就覆蓋 # 不定參數 # 參數組: * 列表 元組, **字典 鍵值對 # 第一種 def test(x,*args): print(x) # 1 print(args) # (2, 3, 4, 5) print(*args) # 2 3 4 5 註意:這裏沒有換行 test(1,2,3,4,5) # 第二種 *() def test(x,*args): print(x) # 1 print(args) # ((2, 3, 4, 5, 6) print(*args) # 2 3 4 5 6 註意:這裏沒有換行 test(1,2,3,*(4,5,6)) # 第三種 () def test(x,*args): print(x) # 1 print(args) # ((2, 3, (4, 5, 6)) print(*args) # 2 3 (4, 5, 6) 註意:這裏沒有換行 test(1,2,3,(4,5,6)) # 第四種 [] def test(x,*args): print(x) # 1 print(args) # (2, 3, [4, 5, 6]) print(*args) # 2 3 [4, 5, 6] 註意:這裏沒有換行 test(1,2,3,[4,5,6]) # 第五種 *[] def test(x,*args): print(x) # 1 print(args) # ((2, 3, 4, 5, 6) print(*args) # 2 3 4 5 6 註意:這裏沒有換行 test(1,2,3,*[4,5,6]) # **kwargs 字典 鍵值對 # 第一種 def test(x,**kwargs): print(x) # 1 print(kwargs) # {‘y‘: 2, ‘z‘: 3} # print(**kwargs) # 報錯 test(1,y=2,z=3) # 第二種 def test(x,**kwargs): print(x) # 1 print(kwargs) # {‘y‘: 2, ‘z‘: 3} # print(**kwargs) # 報錯 # test(1,{"y":2,"z":3}) # 報錯 test(1,**{"y":2,"z":3})

函數裏面可以調用函數

__author__ = "Tang"

def test1():
    print(我是test1)
def test2():
    print(我是test2)
    test1()
test2()

"""
我是test2
我是test1
"""

全局變量與局部變量

  1. 全局變量一般都是大寫 ,在整個程序中都可以被訪問
  2. 局部變量,定義在代碼塊中,for循環,函數等
__author__ = "Tang"

name = "我是全局變量" #
def test():
    name = "我是局部變量"
    print(name) # 我是局部變量

test()
print(name) # 我是全局變量

以上例子可以看到,當局部變量和全局變量都為同一個變量名的時候,在代碼塊裏面,首先先找代碼塊中的變量也就是局部變量,當代碼塊中找不到該變量,就找全局變量

name = "我是全局變量" #
def test():
    print(name) # 我是全局變量
test()
print(name) # 我是全局變量

在代碼塊中修改全局變量需要用到關鍵字 global

name = "我是全局變量" #
def test():
    global name
    name = "我是全局變量,我被修改啦"
    print(name) # 我是全局變量,我被修改啦
test()
print(name) # 我是全局變量,我被修改啦

請註意看我哦!

name = "我是全局變量" 
def test():
    global name
    print(name) # 我是全局變量
    name = "我是全局變量,我被修改啦"
    print(name) # 我是全局變量,我被修改啦
test()
print(name) # 我是全局變量,我被修改啦

總結:當找不到代碼塊中的變量,就會到上一級中找該變量。當看到global 關鍵字,就要想到要重修賦值全局變量。如果沒有global關鍵字,只能讀取全局變量,無法重新賦值全局變量的值。

下面請註意

當全局變量為可變數據類型的時候,可在代碼塊中對全局變量進行修改(增,刪,改),但是不能對全局變量進行重新賦值,賦值的只是局部變量,除非用global 關鍵字進行聲明為全局變量,此時才是賦值給全局變量

# 第六種 列表添加
NAME = ["tang","lao"]
def test():
    NAME.append(er)
    print(NAME) # [‘tang‘, ‘lao‘, ‘er‘]
test()
print(NAME) # [‘tang‘, ‘lao‘, ‘er‘]

# 第七種 列表刪除
NAME = ["tang","lao",er]
def test():
    NAME.remove(er)
    print(NAME) # [‘tang‘, ‘lao‘]
test()
print(NAME) # [‘tang‘, ‘lao‘]

# 第八種 列表修改
NAME = ["tang","lao",er]
def test():
    NAME[0] = "chen"
    print(NAME) # [‘chen‘, ‘lao‘, ‘er‘]
test()
print(NAME) # [‘chen‘, ‘lao‘, ‘er‘]

# 第九種 字典 修改
NAME = {"name":"tang","age":18}
def test():
    NAME["name"] = "chen"
    print(NAME) # {‘name‘: ‘chen‘, ‘age‘: 18}
test()
print(NAME) # {‘name‘: ‘chen‘, ‘age‘: 18}

# 第九種 字典 添加
NAME = {"name":"tang","age":18}
def test():
    NAME["hobby"] = "girl"
    print(NAME) # {‘name‘: ‘tang‘, ‘age‘: 18, ‘hobby‘: ‘girl‘}
test()
print(NAME) # {‘name‘: ‘tang‘, ‘age‘: 18, ‘hobby‘: ‘girl‘}

# 第九種 字典 刪除
NAME = {"name":"tang","age":18}
def test():
    del NAME["name"]
    print(NAME) # {‘age‘: 18}
test()
print(NAME) # {‘age‘: 18}
# 沒有global 賦值
NAME = {"name":"tang","age":18}
def test():
    NAME = {a:1,b:2}
    print(NAME) # {‘a‘: 1, ‘b‘: 2}
test()
print(NAME) # {‘name‘: ‘tang‘, ‘age‘: 18}

# 有global 賦值
NAME = {"name":"tang","age":18}
def test():
    global NAME
    NAME = {a:1,b:2}
    print(NAME) # {‘a‘: 1, ‘b‘: 2}
test()
print(NAME) # {‘a‘: 1, ‘b‘: 2}

一個錯誤的特例

__author__ = "Tang"

# 錯誤的例子     報錯
# NAME = [‘tang‘,‘lao‘,‘er‘]
# def test():
#     NAME = "chen"
#     global NAME
#     print(NAME)
# test()
# print(NAME)

# 改正
NAME = "tang"
def test():
    global NAME # 我是聲明 我要在 NAME 其他操作的前面
    NAME = "chen"
    print(NAME) # chen
test()
print(NAME) # chen

總結:聲明要在其他操作的前面,不然會報錯。。。。。。

為了防止錯誤,全局變量大寫,局部變量小寫,可以防止編程出現沒必要的錯誤

函數嵌套

 1 __author__ = "Tang"
 2 
 3 # 函數嵌套
 4 NAME = "全局"
 5 def yeye():
 6     name = "爺爺級別"
 7     print(name)
 8     def fu():
 9         name =  "父級別"
10         print(name)
11         def zi():
12             name = "子級別"
13             print(name)
14             def sunzi():
15                 name = "孫子級別"
16                 print(name)
17             sunzi()
18         zi()
19     fu()
20 yeye()
21 print(NAME)
22 
23 """
24 爺爺級別
25 父級別
26 子級別
27 孫子級別
28 全局
29 """

再來一個,請仔細看

name = "A"

def test():
    name = "B"
    def test_test():
        global name
        name = "C"
    test_test()
    print(name) # B
print(name) #  A
test()
print(name) # C

關鍵字 nonlocal 聲明上一級的變量

name = "A"

def test():
    name = "B"
    def test_test():
        nonlocal name # nonlocal,指定上一級變量
        name = "C"
    test_test()
    print(name) # C
print(name) #  A
test()
print(name) # A

nonlocal 只能使用於兩級或多級函數嵌套,一級嵌套會導致程序報錯,下面請看一個錯誤的示例

name = "A"
def test():
    nonlocal name # 報錯
    name = "C"
    print(name)
print(name)
test()
print(name)

函數聲明與調用的順序

函數即變量,調用函數前需先聲明

# 第一種情況
def foo():
    print("foo")
    bar()

def bar():
    print("bar")
foo()

下面看一個錯誤的例子

# 第二種情況 報錯的例子
def foo():
    print("foo")
    bar()

foo()
def bar():
    print("bar")

函數遞歸

  1. 必須有一個明確的結束條件(if 判斷)return結束
  2. 每次進入更深一層遞歸時,問題規模相比上一次遞歸都應有所減少

 1 __author__ = "Tang"
 2 
 3 def calc(n):
 4     print(n)
 5     if int(n / 2) ==0:
 6         return n
 7     res = calc(int(n/2))
 8     print("****",res)
 9     return res
10 n = calc(10)
11 print(n)
12 """
13 10
14 5
15 2
16 1
17 **** 1
18 **** 1
19 **** 1
20 1
21 """

遞歸代碼練習:一個快速排序的例子

 1 # coding:utf-8
 2 def quick_sort(alist, first, last):
 3     """快速排序"""
 4     if first >= last:
 5         return
 6     mid_value = alist[first]
 7     low = first
 8     high = last
 9     while low < high:
10         # high 左移
11         while low < high and alist[high] >= mid_value:
12             high -= 1
13         alist[low] = alist[high]
14 
15         while low < high and alist[low] < mid_value:
16             low += 1
17         alist[high] = alist[low]
18     # 循環退出時,滿足條件low==high
19     alist[low] = mid_value
20 
21     # 對low左邊的列表執行快速排序
22     quick_sort(alist, first, low-1)
23 
24     # 對low右邊的列表排序
25     quick_sort(alist, low+1, last)
26 
27 
28 if __name__ == "__main__":
29     li = [54, 26, 93, 17, 77, 31, 44, 55, 20]
30     print(li)
31     quick_sort(li, 0, len(li)-1)
32     print(li)

斐波那契數列

__author__ = "Tang"

# 斐波那契數列
a = 0
b = 1
while b < 1000:
    print(b,end=" ")
    a,b = b, a+b
# 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

# 生成前20項
lis =[]
for i in range(20):
    if i ==0 or i ==1:# 第1,2項 都為1
        lis.append(1)
    else:
        lis.append(lis[i-2]+lis[i-1])# 從第3項開始每項值為前兩項值之和
print(lis) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]

# 遞歸實現
li = []
def test(a, b):
    if a > 1000 or b > 2000:
        return
    li.append(a)
    li.append(b)
    a = a + b
    b = a + b
    test(a, b)
test(1, 1)
print(li) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]

函數作用域相關練習

 1 __author__ = "Tang"
 2 
 3 """函數的作用域相關練習"""
 4 
 5 """
 6 尋找變量的順序:當前函數裏面尋找,如果找不到就往上一層函數找,實在找不到就找全局變量
 7 函數的調用:函數名+ () 函數名即變量,只要取得函數地址就可以
 8 """
 9 
10 # 第一種
11 def foo():
12     print("我是foo")
13     def bar():
14         print("我是bar")
15     bar()
16 foo()
17 # bar() # 報錯 不可以直接調用 記住:要想執行裏面的,就要先執行外面的,想象盒子裏面包含盒子,外面的盒子不拿掉,裏面的也拿不出來
18 """
19 我是foo
20 我是bar
21 """
22 
23 # 第二種
24 def foo():
25     print("我是foo")
26     def bar():
27         print("我是bar")
28     return bar
29 test = foo()
30 test() # 可以調用 test拿到bar函數的地址
31 """
32 我是foo
33 我是bar
34 """
35 
36 # 第三種
37 def test():
38     print("我是test")
39 print(test()) # 沒有沒有返回值 默認為None
40 """
41 我是test
42 None
43 """
44 
45 # 第四種
46 def test():
47     print("我是test")
48     return 10
49 print(test())
50 """
51 我是test
52 10
53 """
54 
55 # 第五種
56 name = "tang"
57 def foo():
58     name = "chen"
59     def bar():
60         name = "li"
61         print(name)
62     return bar
63 a = foo()
64 print(a)
65 a()
66 """
67 <function foo.<locals>.bar at 0x02FE0B28>
68 li
69 """
70 
71 # 第六種
72 name = "tang"
73 def foo():
74     name = "chen"
75     def bar():
76         print(name)
77     return bar
78 a = foo()
79 print(a)
80 a()
81 """
82 <function foo.<locals>.bar at 0x00830B70>
83 chen
84 """
85 
86 # 第七種
87 name = "tang"
88 def foo():
89     name = "chen"
90     def bar():
91         print(name)
92     return bar
93 foo()()
94 """
95 chen
96 """

匿名函數 lambda

lambda x : x+1 一個簡單的匿名函數

__author__ = "Tang"


def test(x):
    return x + 1
res = test(10)
print(res) # 11

#  匿名函數實現上面函數
func = lambda x:x+1
print(func(10)) # 11

下面通過一些簡單的例子來加深匿名函數的理解

# 第一個
name = "tang"
def change_name(x):
    return x +"_sb"
res = change_name(name)
print(res) # tang_sb

res = lambda x:name+"_sb"
print(res(name)) # tang_sb
print(res("tang")) # tang_sb

res = lambda x:x+"_sb"
print(res(name)) # tang_sb
print(res("tang")) # tang_sb


# 第二個 傳多個參數
func = lambda x,y,z:x+y+z
print(func(1,2,3)) # 6

# 第三個
name1 = "tang"
name2 = "lao"
name3 = "er"
x = lambda name1,name2,name3:"".join([name1,name2,name3])
print(x(name1,name2,name3)) # tanglaoer

Python開發【第四篇】函數