python全棧開發筆記---------函數

一 數學定義的函數與python中的函數

 初中數學函數定義:通常的,在一個變化過程當中,若是有兩個變量x和y,而且對於x的每個肯定的值,y都有惟一肯定的值與其對應,那麼咱們就把x稱爲自變量,把y稱爲因變量,y是x的函數。自變量x的取值範圍叫作這個函數的定義域

例如y=2*x

 python中函數定義:函數是邏輯結構化和過程化的一種編程方法。

python中函數定義方法:
 
def test(x):
    "The function definitions"
    x+=1
    return x
     
def:定義函數的關鍵字
test:函數名
():內可定義形參
"":文檔描述(非必要,可是強烈建議爲你的函數添加描述信息)
x+=1:泛指代碼塊或程序處理邏輯
return:定義返回值


調用運行:能夠帶參數也能夠不帶
函數名()

補充:html

1.編程語言中的函數與數學意義的函數是大相徑庭的倆個概念,編程語言中的函數是經過一個函數名封裝好一串用來完成某一特定功能的邏輯,數學定義的函數就是一個等式,等式在傳入因變量值x不一樣會獲得一個結果y,這一點與編程語言中相似(也是傳入一個參數,獲得一個返回值),不一樣的是數學意義的函數,傳入值相同,獲得的結果必然相同且沒有任何變量的修改(不修改狀態),而編程語言中的函數傳入的參數相同返回值可不必定相同且能夠修改其餘的全局變量值(由於一個函數a的執行可能依賴於另一個函數b的結果,b可能獲得不一樣結果,那即使是你給a傳入相同的參數,那麼a獲得的結果也確定不一樣)前端

2.函數式編程就是:先定義一個數學函數(數學建模),而後按照這個數學模型用編程語言去實現它。至於具體如何實現和這麼作的好處,且看後續的函數式編程。python

 

二 爲什麼使用函數

 背景提要程序員

如今老闆讓你寫一個監控程序,監控服務器的系統情況,當cpu\memory\disk等指標的使用量超過閥值時即發郵件報警,你掏空了全部的知識量,寫出瞭如下代碼

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

上面的代碼實現了功能,但即便是鄰居老王也看出了端倪,老王親切的摸了下你家兒子的臉蛋,說,你這個重複代碼太多了,每次報警都要重寫一段發郵件的代碼,太low了,這樣幹存在2個問題:數據庫

  1. 代碼重複過多,一個勁的copy and paste不符合高端程序員的氣質
  2. 若是往後須要修改發郵件的這段代碼,好比加入羣發功能,那你就須要在全部用到這段代碼的地方都修改一遍

你以爲老王說的對,你也不想寫重複代碼,但又不知道怎麼搞,老王好像看出了你的心思,此時他抱起你兒子,笑着說,其實很簡單,只須要把重複的代碼提取出來,放在一個公共的地方,起個名字,之後誰想用這段代碼,就經過這個名字調用就好了,以下編程

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

 

你看着老王寫的代碼,氣勢恢宏、磅礴大氣,代碼裏透露着一股內斂的傲氣,心想,老王這我的真是不通常,忽然對他的背景更感興趣了,問老王,這些花式玩法你都是怎麼知道的? 老王親了一口你兒子,捋了捋不存在的鬍子,淡淡的講,「老夫,年少時,師從京西沙河淫魔銀角大王 」, 你一聽「銀角大王」這幾個字,不禁的嬌軀一震,心想,真nb,怪不得代碼寫的這麼6, 這「銀角大王」當年在江湖上但是數得着的響噹噹的名字,只惋惜後期縱慾過分,卒於公元2016年, 真是惋惜了,只留下其哥哥孤守當年兄弟倆一塊兒打下來的江山。 此時你看着的老王離開的身影,感受你兒子跟他愈來愈像了。。。數組

總結使用函數的好處:服務器

1.代碼重用數據結構

2.保持一致性,易維護app

