Python之路【第四篇】:Python基礎之函數

函數的理解

面向過程:根據業務邏輯從上到下壘代碼python

函數式:將某功能代碼封裝到函數中,往後便無需重複編寫,僅調用函數便可編程

函數做用是你的程序有良好的擴展性、複用性。服務器

一樣的功能要是用3次以上的話就建議使用函數。數據結構

特殊理解:閉包

函數能夠理解爲一個一個的功能塊,你把一個大的功能拆分紅一塊一塊的,用某項功能的時候就去調用某個功能塊便可!app

函數能夠理解爲:樂高積木,給你一塊一塊的,你能夠用這些積木塊組成你想要的任何功能!函數式編程

函數能夠調用函數!主函數的做用就是把函數進行串聯、調用!函數自己是不能本身執行的若是不調用就永不執行!函數

#---------------------------------------------------
def func1():
    pass
def func2(): pass def func3(): pass def func4(): pass func1() func2() func3() func4() if __name__ == '__main__': #調用上面的函數,判斷了、循環了調用等! #函數裏也能夠調用函數例子:def func4(): #__name__ 這個是用來判斷,若是你是把這個程序當模塊導入的話它的__name__就等於這個程序的文件名,若是是手動執行這個腳本好比:python test.py 那麼__name__就等於__main__ 因此,咱們能夠用他來作判斷,若是你是手動執行我就調用函數執行if下面的語句,若是你是調用模塊下面的if判斷後面的語句就不執行!僅當模塊使用! #若是函數當模塊導入的時候,他導入的是函數的名稱,內容沒有被導入,當你去調用的時候他纔會導入函數裏的信息。

自定義函數

1、背景

在學習函數以前,一直遵循:面向過程編程,即:根據業務邏輯從上到下實現功能,其每每用一長段代碼來實現指定功能,開發工程中比較常見的操做就是粘貼複製,也就是將以前實現的代碼塊複製到現需功能處,以下:學習

while True:
    if cpu利用率 > 90 %: # 發送郵件提醒  鏈接郵箱服務器 發送郵件 關閉鏈接 if 硬盤使用空間 > 90%: # 發送郵件提醒  鏈接郵箱服務器 發送郵件 關閉鏈接 if 內存佔用 >80%: # 發送郵件提醒  鏈接郵箱服務器 發送郵件 關閉鏈接

 上面的代碼就是面向過程的編程,可是若是報警多了的話成百的代碼須要如何操做呢?複製粘貼就會顯得本身low,該如何編寫呢,請看下面的代碼:測試

def 發送郵件(內容)
    #發送郵件提醒
 鏈接郵箱服務器 發送郵件 關閉鏈接 while True: if cpu利用率 > 90%: 發送郵件('CPU報警') if 硬盤使用空間 > 90%: 發送郵件('硬盤報警') if 內存佔用 > 80%: 發送郵件('內存報警')

 

第二個必然比第一個的重用性和可讀性要好,其實就是函數式編程和麪向過程編程的區別:

● 面向過程:更具需求一行一行壘加代碼!邏輯亂、並切代碼重複、不易修改重用性差!

● 函數式:將某功能代碼封裝到函數中,往後便無需重複編寫,僅調用函數便可

● 面向對象:對函數進行分類和封裝,讓開發"更快更好更強"

2、函數式編程

函數式編程最重要的是加強代碼的重用性和可讀性:

# 語法

def 函數(參數1,參數2,參數3,....):
        ' ' '註釋' ' ' 函數體 return 返回的值 #函數名的定義要能反映其意義 

函數的定義主要有以下要點:

● def 表示函數的關鍵字

● 函數名:函數的名稱,往後根據函數名調用函數

● 參數:爲函數體提供數據

● 函數體:函數中進行一系列的邏輯計算,如,發送郵件、計算出[11,22,45,56,45,]中的最大數等....

● 返回值:當函數執行完畢後,能夠給調用者返回數據。

函數使用的原則:先定義,後調用

 

函數即"變量","變量"必須先定義後引用,未定義而直接函數,就至關於在引用一個不存在的變量名

#測試一
def func():
    print('from foo')
    bar()
func()   #報錯

