python函數基礎

python函數

  • 函數的基本定義
  • 函數參數
  • 返回值
  • 局部變量和全局變量
  • 嵌套函數
  • 匿名函數
  • 高階函數
  • 遞歸

函數的基本定義

引子

如今你的老闆讓你寫一個監控程序,24小時整年午無休的監控大家公司網站服務器的運行情況,當cpu\memory\disk等指標的使用量超過閾值時即發送報警郵件:java

while True:
    if cpu利用率 > 90%:
        #發送郵件提醒
        鏈接郵箱服務器
        發送郵件
        關閉鏈接

    if 硬盤使用空間 > 90%:
        #發送郵件提醒
        鏈接郵箱服務器
        發送郵件
        關閉鏈接

    if 內存佔用 > 80%:
        #發送郵件提醒
        鏈接郵箱服務器
        發送郵件
        關閉鏈接

那麼當你的同事看到這個代碼的時候,就發現了代碼的重複性比較高,每次報警都要重寫一段發郵件的代碼,一個勁的copy and paste根本就不符合高端程序員的氣質,其次若是之後想修改發郵件的代碼,好比加上羣發功能,那麼就須要在全部代碼上都要修改一遍.python

你也看出來了這個問題,你也不想去寫重複代碼,但又不知道怎麼寫,此時你的同時笑着和你說,這個很簡單,只要把重複的代碼提出出來,放在一個公共的地方,起個名字,之後誰想用這個代碼,就經過這個名字就能夠調用了.,以下:linux

def 發送郵件(內容):
    # 發送郵件提醒
    鏈接郵件服務器
    發送郵件
    關閉鏈接

while True:
    if cpu利用率 > 90%:
        發送郵件('CPU報警')
    if 硬盤使用空間 > 90%:
        發送郵件('硬盤報警')
    if 內存佔用 > 80%:
        發送郵件('內存報警')

基本定義

函數是什麼?

函數一詞來源於數學,但編程中的「函數」概念,與數學中的函數是有很大不一樣的,編程中的函數在英文中也有不少不一樣的叫法。在BASIC中叫作subroutine(子過程或子程序),在Pascal中叫作procedure(過程)和function,在C中只有function,在Java裏面叫作method。程序員

定義:函數是指將一組語句的集合經過一個名字(函數名)封裝起來,要想執行這個函數,只需調用其函數名便可編程

函數的特徵

  • 減小重複代碼
  • 使程序變得可擴展
  • 使程序變得可維護

語法定義

def sayhi():  # sayhi函數名
    print('hello world')

sayhi()  # 調用函數

函數參數

形參變量 只有在調用時猜分配內存單元,在調用結束後,即刻釋放所分配的內存單元.所以,形參只在函數內部有效.函數調用結束返回主調用函數後則不能再使用該形參變量服務器

實參 能夠是常量\變量\表達式\函數等,不管實參是那種類型的量,再進行函數調用時,他們都必須有肯定的值,以便把這些值傳送給形參.所以應預先用賦值,輸入等方法使參數得到肯定值.運維

def cacl(x,y):  # 此時的x,y是形參
    res = x**y
    return res

c = cacl(2,5)  # 此時的2,5是形參
print(c)

默認參數

看以下代碼:函數

def stu_register(name,age,country,course):
    print('-----註冊學生信息-----')
    print('姓名:',name)
    print('年齡:',age)
    print('國家:',country)
    print('課程:',course)

stu_register('老王',22,'CHINA','PYTHON')
stu_register('小明',18,'CHINA','JAVA')
stu_register('康康',19,'CHINA','C++')

運行結果以下:網站

-----註冊學生信息-----
姓名: 老王
年齡: 22
國家: CHINA
課程: PYTHON
-----註冊學生信息-----
姓名: 小明
年齡: 18
國家: CHINA
課程: JAVA
-----註冊學生信息-----
姓名: 康康
年齡: 19
國家: CHINA
課程: C++

這時候咱們發現了一個問題,咱們發現country這個參數的值都是CHINA,就像咱們在註冊網站的時候,像國家這種信息,你不填寫的話,那麼默認是CHINA,這就是經過默認參數實現的,把country變成默認參數很是簡單.ui

def stu_register(name,age,course,country='CHINA'):

這樣,這個參數在調用時不指定,那麼默認就是CHINA了,若是指定的話,就是你本身指定的值了.舉個例子看看:

# 默認參數--若是用戶指定了參數值,則使用用戶指定的值,不然使用默認參數的值。
def stu_register(name,age,course,country='CHINA',):
    print('-----註冊學生信息-----')
    print('姓名:',name)
    print('年齡:',age)
    print('國家:',country)
    print('課程:',course)

stu_register('老王',22,'PYTHON')
stu_register('小明',18,'JAVA','JAPAN')  # 指定了country = JAPAN

那麼咱們看一下運行結果:

-----註冊學生信息-----
姓名: 老王
年齡: 22
國家: CHINA
課程: PYTHON
-----註冊學生信息-----
姓名: 小明
年齡: 18
國家: JAPAN
課程: JAVA

那麼,爲何默認參數要放置在參數的最後一個位置呢?讓咱們來看下:

def stu_register(name,age,country='CHINA',course):  # 若是寫成這樣的話,那麼會當即報錯,根本就不會運行,由於將實參傳遞給形參時,不知道CHINA是傳給誰的
    print('-----註冊學生信息-----')
    print('姓名:',name)
    print('年齡:',age)
    print('國家:',country)
    print('課程:',course)

stu_register('康康',19,'CHINA','C++')

關鍵參數

正常狀況下,給函數傳參數要按順序,不想按順序就能夠用關鍵參數,只需指定參數名就能夠了(指定參數名的參數就叫作關鍵參數),注意:關鍵參數必須放在位置參數以後(以位置順序肯定對應關係的參數) 舉個例子看一下:

def stu_register(name,age,course='python',country='CHINA'):  # 設置兩個默認參數
    print('-----註冊學生信息-----')
    print('姓名:',name)
    print('年齡:',age)
    print('國家:',country)
    print('課程:',course)

stu_register('王佳',course='LIUNX',age = 22)

可是不能夠這樣調用:

stu_register('小明',course='java ',22,country='JAPAN')
也不能夠這樣
stu_register('小明',22,23,country='JAPAN')  # 這句話等於將22 23傳遞給了age,可是不能傳遞兩個值

非固定參數

若你的函數中不肯定要傳入多少參數,就可使用非固定函數,舉個例子來講,文章開頭的郵件報警,如今我不想只對一我的發郵件,我想對整個運維部的人發送報警郵件,那麼這個時候使用非固定參數最合適不過了:

def students(name,age,*args):  # *args 會把多傳入的參數變成一個元組形式
    print(name,age,args)  # 打印name,age,args

students('小明',22,'PYTHON','CHINA')  # 小明 22 ('PYTHON', 'CHINA')

原來,*args所接受的參數是用元組的形式保存的

那麼如今還有一個**kwargs

def stu(name,age,*args,**kwargs):
    print(name,age,args,kwargs)

stu('肖亞飛',22)  # 肖亞飛 22 () {}
# 讓咱們看看args和kwargs的差異在哪?
stu('肖爸爸',23,'python','linux')  # 肖爸爸 23 ('python', 'linux') {}
stu('肖爸爸',23,'python','linux',addr = 'Henan',music = '蝴蝶')  # 肖爸爸 23 ('python', 'linux') {'addr': 'Henan', 'music': '蝴蝶'}

總結:

1.*args必須放在**kwargs以前
   2.*args 沒有key值,**kwargs有key值
   3.使用*args和**kwargs能夠很是方便的定義函數,同時能夠增強擴展性,以便往後的代碼維護

返回值

函數外部的代碼想要獲取函數的執行結果,就能夠在函數裏使用return語句把結果返回

def student(name,age,course='PYTHON',country='CN'):  # 設置了course和country兩個默認參數
    print('-----註冊學生信息-----')
    print('姓名:',name)
    print('年齡:',age)
    print('國家:',country)
    print('課程:',course)

    if age > 20:  # 判斷若是age大於20
        return False  # 返回False
    else:
        return True

result = student('張三',22)  # 函數外部的代碼想要獲取函數的執行結果,就須要使用一個變量來進行接受
if result:  # 若是result = True
    print('恭喜註冊成功!')
else:  # 若是result = Flase
    print('年紀太大!')

看一下運行結果:

-----註冊學生信息-----
姓名: 張三
年齡: 22
國家: CN
課程: PYTHON
年紀太大!

注意

  • 函數在執行過程當中,只要遇到return語句,就會中止執行並返回結果,so也能夠理解爲return語句表明着函數的結束
  • 若是未在函數中指定return,那麼這個函數的返回值爲None

局部變量和全局變量

name = 'xiaoyafei'
def change_name(name):  # 定義一個函數,傳遞Name參數
    print('修改前:',name)
    name = '肖亞飛'
    print('修改後:',name)

change_name(name)
print('在外面看修改過了嗎?',name)

輸出結果爲:

修改前: xiaoyafei  # 沒修改以前的
修改後: 肖亞飛  # 在函數裏修改過的
在外面看修改過了嗎? xiaoyafei

不用傳name參數,在函數裏面仍是能夠調用外面的變量

name = "xiaoyafei"
def change_name():
    name = '肖亞飛'
    print("修改後:",name)
change_name()
print("在外面看:",name)

運行結果爲:

修改後: 肖亞飛
在外面看: xiaoyafei

那麼,爲啥我明明修改過了,爲啥在外面仍是沒修改呢?讓咱們看看name變量的空間地址:

name = "xiaoyafei"
def change_name():
    name = '肖亞飛'
    print("函數內,id:",id(name))
change_name()
print("函數外,id:",id(name))

結果以下:

函數內,id: 1388194004688
函數外,id: 1388193784688

要是不放大你的眼睛還真的看不清楚呢,內存空間地址不一樣,因此兩個name是沒有關係的,那麼爲啥一個函數裏能定義兩個甚至更多相同的變量呢?

  • 在函數中定義的變量稱爲全局變量,在程序的一開始定義的變量稱爲全局變量
  • 全局變量的做用域是整個程序,局部變量的做用是定義該變量的函數
  • 當全局變量和局部變量相同時,在定義局部變量的函數內,局部變量起做用;在其餘地方全局變量起做用

做用域

做用域,程序設計概念,一般來講,一段代碼中所用到的名字並不老是有效/可用的,而限定這個名字的可用性的代碼範圍就是這個名字的做用與.

如何在函數裏修改全局變量

name = '肖亞飛'

def change_name():
    global name  # global的做用就是在函數裏聲明全局變量name,意味着最上面的name = '肖亞飛'即便不寫,程序最後面也能夠print name
    name = 'xiaoyafei'
    print('函數裏修改:',name)

change_name()  # 調用函數
print('函數外:',name )

運行結果以下:

函數裏修改: xiaoyafei
函數外: xiaoyafei

嵌套函數

name = 'xiaoyafei'
def change_name():
    name = 'xiaoyafei2'

    def change_name2():
        name = 'xiaoyafei3'  # 若是在當前函數擁有name變量,則使用函數內的name變量,若是沒有,則會去上一級去找name,一直找到全局變量
        print('第3層打印:',name)  # 第3層打印: xiaoyafei3

    change_name2()
    print('第2層的音:',name)  # 第2層的音: xiaoyafei2

change_name()
print('第一層打印:',name)  # 第一層打印: xiaoyafei

匿名函數

匿名函數就是不須要顯示的指定函數名

匿名函數的聲明

res1 = lambda x,y:x+y  #聲明一個匿名函數,有x和y兩個參數,操做爲x+y
print(res1)  # <function <lambda> at 0x0000021D32590D08>

常規函數和匿名函數:

# 常規函數
def cacl(x,y):
    return x**y

res = cacl(2,3)  # 若是想要使用函數的返回值,就須要定義一個變量來接收
print(res)  # 8

# 匿名函數
res = lambda x,y:x**y
print(res(2,3))  # 8

匿名函數的優勢:

  • 使用python寫一些腳本時,使用lambda能夠省去自定義函數的過程,讓代碼更加精簡
  • 對於一些抽象的,不會被別的地方再重複使用的函數,有時候函數起個名字也是個難題,使用lambda不用考慮這些問題
  • 使用lambda在某些時候讓代碼更容易理解

匿名函數的其他用法

data  = list(range(10))
print(data)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 問題:用兩種方法計算這些數的平方

# 常規操做
for index,i in enumerate(data):
    data[i] = i*i
print(data)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 裝逼操做
res = list(map(lambda x:x*x,data))
print(res)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

那麼在方法2中的map()函數是啥意思?

map()會根據提供的函數對指定序列作映射

第一個參數functrion以參數序列中的每個元素調用function函數,返回包含每次function函數返回值的新列表,能夠不懂,下面就會講,

今天不是看到map()函數,我還真不知道python2和python3中的map()有區別,讓咱們舉個例子看一下map()函數的用法:

在python2中:
>>> def cacl(x):  # 求一個數的平方
...     return x**2
...
>>> map(cacl,[1,2,3,4,5])  # 在python2中返回的是列表
[1, 4, 9, 16, 25]
>>>

在python3中:
>>> def cacl(x):
...     return x**2
...
>>> map(cacl,[1,2,3,4,5])  # python3中返回的是迭代器對象,何謂迭代器?晚點會在博客中說明
<map object at 0x0000015B373533C8>
>>> res = map(cacl,[1,2,3,4,5])
>>> next(res)  # 返回迭代器中的下一個值
1
>>> next(res)
4

map()函數在python2和python3中的區別:

  • 在python2中返回的是列表
  • 在python3中返回的是迭代器對象

map()是python內置的高階函數,它接收一個函數cacl和一個list,並經過函數cacl依次做用於list的每一個元素上,而且獲得一個新的list並返回,因爲list包含的元素能夠是各類類型的,所以,map()不只僅能夠處理只包含數值的list,事實上它也能夠處理包含任意類型的list,只要傳入的函數cacl能夠處理這種數據類型.

高級函數

變量能夠指向函數,函數的參數能接受變量,那麼一個函數就能夠接收另外一個函數做爲參數,這種函數就被稱爲高階函數.

  • 接收一個或多個函數做爲輸入
  • return 返回另一個函數
def func2(x,y):
    return abs,x,y
res = func2(-1,10)
print(res)  # (<built-in function abs>, -1, 10)

def cacl(x,y,f):
    return f(x)+f(y)

res = cacl(-4,10,abs)
print(res)  # 14
相關文章
相關標籤/搜索