3.可擴展性

三 函數和過程

過程定義:過程就是簡單特殊沒有返回值的函數

這麼看來咱們在討論爲什麼使用函數的的時候引入的函數,都沒有返回值,沒有返回值就是過程,沒錯,可是在python中有比較神奇的事情

def test01():
    msg='hello The little green frog'
    print msg
 
def test02():
    msg='hello WuDaLang'
    print msg
    return msg
 
 
t1=test01()
 
t2=test02()
 
 
print 'from test01 return is [%s]' %t1
print 'from test02 return is [%s]' %t2

總結:當一個函數/過程沒有使用return顯示的定義返回值時,python解釋器會隱式的返回None,

因此在python中即使是過程也能夠算做函數。

def test01():
    pass
 
def test02():
    return 0
 
def test03():
    return 0,10,'hello',['alex','lb'],{'WuDaLang':'lb'}
 
t1=test01()
t2=test02()
t3=test03()
 
 
print 'from test01 return is [%s]: ' %type(t1),t1
print 'from test02 return is [%s]: ' %type(t2),t2
print 'from test03 return is [%s]: ' %type(t3),t3

總結:

   返回值數=0:返回None

   返回值數=1:返回object

   返回值數>1:返回tuple

 

四 函數參數

 

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

2.實參能夠是常量、變量、表達式、函數等,不管實參是何種類型的量,在進行函數調用時,它們都必須有肯定的值,以便把這些值傳送給形參。所以應預先用賦值,輸入等辦法使參數得到肯定值

3.位置參數和關鍵字(標準調用:實參與形參位置一一對應;關鍵字調用:位置無需固定)

4.默認參數

5.參數組

 

def test(x,*args,**kwargs):
    print(x)
    print(args)
    print(kwargs)
test(1,2,3,5,432,4,y=2,z=3)    

輸出結果:1
(2, 3, 5, 432, 4)
{'y': 2, 'z': 3}

 

五 局部變量和全局變量

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

全局變量做用域是整個程序,局部變量做用域是定義該變量的子程序。
當全局變量與局部變量同名時:
在定義局部變量的子程序內,局部變量起做用;在其它地方全局變量起做用。
name='lhf'

def change_name():
    print('個人名字',name)

change_name()


def change_name():
    name='帥了一筆'
    print('個人名字',name)

change_name()
print(name)



def change_name():
    global name
    name='帥了一筆'
    print('個人名字',name)

change_name()
print(name)

 

 

六 前向引用之'函數即變量'

def action():
    print 'in the action'
    logger()
action()
報錯NameError: global name 'logger' is not defined


def logger():
    print 'in the logger'
def action():
    print 'in the action'
    logger()
 
action()
 

def action():
    print 'in the action'
    logger()
def logger():
    print 'in the logger'
 
action()

 

七 嵌套函數和做用域

 

看上面的標題的意思是,函數還能套函數?of course

name = "Alex"
 
def change_name():
    name = "Alex2"
 
    def change_name2():
        name = "Alex3"
        print("第3層打印",name)
 
    change_name2() #調用內層函數
    print("第2層打印",name)
 
 
change_name()
print("最外層打印",name)

 

此時,在最外層調用change_name2()會出現什麼效果?

沒錯, 出錯了, 爲何呢?

 

做用域在定義函數時就已經固定住了,不會隨着調用位置的改變而改變

例一:
name='alex'

def foo():
    name='lhf'
    def bar():
        print(name)
    return bar

func=foo()
func()


例二:
name='alex'

def foo():
    name='lhf'
    def bar():
        name='wupeiqi'
        def tt():
            print(name)
        return tt
    return bar

func=foo()
func()()

 

八 遞歸調用

 

古之慾明明德於天下者,先治其國;欲治其國者,先齊其家;欲齊其家者,先修其身;欲修其身者,先正其心;欲正其心者,先誠其意;欲誠其意者,先致其知,致知在格物。物格然後知至,知至然後意誠,意誠然後心正,心正然後身修,身修然後家齊,家齊然後國治,國治然後天下平。

 

