1.定義函式
函式代碼塊以 def 關鍵詞開頭,后接函式識別符號名稱和圓括號 (),
任何傳入引數和自變數必須放在圓括號中間,圓括號之間可以用于定義引數,
函式的第一行陳述句可以選擇性地使用檔案字串—用于存放函式說明,
函式內容以冒號起始,并且縮進,
return [運算式] 結束函式,選擇性地回傳一個值給呼叫方,不帶運算式的return相當于回傳 None,
可以回傳多個值,其實就是一個tuple,
def my_abs(x): if x >= 0: return x else: return -x
空函式:如果想定義一個什么事也不做的空函式,可以用來占位,可以用pass陳述句:
def nop(): pass
2.引數傳遞
可更改(mutable)與不可更改(immutable)物件
在 python 中,strings, tuples, 和 numbers 是不可更改的物件,而 list,dict 等則是可以修改的物件,
不可變型別:變數賦值 a=5 后再賦值 a=10,這里實際是新生成一個 int 值物件 10,再讓 a 指向它,而 5 被丟棄,不是改變a的值,相當于新生成了a,
可變型別:變數賦值 la=[1,2,3,4] 后再賦值 la[2]=5 則是將 list la 的第三個元素值更改,本身la沒有動,只是其內部的一部分值被修改了,
python 函式的引數傳遞:
不可變型別:類似 c++ 的值傳遞,如 整數、字串、元組,如fun(a),傳遞的只是a的值,沒有影響a物件本身,比如在 fun(a)內部修改 a 的值,只是修改另一個復制的物件,不會影響 a 本身,
可變型別:類似 c++ 的參考傳遞,如 串列,字典,如 fun(la),則是將 la 真正的傳過去,修改后fun外部的la也會受影響
python 中一切都是物件,嚴格意義我們不能說值傳遞還是參考傳遞,我們應該說傳不可變物件和傳可變物件,
3.引數
呼叫函式時可使用的正式引數型別:必需引數,關鍵字引數,默認引數,不定長引數等,引數型別也可以組合,
a. 必須引數,也叫位置引數
必需引數須以正確的順序傳入函式,呼叫時的數量必須和宣告時的一樣,
b.關鍵字引數
關鍵字引數和函式呼叫關系緊密,函式呼叫使用關鍵字引數來確定傳入的引數值,
使用關鍵字引數允許函式呼叫時引數的順序與宣告時不一致,因為 Python 解釋器能夠用引數名匹配引數值,
def printinfo( name, age ): "列印任何傳入的字串" print ("名字: ", name) print ("年齡: ", age) return #呼叫printinfo函式 printinfo( age=50, name="runoob" )
c.默認引數
呼叫函式時,如果沒有傳遞引數,則會使用默認引數,默認引數要放在最后,默認引數必須指向不可變物件,
def printinfo( name, age = 35 ): "列印任何傳入的字串" print ("名字: ", name) print ("年齡: ", age) return #呼叫printinfo函式 printinfo( age=50, name="runoob" ) print ("------------------------") printinfo( name="runoob" )
d.不定長引數,可變引數,收集引數
需要一個函式能處理比當初宣告時更多的引數,
加了星號 * 的引數會以元組(tuple)的形式匯入,存放所有未命名的變數引數,
果在函式呼叫時沒有指定引數,它就是一個空元組,我們也可以不向函式傳遞未命名的變數,
如果* 后,還有引數,引數必須用關鍵字傳入,
加了兩個星號 ** 的引數會以字典的形式匯入,允許你傳入0個或任意個含引數名的引數,這些關鍵字引數在函式內部自動組裝為一個dict,
def printinfo( arg1, *vartuple ): "列印任何傳入的引數" print ("輸出: ") print (arg1) for var in vartuple: print (var) return # 呼叫printinfo 函式 printinfo( 10 ) printinfo( 70, 60, 50 )
>>> nums = [1, 2, 3]
>>> calc(*nums)
14
def fun(**kwargs):
for x, y in kwargs.items():
print(x,y)
fun(city = "asdasd",beijing = "sadasdw")
4.匿名函式
python 使用 lambda 來創建匿名函式,
所謂匿名,意即不再使用 def 陳述句這樣標準的形式定義一個函式,
lambda 只是一個運算式,函式體比 def 簡單很多,
lambda的主體是一個運算式,而不是一個代碼塊,僅僅能在lambda運算式中封裝有限的邏輯進去,
lambda 函式擁有自己的命名空間,且不能訪問自己引數串列之外或全域命名空間里的引數,
雖然lambda函式看起來只能寫一行,卻不等同于C或C++的行內函式,后者的目的是呼叫小函式時不占用堆疊記憶體從而增加運行效率,
sum = lambda arg1, arg2: arg1 + arg2
請參考:https://www.cnblogs.com/kaishirenshi/p/8611358.html
two_sum = (lambda x, y: x + y)(3, 4)
匿名函式也是一個函式物件,也可以把匿名函式賦值給一個變數,再利用變數來呼叫該函式:
>> f = lambda x: x * x >>> f <function <lambda> at 0x101c6ef28> >>> f(5) 25
也可以把匿名函式作為回傳值回傳,
def build(x, y): return lambda: x * x + y * y
5.高階函式
一個函式就可以接收另一個函式作為引數,這種函式就稱之為高階函式,
def add(x, y, f): return f(x) + f(y) def zheng(n): if n > 0: return n else: return -n x = -5 y = 10 f = zheng #變數指向函式,函式名就是變數 print(add(x, y, f))
5.1 map()和reduce()函式
map()函式接收兩個引數,一個是函式,一個是Iterable,map將傳入的函式依次作用到序列的每個元素,并把結果作為新的Iterator回傳,
>>> def f(x): ... return x * x ... >>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> list(r) [1, 4, 9, 16, 25, 36, 49, 64, 81]
再看reduce的用法,reduce把一個函式作用在一個序列[x1, x2, x3, ...]上,這個函式必須接收兩個引數,reduce把結果繼續和序列的下一個元素做累積計算:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
>>> from functools import reduce
>>> def add(x, y):
... return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25
作業:
利用map和reduce撰寫一個str2float函式,把字串'123.456'轉換成浮點數123.456:
摘選了一個答案:
def str2float(str): d = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} def s2n(s): return d[s] def fn(a, b): return reduce(lambda x, y: x * 10 + y, map(s2n, a)) + reduce(lambda x, y: x * 10 + y, map(s2n, b)) * (10 ** -len(b)) theS = str.split('.') return fn(theS[0], theS[1])
5.2 filter
Python內建的filter()函式用于過濾序列,
和map()類似,filter()也接收一個函式和一個序列,和map()不同的是,filter()把傳入的函式依次作用于每個元素,然后根據回傳值是True還是False決定保留還是丟棄該元素,
def is_odd(n): return n % 2 == 1 list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) # 結果: [1, 5, 9, 15]
用filter求素數
def _odd_iter(): #構造一個從3開始的奇數序列,這是一個生成器,并且是一個無限序列, n = 1 while True: n = n + 2 yield n
def _not_divisible(n): #定義一個篩選函式 return lambda x: x % n > 0
def primes(): #定義一個生成器,不斷回傳下一個素數 yield 2 it = _odd_iter() # 初始序列 while True: n = next(it) # 回傳序列的第一個數 #每次回圈,it會改變,n取新序列的第一個數, yield n it = filter(_not_divisible(n), it) # 構造新序列 #回圈一次,就將n及n倍數的值去掉回傳新的Iterator
#將lambda函式寫在filter中,篩選有問題,沒搞懂是怎么回事,應該是閉包的問題,
# 列印1000以內的素數: for n in primes(): if n < 1000: print(n) else: break
5.3 stored
sorted()函式也是一個高階函式,可以接收一個key函式來實作自定義的排序,例如按絕對值大小排序:
先將序列輸入key函式,獲取新序列,然后再排序,
>>> sorted([36, 5, -12, 9, -21]) [-21, -12, 5, 9, 36] >>> sorted([36, 5, -12, 9, -21], key=abs) [5, 9, -12, -21, 36] >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True) #反向排序 ['Zoo', 'Credit', 'bob', 'about']
key指定的函式將作用于list的每一個元素上,并根據key函式回傳的結果進行排序,
序列中的元素是一個個傳入key函式,再回傳一個新序列,
max,min
salaries={ 'siry':3000, 'tom':7000, 'lili':10000, 'jack':2000 } # 需求1:找出薪資最高的那個人=》lili # res=max([3,200,11,300,399]) # print(res) # res=max(salaries) # print(res) salaries={ 'siry':3000, 'tom':7000, 'lili':10000, 'jack':2000 } # 迭代出的內容 比較的值 # 'siry' 3000 # 'tom' 7000 # 'lili' 10000 # 'jack' 2000 # def func(k): # return salaries[k] # ========================max的應用 # res=max(salaries,key=func) # 回傳值=func('siry') # print(res) # res=max(salaries,key=lambda k:salaries[k]) # print(res) # ========================min的應用 # res=min(salaries,key=lambda k:salaries[k]) # print(res)
5.4 函式作為回傳值
閉包
https://blog.csdn.net/qq_37616069/article/details/79646905
在函式內部再定義一個函式,并且這個函式用到了外邊函式的變數,那么將這個函式以及用到的一些變數稱之為閉包
函式lazy_sum中又定義了函式sum,并且,內部函式sum可以參考外部函式lazy_sum的引數和區域變數,當lazy_sum回傳函式sum時,相關引數和變數都保存在回傳的函式中,這種稱為“閉包
#形成閉包的條件
#1、必須要有一個內嵌函式
#2、內嵌函式中要對外層函式變數的參考
#3、外部函式必須回傳內嵌函式
回傳閉包時牢記一點:回傳函式不要參考任何回圈變數,或者后續會發生變化的變數,
如果一定要參考回圈變數怎么辦?方法是再創建一個函式,用該函式的引數系結回圈變數當前的值,無論該回圈變數后續如何更改,已系結到函式引數的值不變:
def count(): def f(j): def g(): return j*j return g fs = [] for i in range(1, 4): fs.append(f(i)) # f(i)立刻被執行,因此i的當前值被傳入f() return fs
5.5 裝飾器
可以在不修改原有代碼的情況下,為被裝飾的物件增加新的功能或者附加限制條件或者幫助輸出,這種在代碼運行期間動態增加功能的方式,稱之為“裝飾器”(Decorator)
要先理解閉包,
def outer(func): # 裝飾函式 def inner(): print("認證成功!") result = func() print("日志添加成功") return result return inner @outer def f1(): # 被裝飾函式 print("業務部門1資料介面......")
a.程式開始運行,從上到下開始解釋,讀到def outer(func)時,發現這是一個函式的定義,將其函式體放入記憶體中,然后跳過,
b.跳到@outer時,程式被@這個python語法糖吸引住,知道這是個裝飾器,按規矩要立即執行,于是程式開始運行@后面那個名字outer所定義的函式,
c.程式回傳到outer函式,開始執行裝飾器的語法規則,規則是:被裝飾函式的名字會被當作函式形參傳遞給裝飾函式,裝飾函式執行它自己內部的代碼后,會將它的回傳值賦值給被裝飾函式,原來f1函式被當作引數傳遞給了func,而f1這個函式名之后會指向inner函式, 注意:@outer和outer()是有區別的,沒有括號時,outer函式會被立即執行,這個與傳統的用括號才能呼叫函式不同,
d.程式開始執行outer函式內部的內容,一開始它又碰到了一個函式inner,inner函式定義塊被程式觀察到后不會立刻執行,而是讀入記憶體中(這是默認規則),
e.再往下,碰到return inner,回傳值是個函式名,并且這個函式名會被賦值給f1這個被裝飾函式,也就是f1 = inner,此時,f1函式被新的函式inner覆寫了(實際上是f1這個函式名更改成指向inner這個函式名指向的函式體記憶體地址,f1不再指向它原來的函式體的記憶體地址),再往后呼叫f1的時候將執行inner函式內的代碼,而不是先前的函式體,那么先前的函式體去哪了?還記得我們將f1當做引數傳遞給func這個形參么?func這個變數保存了老的函式在記憶體中的地址,通過它就可以執行老的函式體,你能在inner函式里看到result = func()這句代碼,它就是這么干的!
f.接下來,還沒有結束,當業務部門,依然通過f1()的方式呼叫f1函式時,執行的就不再是舊的f1函式的代碼,而是inner函式的代碼,在本例中,它首先會列印個“認證成功”的提示,很顯然你可以換成任意的代碼,這只是個示例;然后,它會執行func函式并將回傳值賦值給變數result,這個func函式就是舊的f1函式;接著,它又列印了“日志添加成功”的提示,這也只是個示例,可以換成任何你想要的;最后回傳result這個變數,我們在業務部門的代碼上可以用r = f1()的方式接收result的值,
g.以上流程走完后,你應該看出來了,在沒有對業務部門的代碼和介面呼叫方式做任何修改的同時,也沒有對基礎平臺部原有的代碼做內部修改,僅僅是添加了一個裝飾函式,就實作了我們的需求,在函式呼叫前進行認證,呼叫后寫入日志,這就是裝飾器的最大作用,
f1._name_ 輸出inner,Python內置functools.wraps(),可以解決它們的__name__已經從原來的'f1'變成了'inner'的問題
import functools def log(text): ###now = log('execute')(now) def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator @log('execute') ###decorator本身需要傳入引數 def now(): print('2015-3-25')
#帶引數 def outer(func): def inner(*args, *kwargs): print("認證成功") result = func(*args, **kwargs) print("日志添加成功") return result return inner @outer def f1(name, age): print("{}正在呼叫業務部門1的資料介面".format(name)) # 呼叫方法 f1("jack", 19)
#有多個裝飾器 def outer1(func): def inner(*args,**kwargs): print("認證成功!") result = func(*args,**kwargs) print("日志添加成功") return result return inner def outer2(func): def inner(*args,**kwargs): print("一潭訓迎資訊,,,") result = func(*args,**kwargs) print("一潭訓送資訊,,,") return result return inner @outer1 @outer2 def f1(name,age): print("%s 正在連接業務部門1資料介面......"%name) # 呼叫方法 f1("jack",18)
###裝飾器中形參是函式 # 認證函式 def auth(request,kargs): print("認證成功!") # 日志函式 def log(request,kargs): print("日志添加成功") # 裝飾器函式,接收兩個引數,這兩個引數應該是某個函式的名字, def Filter(auth_func,log_func): # 第一層封裝,f1函式實際上被傳遞給了main_fuc這個引數 def outer(main_func): # 第二層封裝,auth和log函式的引數值被傳遞到了這里 def wrapper(request,kargs): # 下面代碼的判斷邏輯不重要,重要的是引數的參考和回傳值 before_result = auth(request,kargs) if(before_result != None): return before_result; main_result = main_func(request,kargs) if(main_result != None): return main_result; after_result = log(request,kargs) if(after_result != None): return after_result; return wrapper return outer # 注意了,這里的裝飾器函式有引數哦,它的意思是先執行filter函式,然后將filter函式的回傳值作為裝飾器函式的名字回傳到這里,所以,Filter(auth,log) = outer , @Filter(auth,log) = @outer @Filter(auth,log) def f1(name,age): print("%s 正在連接業務部門1資料介面......"%name) # 呼叫方法 f1("jack",18)
5.6 偏函式
functools.partial的作用就是,把一個函式的某些引數給固定住(也就是設定默認值),回傳一個新的函式,
>>> import functools >>> int2 = functools.partial(int, base=2) >>> int2('1000000') 64 >>> int2('1010101') 85
固定引數,回傳新的函式,
參考:菜鳥教程和廖雪峰Python3
https://www.jianshu.com/p/affeb6acf1c9
https://www.cnblogs.com/whyaza/p/9505205.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/165918.html
標籤:Python
上一篇:Java--Junit單元測驗