#測試二
def abc():
    print('from abc')
def func():
    print('from func')
    abc()
func() #正常

#測試三
def func():
    print('from func')
    abc()

def abc():
    print('from abc')
func() #不會報錯

#結論:函數的使用,必須遵循原則:先定義,後調用
#咱們在使用函數時,必定要明確的區分定義階段和調用階段

#定義階段:
def func():
    print('from func')
    abc()

def abc():
    print('from abc')
#調用階段
func()

 函數在定義階段都幹了哪些事?

#只檢測語法,不執行代碼
也就說,語法錯誤在函數定義階段就會檢測出來,而代碼的邏輯錯誤只有在執行的時候纔會知道

 定義函數的三種形式

#一、無參:應用場景僅僅只是執行一些操做,好比與用戶交互,打印
#二、有參:須要根據外部傳進來的參數,才能執行相應的邏輯,好比統計長度,求最大值最小值
#三、空函數:設計代碼結構

一、返回值

函數式一個功能塊,該功能到底執行成功與否,須要經過返回值來告知調用者。

def test():
    '''
    2*x+1
    :param x:整形數字
    :return: 返回計算結果
    ''' x=3 y=2*x+1 return y a = test() print(a)

 

def  發送短信():
    發送短信的代碼..:

    if 發送成功: return True else: return False while True: # 每次執行發送短信函數,都會將返回值自動賦值給result # 以後,能夠根據result來寫日誌,或重發等操做  result = 發送短信() if result == False: 記錄日誌,短信發送失敗....

二、參數

一、形參與實參

#形參即變量名,實參即變量值,函數調用時,將值綁定到變量名上,函數調用結束,解除綁定

 

二、具體應用

 

#一、位置參數:按照從左到右的順序定義的參數
        位置形參:必選參數
        位置實參:按照位置給形參傳值
#二、關鍵字參數:安裝key=value的形式定義的實參
 無需按照位置爲形象傳值 注意的問題: 1、關鍵字實參必須在位置實參右面 2、對同一個形參不能重複傳值 #三、默認參數:形參在定義時就已經爲其賦值  能夠傳值也能夠不傳值,常常須要變得參數定義成位置形參,變成較小的參數定義成默認參數(形參) 注意的問題: 1、只在定義時賦值一次 2、默認參數的定義應該在位置形參右面 3、默認參數一般應該定義成不可變類型 #四、可變長參數:  可變長指的是實參值的個數不固定 而實參有按位置和按關鍵字兩種形式定義,針對這兩種形式的可變長,形參對應有兩種解決方案來完整地存放它們,分別是*args,**kwargs # ########### *args #################### def foo(x,y,*args): print(x,y) print(args) foo(1,2,3,4,5) 輸出結果: C:\Python35\python3.exe C:/Users/ZR/PycharmProjects/python全棧開發/day15/def函數.py 1 2 (3, 4, 5) def foo(x,y,*args): print(x,y) print(args) foo(1,2,*[3,4,5]) 輸出結果: 1 2 (3, 4, 5) def foo(x,y,z): print(1,2,3) foo(*[1,2,3]) 輸出結果: 1 2 3 # ############ **kwargs ################### def foo(x,y,**kwargs): print(x,y) print(kwargs) foo(1,y=2,a=1,b=2,c=3) 輸出結果: 1 2 {'c': 3, 'a': 1, 'b': 2} def foo(x,y,**kwargs): print(x,y) print(kwargs) foo(1,y=2,**{'a':1,'b':2, 'c':3}) 輸出結果: #更上面輸出結果相同,只不過位置有所變化 1 2 {'a': 1, 'b': 2, 'c': 3} def foo(x,y,z): print(x, y, z) foo(**{'z':1,'x':2,'y':3}) 輸出結果: 2 3 1 # ##### *args + **kwargs############ def foo(x,y): print(x,y) def wrapper(*args,**kwargs): print('==========>') foo(*args,**kwargs) #五、命名關鍵字參數:*後定義的參數,必須被傳值(有默認值的除外),且必須按照關鍵字實參的形式傳遞 def foo(x,y,*args,a=1,b,**kwargs): print(x,y) print(args) print(a) print(b) print(kwargs) foo(1,2,3,4,5,b=3,c=4,d=5) 輸出結果: 1 2 (3, 4, 5) 1 3 {'c': 4, 'd': 5}

 

 

 