在函數內部,能夠調用其餘函數。若是在調用一個函數的過程當中直接或間接調用自身自己

def calc(n):
    print(n)
    if int(n/2) ==0:
        return n
    return calc(int(n/2))
 
calc(10)
 
輸出:
10
5
2
1
0( 3.53py後版本有顯示結果0的出現)

 

遞歸特性:

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

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

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

堆棧掃盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html 

尾遞歸優化:http://egon09.blog.51cto.com/9161406/1842475

 

data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
 
 
def binary_search(dataset,find_num):
    print(dataset)
 
    if len(dataset) >1:
        mid = int(len(dataset)/2)
        if dataset[mid] == find_num:  #find it
            print("找到數字",dataset[mid])
        elif dataset[mid] > find_num :# 找的數在mid左面
            print("\033[31;1m找的數在mid[%s]左面\033[0m" % dataset[mid])
            return binary_search(dataset[0:mid], find_num)
        else:# 找的數在mid右面
            print("\033[32;1m找的數在mid[%s]右面\033[0m" % dataset[mid])
            return binary_search(dataset[mid+1:],find_num)
    else:
        if dataset[0] == find_num:  #find it
            print("找到數字啦",dataset[0])
        else:
            print("沒的分了,要找的數字[%s]不在列表裏" % find_num)
 
 
binary_search(data,66)

二分查找
View Code

 

九 匿名函數

 

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

#這段代碼
def calc(n):
    return n**n
print(calc(10))
 
#換成匿名函數
calc = lambda n:n**n
print(calc(10))

 

你也許會說,用上這個東西沒感受有毛方便呀, 。。。。呵呵,若是是這麼用,確實沒毛線改進,不過匿名函數主要是和其它函數搭配使用的呢,以下

l=[3,2,100,999,213,1111,31121,333]
print(max(l))

dic={'k1':10,'k2':100,'k3':30}


print(max(dic))
print(dic[max(dic,key=lambda k:dic[k])])

 

res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
    print(i)

輸出
1
25
49
16
64

 

十 函數式編程

 

峯哥原創面向過程解釋:

函數的參數傳入,是函數吃進去的食物,而函數return的返回值,是函數拉出來的結果,面向過程的思路就是,把程序的執行當作一串首尾相連的函數,一個函數吃,拉出的東西給另一個函數吃,另一個函數吃了再繼續拉給下一個函數吃。。。


例如:
用戶登陸流程:前端接收處理用戶請求-》將用戶信息傳給邏輯層,邏輯詞處理用戶信息-》將用戶信息寫入數據庫
驗證用戶登陸流程:數據庫查詢/處理用戶信息-》交給邏輯層,邏輯層處理用戶信息-》用戶信息交給前端,前端顯示用戶信息

 

 

函數式編程: 

http://egon09.blog.51cto.com/9161406/1842475

11 高階函數

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

1.函數的傳入參數是一個函數名

2.函數的返回值是一個函數名

 

array=[1,3,4,71,2]

ret=[]
for i in array:
    ret.append(i**2)
print(ret)

#若是咱們有一萬個列表,那麼你只能把上面的邏輯定義成函數
def map_test(array):
    ret=[]
    for i in array:
        ret.append(i**2)
    return ret

print(map_test(array))

#若是咱們的需求變了,不是把列表中每一個元素都平方,還有加1,減一,那麼能夠這樣
def add_num(x):
    return x+1
def map_test(func,array):
    ret=[]
    for i in array:
        ret.append(func(i))
    return ret

print(map_test(add_num,array))
#可使用匿名函數
print(map_test(lambda x:x-1,array))


#上面就是map函數的功能,map獲得的結果是可迭代對象
print(map(lambda x:x-1,range(5)))

