這篇部落格記錄廖雪峰python教程的習題(二)
函數語言程式設計
高階函式—–sorted
首先我們需要明確一點就是sorted()函式是作用於一個列表,對列表中的每一項元素進行排序,因為sorted本身的作用就是對元素排序,如果後面還有key=function ,則是先對列表中的每一項元素按照function進行作用,sorted()函式在對返回的結果(仍然是存在一個list中)在進行排序!理解了上面的邏輯我們就可以做題啦。
“假設我們用一組tuple表示學生名字和成績:
L = [(‘Bob’, 75), (‘Adam’, 92), (‘Bart’, 66), (‘Lisa’, 88)]
請用sorted()對上述列表分別按名字排序:”
程式碼如下:
#請用sorted()對上述列表分別按名字排序:
def main():
L=[('Bob',98),('xuanxuan',90),('hehe',97),['Asas',100]]
L1=sorted(L,key=sort_byname)
print(L1)
def sort_byname(t): #t這裡代表著一個元組tuple因為list中每一項不再是單純的一個元素,而是一個tuple
return t[0].lower()
#return t[0]
main()
需要注意的是這裡sort_byname()函式的作用物件是sorted()函式中的list的每一項,在這裡也就是一個tuple了,由於我們是希望對名字進行排序,sort_byname()函式只需要對一個tuple返回第一個元素值 也就是名字 ,然後sorted()函式會對返回來的值 再進行排序,自然就是按名字排序了
如果是按照分數進行排序呢:
#還是上面那個例子,請用sorted()對上述列表按分數進行排序
def main():
L=[('Bob',98),('xuanxuan',90),('hehe',97),['Asas',100]]
L1=sorted(L,key=sort_byscore)
print(L1)
def sort_byscore(t):
return t[1]
main()
返回函式
需要注意的是,如果一個函式的返回值仍然是一個函式或者函式的某種形式(比如說列表中的元素都是函式的形式等),那麼只有當這個被返回的函式被呼叫時才會返回值。
現在通過例子說明一下啊:
返回函式,只有被返回的函式被呼叫時,才會計算裡邊引數的值
def count():
fs=[]
for i in range(1,4):
def f():
return i*i
fs.append(f)
return fs
def main():
f1,f2,f3=count() #因為count()返回的是一個list 裡邊的元素都是函式,f1,f2,f3就以此對應了list列表中的三個函式,
result1=f1() #只不過這三個函式只有等到自己被呼叫時f1()時才會返回原本儲存在函式中引數的值
result2=f2()
result3=f3() #由於f()函式在定義時使用的時變化的i,因此前兩次迴圈 fs列表中對應的元素--函式儲存的並不是原來的1 和2 而是最後被更新到3
print(result1,result2,result3)
main()
需要說明一下,上面的程式碼執行之後返回的都是9 。
首先呼叫count()函式,返回的是fs,一個list 只不過這個list函式存放的元素不是普通的整數或者字元,在這裡是函式f,主函式裡f1,f2,f3=count() 後就會把三次迴圈結束的函式依次賦值給 f1,f2,f3,也就是現在他們三個仍是函式,並不是某個具體的值,而且這三個函式裡儲存著需要返回的引數i ,只有當f1() f2() f3()這樣被呼叫時,才會依次返回值。
而且返回的值都是9並不是期望的1,4,9 原因是前一次迴圈的i 被後一次給覆蓋了,所以最後返回的都是i=3 即3*3=9的值
那如果想要返回1,4,9呢,下面提供兩種方法:
#當然如果你想輸出1 4 9的話 一種方法是返回的時候直接就呼叫這個函式,當然這種方法返回的就不是具體的函數了
def count():
fs=[]
for i in range(1,4):
def f():
return i*i
fs.append(f()) #原本使用的是fs.append(f) 原來列表中存的是函式,現在列表中存放的是具體的值,因為f()就會呼叫上買你的函式,直接就會計算出來
return fs
def main():
r1,r2,r3=count()
print(r1,r2,r3)
main()
另外一種仍然採用返滬函式的程式碼實現如下:
#如果還想返回的是一個函式,而不是具體的值,然後向輸出1,4,9,怎麼辦呢,只需要在返回函式的地方,讓他不再使用變化的引數即可
def count():
fs=[]
def f(i): #定義一個函式,返回值仍然是一個函式
def g():
return i*i
return g
for i in range(1,4):
fs.append(f(i)) #這裡呼叫函式之後會儲存這個引數的值,而不是再下一次迴圈中把上一次的引數值給沖掉
return fs
def main():
f1,f2,f3=count() #count()函式返回的仍然是列表fs,裡邊的值仍然是函式,只不過函式裡儲存的引數i依次是1,2,3即下一次迴圈的值不會吧上一次迴圈的值給沖掉
print(f1(),f2(),f3()) #只有對fs列表中存放的三個函式都進行呼叫時才會返回值
main()
”利用閉包返回一個計數器函式,每次呼叫它返回遞增整數:“
我在編寫的時候把要呼叫的次數使用者輸入了,直接輸出每次呼叫的結果
程式碼如下:
#利用閉包返回一個計數器函式,每次呼叫它都會返回一個遞增的整數
def count(): #count()函式就是會返回一個計數器函式 increase()
def increase(n): #increase()函式裡面的引數是第幾次呼叫它
number=0
for i in range(n): #根據呼叫的次數返回number的值,相當於就是計數累加
number+=1
return number
return increase
def main():
n=eval(input('please input a number:')) #輸入想呼叫計數器的次數n ,也就是說明想累加幾次
for i in range(n):
f=count() #現在f就是count()函式的返回值 是一個函式 increase()
result=f(i) #increase(i) 就會返回第i次呼叫increase()函式累加的值
print(result,end=' ')
main()
上面的程式碼其實邏輯上不對,修改如下:
#利用閉包返回一個計數器函式,每次呼叫它都會返回一個遞增的整數
#20180206裡面寫的不對啊,邏輯不對
def count(n): #count(n)函式就是會返回一個計數器函式increase(n),為什麼這裡要加一個引數,裡面又重新定義了一個新的函式g呢是為了儲存當前的變數值,防止下一次賦值把原來的變數值給沖掉
def increase(i): #這裡i其實就是第幾次呼叫的意思
def g():
sum=0
for j in range(i):
sum+=1
return sum
return g
return increase(n)
def main():
n=eval(input("please input a number:"))
for i in range(n):
f=count(i)
result=f()
print(result)
main()
哎,實現一個功能得想半天,,,難過
“請用匿名函式改造一下函式:”
#請用匿名函式改造下面的程式碼:
def is_odd(x): #判斷是否為奇數
return x%2==1
def main():
print(list(filter(is_odd,range(1,20))))
main()
使用匿名函式改寫為:
list(filter(lambda x:x%2==1,range(1,20))) 即可。
匿名函式中:號前面的是函式的引數,匿名函式的返回值是後面的表示式的值
裝飾器
“請設計一個decorator,它可作用於任何函式上,並列印該函式的執行時間:”
這個程式碼是參考的這位大神
import time
import functools
def log_time(func):
@functools.wraps(func)
def wrapper(*args,**kw):
start=time.time()
res=func(*args,**kw)
end=time.time()
print("%s runned in %s seconds"%(func.__name__,(end-start)*1000))
return res
return wrapper
@log_time
def f1(x,y):
time.sleep(1)
return x+y
def main():
result=f1(1,2)
print(result)
main()
下面的程式碼是我的一點點拓展:
#this code is to creat another feature
import functools,time
def log_time(text): #給裝飾器log_time()傳入一個引數
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**kw):
start=time.time()
fun=func(*args,**kw)
end=time.time()
print("the progame %s runned in %s ms"%(func.__name__,(end-start)*1000))
return fun
return wrapper
return decorator
#log_time(text)(f1)
#先log_time(text) 返回一個decorator 函式,然後再decorator(f1) 在返回一個wrapper函式 至此就是@log_time("xuanxuan,,,") 和接下倆def f1()
@log_time("xuanxuan,you are a beautiful girl!")
def f1(x,y,z):
time.sleep(2) #作用是讓函式暫停2s在執行,就是計算函式執行的時間的
return x+y+z
def main():
result=f1(2,3,4)
print("the result and the name of this function is {} and {} ".format(result,f1.__name__))
main()
以下兩個小題的答案參考自這位大神
“請編寫一個decorator,能在函式呼叫的前後打印出’begin call’和’end call’的日誌。”
相對比較簡單,直接上程式碼:
#在函式執行的前後輸出begin call和end call:
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print("begin call %s():"%func.__name__)
res=func(*args,**kw)
print("the result of the program is {}".format(res))
print("end call %s():"%func.__name__)
#resturn res
return wrapper
@log
def f2(x,y):
return x+y
def main():
f2(4,6)
print("the name of the function is :"+f2.__name__)
main()
“再思考一下能否寫出一個@log的decorator,使它既支援:
@log
def f():
pass
又支援:
@log(‘execute’)
def f():
pass”
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**kw):
if text!=None:
print("the text is %s and the call %s(): "%(text,func.__name__))
res=func(*args,**kw)
return res
else:
print("call %s ():"%func.__name__)
res=func(*args,**kw)
return res
return wrapper
if isinstance(text,str): #首先如果有引數 就跟原來一樣直接返回decorator即可
return decorator
else: #如果沒有引數 其實log(func)就是log裡邊其實直接傳的引數就是func 返回的應該是wrapper
func=text
text=None
return decorator(func) #所以這裡的應該是直接decorator(func) 返回wrapper
@log("there is a parameter in this edition")
def f1(x,y):
return x*y
def main1():
result=f1(2,3)
print("the result is {}".format(result))
print("the name of this function(no_parameter) is "+f1.__name__)
@log
def f2(x,y):
return x+y
def main2():
result=f2(5,8)
print("the result of this function(with parameter) is {}".format(result))
print("the name of this function is "+f2.__name__)
def main():
number=eval(input("please input a number to decide which the function to run:"))
if number==1:
main1()
print("run successfully!")
else:
main2()
print("Run successfully!")
main()
偏函式
簡單的說 引入functools.partial 之後 就可以把原來函式的引數給固定住,從而建立一個新的函式,當然對於新的函式我們仍然是可以傳入新的引數值的。
import functools
def main1():
int2=functools.partial(int,base=4)
result=int2('1000000')
print(result)
def main2():
max2=functools.partial(max,100)
result=max(1,2,4,7,99)
result1=max(1,2,3,102)
print((result,result1))
#main1()
main2()