爲何要用參數?舉例說明

若是不定義參數,用函數的話:(每一個有相同功能的都寫個函數,說好的代碼簡化呢?)

def cpu報警郵件():
    # 發送郵件提醒
 鏈接郵箱服務器 發送郵件 關閉鏈接 def 硬盤報警郵件(): # 發送郵件提醒  鏈接郵箱服務器 發送郵件 關閉鏈接 def 內存報警郵件(): # 發送郵件提醒  鏈接郵箱服務器 發送郵件 關閉鏈接 while True: if CPU利用率 > 90%: cpu報警郵件() if 硬盤使用空間 > 90%: 硬盤報警郵件() if 內存佔用 > 80%: 內存報警郵件()

使用函數:(代碼明顯少了不少,把重複內用改成參數調用!)

def 發送郵件(內容)
    #發送郵件提醒
 鏈接郵箱服務器 發送郵件 關閉鏈接 while True: if cpu利用率 > 90%: 發送郵件('CPU報警') if 硬盤使用空間 > 90%: 發送郵件('硬盤報警') if 內存佔用 > 80%: 發送郵件('內存報警')

 函數的四種不一樣的參數:

一、普通參數

二、默認參數

三、動態參數

普通參數:

# #### 定義函數 ###############
# name 叫作函數func的形式參數,簡稱:形參
def func(name):
        print(name) # #### 執行函數 ############### # 'zhurui' 叫作函數func的實際參數,簡稱:實參 func('zhurui')

可是普通參數有個問題!你在定義參數的時候定義了幾個參數,你在調用的時候必須給他幾個參數不然會報錯! 

def func(name,age):
    print(name,age) func('william') 報錯提示: TypeError: func() missing 1 required positional argument: 'age' 其正確的寫法是: def func(name,age): print(name,age) func('william',24) 輸出結果: william 24

默認參數:

在你沒有給他指定參數的時候它就會使用默認參數!

def func(name, age = 24):
    print('%s:%s' %(name,age)) # 指定參數: func('william', 32) 輸出結果: william:24 # 使用默認參數 func('william') 輸出結果: william:27

 

3、局部變量與全局變量

在子程序中定義的變量成爲局部變量,在程序的一開始定義的變量稱爲全局變量。

全局變量做用域是整個程序,局部變量做用域是定義該變量的子程序。

當全局變量與局部變量同名時:

在定義局部變量的子程序內,局部變量起做用;在其餘地方全局變量起做用。

name='simon' #全局變量

def change_name():
    name='牛逼的人物'  #局部變量
    print('change_name',name)

change_name()
print(name)
輸出結果:
C:\Python35\python3.exe G:/python_s3/day15/全局變量與局部變量.py
change_name 牛逼的人物
simon

#輸出結果要想讓全局變量改變成局部變量須要在做用域中加 global name,至關於指針跟引用
代碼以下:
name='simon' #全局變量

def change_name():
    global name
    name='牛逼的人物'  #局部變量
    print('change_name',name)

change_name()
print(name)

輸出結果:
C:\Python35\python3.exe G:/python_s3/day15/全局變量與局部變量.py
change_name 牛逼的人物
牛逼的人物

  

name = 'simon'
def test1():
    #name = '孫悟空'
    global name #將全局變量引用過來,已經聲明,name就是全局的那個變量
    print('我要搞', name)
def test2():
    name = '基'
    print('我要搞', name)
#若是函數的內部無 global關鍵字,優先讀取局部變量,能讀取全局變量,沒法對全局變量從新賦值 NAME='fff',可是對於可變類型,能夠對內部元素進行操做
#若是函數中有global關鍵字,變量本質上就是全局的那個變量,可讀取可賦值
test1()
test2()

注意:

全局變量變量名大寫

局部變量變量名小寫

def huangwei():
    name = '黃偉'
    print(name)
    def liuyang():
        name = '劉洋'
        print(name)
        def nulige():
            name = '滬指花'
            print(name)
        print(name)
        nulige()
    liuyang()
    print(name)