map函數
map函數
from functools import reduce
#合併,得一個合併的結果
array_test=[1,2,3,4,5,6,7]
array=range(100)

#報錯啊,res沒有指定初始值
def reduce_test(func,array):
    l=list(array)
    for i in l:
        res=func(res,i)
    return res

# print(reduce_test(lambda x,y:x+y,array))

#能夠從列表左邊彈出第一個值
def reduce_test(func,array):
    l=list(array)
    res=l.pop(0)
    for i in l:
        res=func(res,i)
    return res

print(reduce_test(lambda x,y:x+y,array))

#咱們應該支持用戶本身傳入初始值
def reduce_test(func,array,init=None):
    l=list(array)
    if init is None:
        res=l.pop(0)
    else:
        res=init
    for i in l:
        res=func(res,i)
    return res

print(reduce_test(lambda x,y:x+y,array))
print(reduce_test(lambda x,y:x+y,array,50))

reduce函數
reduce函數
#電影院彙集了一羣看電影bb的傻逼,讓咱們找出他們
movie_people=['alex','wupeiqi','yuanhao','sb_alex','sb_wupeiqi','sb_yuanhao']

def tell_sb(x):
    return x.startswith('sb')


def filter_test(func,array):
    ret=[]
    for i in array:
        if func(i):
            ret.append(i)
    return ret

print(filter_test(tell_sb,movie_people))


#函數filter,返回可迭代對象
print(filter(lambda x:x.startswith('sb'),movie_people))

filter函數
filter函數
#固然了,map,filter,reduce,能夠處理全部數據類型

name_dic=[
    {'name':'alex','age':1000},
    {'name':'wupeiqi','age':10000},
    {'name':'yuanhao','age':9000},
    {'name':'linhaifeng','age':18},
]
#利用filter過濾掉千年王八,萬年龜,還有一個九千歲
def func(x):
    age_list=[1000,10000,9000]
    return x['age'] not in age_list


res=filter(func,name_dic)
for i in res:
    print(i)

res=filter(lambda x:x['age'] == 18,name_dic)
for i in res:
    print(i)


#reduce用來計算1到100的和
from functools import reduce
print(reduce(lambda x,y:x+y,range(100),100))
print(reduce(lambda x,y:x+y,range(1,101)))

#用map來處理字符串列表啊,把列表中全部人都變成sb,比方alex_sb
name=['alex','wupeiqi','yuanhao']

res=map(lambda x:x+'_sb',name)
for i in res:
    print(i)

總結
總結

小結:

# map()
# 處理序列中的每個元素,獲得的結果是一個‘列表’(便可迭代對象),該‘列表’元素的個數及位置與原來的同樣

#filter
#遍歷序列中的每一個元素,判斷每一個元素獲得的布爾值,若是是True則留下來
people =[
    {'name':'alex','age':10000},
    {'name':'wuqi','age':5000},
    {'name':'wangwang','age':3000},
    {'name':'meimei','age':20}
]
v =list(filter(lambda p:p['age']<=20,people))
print(v)    #[{'name': 'meimei', 'age': 20}]
 
 
#reduce
#引入文件 from functools import reduce
#處理一個序列,而後把序列進行合併操做
from functools import reduce
print(reduce(lambda x,y:x+y,range(100),100))  #5050   後面的設定初始值100
print(reduce(lambda x,y:x+y,range(1,100)))    #4950   左開,右閉區間
 
 
 
 

十一 內置函數

字典的運算:最小值,最大值,排序
salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}

迭代字典,取得是key,於是比較的是key的最大和最小值
>>> max(salaries)
'yuanhao'
>>> min(salaries)
'alex'

能夠取values,來比較
>>> max(salaries.values())
>>> min(salaries.values())
但一般咱們都是想取出,工資最高的那我的名,即比較的是salaries的值,獲得的是鍵
>>> max(salaries,key=lambda k:salary[k])
'alex'
>>> min(salaries,key=lambda k:salary[k])
'yuanhao'