huangwei()

def weihou():
    name = "陳卓"
    def weiweihou():
        global name
        name = "冷靜"
    weiweihou()
    print(name)
print(name)
weihou()
print(name)

輸出結果:

C:\Python35\python3.exe G:/python_s3/day15/全局變量與局部變量.py
剛娘
陳卓
冷靜  

代碼運行示例圖:

使用nonlocal 指定上一級變量

name = "剛娘"
def weihou():
    name = "陳卓"
    def weiweihou():
        nonlocal name  #nonlocal,指定上一級變量
        name = "冷靜"
    weiweihou()
    print(name)
print(name)
weihou()
print(name)

運行結果:
C:\Python35\python3.exe G:/python_s3/day15/全局變量與局部變量.py
剛娘
冷靜
剛娘

4、遞歸

在函數內部,能夠調用其餘函數。若是一個函數在內部調用自身

def calc(n):
    print(n)
    if int(n/2) == 0:
        return n
    return calc(int(n/2))
calc(10)

輸出結果:
C:\Python35\python3.exe G:/python_s3/day15/全局變量與局部變量.py
10
5
2
1
__author__ = 'zhurui'
import time

person_list=['zhurui','caiyunjie','yuanhao','simon','william','zcz']
def ask_way(person_list):
    print('-'*60)
    if len(person_list) == 0:
        return '沒人知道'
    person=person_list.pop(0)
    if person == 'simon':
        return '%s說:我知道,東方財富網就在東方財富大廈A座,下肇嘉浜路地鐵站就是' %person
    print('hi 美男[%s],敢問路在何方' % person)
    print('%s回答道:我不知道,但你慧眼識珠,我去幫你問問%s...' % (person,person_list) )
    time.sleep(3)
    res = ask_way(person_list)
    print('%s問的結果是: %res' %(person,res))
    return res

res = ask_way(person_list)
print(res)

 運行結果以下:

C:\Python35\python3.exe G:/python_s3/day15/全局變量與局部變量.py
------------------------------------------------------------
hi 美男[zhurui],敢問路在何方
zhurui回答道:我不知道,但你慧眼識珠,我去幫你問問['caiyunjie', 'yuanhao', 'simon', 'william', 'zcz']...
------------------------------------------------------------
hi 美男[caiyunjie],敢問路在何方
caiyunjie回答道:我不知道,但你慧眼識珠,我去幫你問問['yuanhao', 'simon', 'william', 'zcz']...
------------------------------------------------------------
hi 美男[yuanhao],敢問路在何方
yuanhao回答道:我不知道,但你慧眼識珠,我去幫你問問['simon', 'william', 'zcz']...
------------------------------------------------------------
yuanhao問的結果是: 'simon說:我知道,東方財富網就在東方財富大廈A座,下肇嘉浜路地鐵站就是'es
caiyunjie問的結果是: 'simon說:我知道,東方財富網就在東方財富大廈A座,下肇嘉浜路地鐵站就是'es
zhurui問的結果是: 'simon說:我知道,東方財富網就在東方財富大廈A座,下肇嘉浜路地鐵站就是'es
simon說:我知道,東方財富網就在東方財富大廈A座,下肇嘉浜路地鐵站就是

Process finished with exit code 0

遞歸特性:

1.必須有一個明確的結束條件

2.每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減小

3.遞歸效率不高,遞歸層次過多會致使棧溢出(在計算機中,函數調用是經過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層幀。因爲棧的大小不是無限的,因此,遞歸調用的次數過多,會致使棧溢出)

 

 

 

5、做用域

示例代碼以下:

#一、做用域即範圍
        - 全局範圍(內置名稱空間與全局名稱空間屬於該範圍):全局存活,全局有效
      - 局部範圍(局部名稱空間屬於該範圍):臨時存活,局部有效 #二、做用域關係是在函數定義階段就已經固定的,與函數的調用位置無關,以下 x = 1 def f1(): def f2(): print(x) return f2 x = 100 def f3(func): x=2 func() x = 10000 f3(f1()) 結果: C:\Python35\python3.exe G:/python_s3/day16/做用域.py 10000 #三、查看做用域:globals(),locals()  LEGB 表明名字查找順序: locals -> enclosing function -> globals -> __builtins__ locals 是函數內的名字空間,包括局部變量和形參 enclosing 外部嵌套函數的名字空間(閉包中常見) globals 全局變量,函數定義所在模塊的名字空間 builtins 內置模塊的名字空間

 

6、匿名函數

代碼以下:

#一、 代碼方式一
def calc(x):
    return x+1 res = calc(10) print(res) 輸出結果爲: C:\Python35\python3.exe G:/python_s3/day16/匿名函數.py 11 #二、用lambda方式表達 print (lambda x:x+1) #表明單純的輸出內存地址 func=lambda x:x+1 print (func(10)) 輸出結果爲: <function <lambda> at 0x00000000006EE0D0> 11
#表達方式1
name = 'simon'
def change_name(x):
    return name+'_sb' res = change_name(name) print(res) #lambda方式表達: name='simon' func = lambda x:x+'_sb' print(func(name)) 輸出結果: C:\Python35\python3.exe G:/python_s3/day16/匿名函數.py simon_sb simon_sb

 匿名函數補充:

f = lambda x,y,z:(x+1,y+1,z+1)
print(f(1,2,3)) 輸出結果爲: C:\Python35\python3.exe G:/python_s3/day16/匿名函數.py (2, 3, 4)

7、函數式編程

11 高階函數

知足倆個特性任意一個即爲高階函數

一、函數的傳入參數是一個函數名

二、函數的返回值是一個函數名

例一:不可變:不用變量保存狀態,不修改變量

#非函數式
a = 1
def incr_test1():
    global a
    a+=1
    return a
incr_test1()
print(a)
輸出結果:
C:\Python35\python3.exe G:/python_s3/day16/匿名函數.py
2

#函數式
n=1
def incr_test2(n):
    return n+1
print(incr_test2(2))
print (n)

輸出結果:
C:\Python35\python3.exe G:/python_s3/day16/匿名函數.py
3
1
map函數
filter函數
reduce函數

 簡單小結:

小結

8、內置函數

#空,None,0的布爾值爲False,其他都爲True
print(bool(''))
print(bool(None)) print(bool(0)) C:\Python35\python3.exe G:/python_s3/day16/內置函數.py False False False #bytes()函數,轉換成二進制 name='你好' print(bytes(name,encoding='utf-8')) print(bytes(name,encoding='utf-8').decode('utf-8')) #decode是將前面處理的編碼再解碼,還原成原來 print(bytes(name,encoding='gbk')) print(bytes(name,encoding='gbk').decode('gbk')) print(bytes(name,encoding='ascii')) #ascii不能編碼中文 C:\Python35\python3.exe G:/python_s3/day16/內置函數.py b'\xe4\xbd\xa0\xe5\xa5\xbd' 你好 b'\xc4\xe3\xba\xc3' 你好

 

View Code

 max函數小結:

1、max函數處理的是可迭代對象,至關於一個for循環取出每一個元素進行比較,注意,不一樣類型之間不能進行比較
二、每一個元素間進行比較,是從每一個元素的第一個位置依次比較,若是這一個位置分出大小,後面的都不須要比較了,直接得出這倆元素的大小

 

#空,None,0的布爾值爲False,其他都爲True
# print(bool(''))
# print(bool(None))
# print(bool(0))

# #bytes()函數,轉換成二進制
# name='你好'
# print(bytes(name,encoding='utf-8'))
# print(bytes(name,encoding='utf-8').decode('utf-8')) #decode是將前面處理的編碼再解碼,還原成原來
# print(bytes(name,encoding='gbk'))
# print(bytes(name,encoding='gbk').decode('gbk'))
#
# print(bytes(name,encoding='ascii')) #ascii不能編碼中文

#chr()函數
# print(chr(97))
# print(dir(dict))
# print(divmod(10,36))
# dic ={'name':'alex'}
# print(dic)
# #可hash的數據類型即不可變類型,不可hash的類型便可變數據類型
# name='simon'
# print(hash(name))