也能夠經過zip的方式實現
salaries_and_names=zip(salaries.values(),salaries.keys()) 

先比較值,值相同則比較鍵
>>> max(salaries_and_names)
(100000000, 'alex')


salaries_and_names是迭代器,於是只能訪問一次
>>> min(salaries_and_names)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence



sorted(iterable,key=None,reverse=False)
View Code

內置參數詳解 https://docs.python.org/3/library/functions.html?highlight=built#ascii 

 

十二 本節做業

有如下員工信息表

固然此表你在文件存儲時能夠這樣表示

1 1,Alex Li,22,13651054608,IT,2013-04-01

現須要對這個員工信息文件,實現增刪改查操做

  1. 可進行模糊查詢,語法至少支持下面3種:可建立新員工紀錄,以phone作惟一鍵,staff_id需自增
    1.   select name,age from staff_table where age > 22
    2.   select  * from staff_table where dept = "IT"
    3.       select  * from staff_table where enroll_date like "2013"
    4. 查到的信息,打印後,最後面還要顯示查到的條數 
  2. 可刪除指定員工信息紀錄,輸入員工id,便可刪除
  3. 可修改員工信息,語法以下:
    1.   UPDATE staff_table SET dept="Market" WHERE where dept = "IT"

 注意:以上需求,要充分使用函數,請盡你的最大限度來減小重複代碼!

內置函數
匿名函數
遞歸
=====================做業一
#用map來處理字符串列表啊,把列表中全部人都變成sb,比方alex_sb
name=['alex','wupeiqi','yuanhao']


#用map來處理下述l,而後用list獲得一個新的列表,列表中每一個人的名字都是sb結尾
>>> l=[{'name':'alex'},{'name':'y'}]
>>> x=map(lambda i:{'name':i['name']+'sb'},l)
>>> for i in x:
...  print(i)
...
{'name': 'alexsb'}
{'name': 'ysb'}


=====================做業二
#用filter來處理,獲得股票價格大於20的股票名字
shares={
    'IBM':36.6,
    'Lenovo':23.2,
    'oldboy':21.2,
    'ocean':10.2,
}
>>> f=filter(lambda k:shares[k]>20,shares)
>>> list(f)
['IBM', 'Lenovo', 'oldboy']



=====================做業三
#以下,每一個小字典的name對應股票名字,shares對應多少股,price對應股票的價格
portfolio = [
    {'name': 'IBM', 'shares': 100, 'price': 91.1},
    {'name': 'AAPL', 'shares': 50, 'price': 543.22},
    {'name': 'FB', 'shares': 200, 'price': 21.09},
    {'name': 'HPQ', 'shares': 35, 'price': 31.75},
    {'name': 'YHOO', 'shares': 45, 'price': 16.35},
    {'name': 'ACME', 'shares': 75, 'price': 115.65}
]

1:map來得出一個包含數字的迭代器,數字指的是:購買每支股票的總價格
>>> m=map(lambda item:item['shares']*item['price'],l)

2:基於1的結果,用reduce來計算,購買這些股票總共花了多少錢
>>> r=reduce(lambda x,y:x+y,m)
>>> r
51009.75

3:用filter過濾出,單價大於100的股票有哪些
>>> f=filter(lambda item:item['price'] > 100,l)
View Code

 

 函數總結:

形參

  普通參數必須一一對應,必須傳

  默認參數可傳可不傳   實參的級別大於形參級別,

  一個形參只能給它傳一次,不能被賦予多個值

  *args 處理關鍵字、**字典,其餘均可以傳,它是一個元組,不傳也能夠

  **kwargs只能接收關鍵字參數,若是接收字典的話,在字典前面要加**,不傳也能夠

  優先級別 先是位置一一對應,普通參數,默認參數,*參數,**參數

實參

  普通參數必須一一對應,必須傳

相關文章
相關標籤/搜索