# print(help(all))
#
# print(bin(10)) #10進制->2進制
# print(hex(12))
# print(oct(12)) #10進制轉8進制
#
# print(isinstance(1,int))

# l=[1,3,100,-1,-2,4]
# print(max(l))
# print(min(l))

#zip()函數,至關於拉鍊的做用
# print(list(zip(('a','b','c'),(1,2,3))))
# print(list(zip(('a','b','c'),(1,2,3))))
# print(list(zip(('a','b','c','d'),(1,2,3))))
#
# p={'name':'alex','age':18,'gender':'none'}
# print(list(zip(p.keys(),p.values()))) #不加list,只會輸出內存地址
# # print(list(p.keys()))
# # print(list(p.values()))
#
# print(list(zip('hello','12345'))) #zip方法裏傳兩個參數,都是序列類型(列表,元祖,字符串)

# l=[1,3,100,-1,-2,4]
# print(max(l))
# print(min(l))

people=[ {'name':'alex','age':1000}, {'name':'wupeiqi','age':10000}, {'name':'yuanhao','age':9000}, {'name':'simon','age':18}, ] print('-------->',max(people,key=lambda dic:dic['age'])) # age_dic={'age1':18,'age4':20,'age3':100,'age2':30} # print(max(age_dic.values())) # print((max(age_dic.keys()),max(age_dic.values())))  age_dic={'alex_age':18,'wupeiqi_age':20,'zsc_age':100,'lhf_age':30} # print(max(age_dic.values())) #默認比較的是字典的key # print(max(age_dic)) # for item in zip(age_dic.values(),age_dic.keys()): #(18.'alex_age') (20,'wupeiqi_age') # print(item) # print(list(max(zip(age_dic.values(),age_dic.keys())))) # # l = [ # (5,'e'), # (1,'b'), # (3,'a'), # (4,'d'), # ] # print(list(max(l))) # # l1=['a10','b12','c10',100] #不一樣類型之間不能進行比較 # l1=['a10','b12','c10'] #不一樣類型之間不能進行比較 # print(list(max(l))) # print(max(l1)) #總結 #一、max的比較,傳入的類型爲可迭代類型 #二、max的比較,從第一個位置開始比較,若是已經比較出大小,不會再比較後面的位置,直接輸出結果 # print(chr(97)) # print(ord('a')) #pow()函數: print(pow(2,3)) #2**3 print(pow(3,3,2)) #3**3/2 #reversed()函數,使結果反轉 # l=[1,2,3,4] # print(list(reversed(l))) # # #round()函數:四舍不入函數 # print(round(3.5)) # # #set()函數: # print(set('hello')) #selict()函數:切片 # l='hello' # # print(l[3:5]) # s1=slice(3,5) # s2=slice(1,4,2) # print(l[s1]) # print(l[s2]) # print(s2.start) # print(s2.stop) # print(s2.step) #sorted()函數: # l=[3,2,1,5,7] # l1=[3,2,'a',1,5,7] # print(sorted(l)) # print(sorted(l1)) #程序本質就是在比較大小,不一樣類型之間不能夠比較大小  people=[ {'name':'alex','age':1000}, {'name':'wupeiqi','age':10000}, {'name':'yuanhao','age':9000}, {'name':'simon','age':18}, ] print(sorted(people,key=lambda dic:dic['age'])) name_dic={ 'abyuanhao':900, 'alex':200, 'wupei':300, } print(sorted(name_dic)) print(sorted(name_dic,key=lambda key:name_dic[key])) print(sorted(zip(name_dic.values(),name_dic.keys()))) #str()函數 print(str('l')) print(str({'a':1})) #sum()函數 l=[1,2,3,4] print(sum(l)) print(sum(range(5))) p=range(10) print(sum(p)) #type()函數 l=[1,2,3,4] print('>>>>>>>',type(l)) msg='123' if type(msg) is str: msg=int(msg) msg+=1 print(msg) #var()函數 def test(): msg='人麼容量爲進入高溫熱未來惹我竟然我給我' # print(locals()) print(vars()) test() #import ----->sys-------->__import__() #__import__()函數: #能夠導入字符串 # import 'test' #不能導入字符串
相關文章
相關標籤/搜索