天天看點

python基礎3

1.函數基本文法及特性

函數是什麼?

函數一詞來源于數學,但程式設計中的「函數」概念,與數學中的函數是有很大不同的,具體差別,我們後面會講,程式設計中的函數在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子過程或子程式),在Pascal中叫做procedure(過程)和function,在C中隻有function,在Java裡面叫做method。

定義: 函數是指将一組語句的集合通過一個名字(函數名)封裝起來,要想執行這個函數,隻需調用其函數名即可

特性:

  1. 減少重複代碼
  2. 使程式變的可擴充
  3. 使程式變得易維護

定義:

1 def Hello():#函數名
2     print('Hello World!')
3 Hello()#調用函數      

可以帶參數:

1 def calc(x,y):
2     z = x*y
3     return z
4 c = calc(3,4)
5 print(c)#結果12      

2.函數參數與局部變量 

形參變量隻有在被調用時才配置設定記憶體單元,在調用結束時,即刻釋放所配置設定的記憶體單元。是以,形參隻在函數内部有效。函數調用結束傳回主調用函數後則不能再使用該形參變量

實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有确定的值,以便把這些值傳送給形參。是以應預先用指派,輸入等辦法使參數獲得确定值

還是上面的代碼:

1 def calc(x,y): #(x,y)為形參
2     z = x*y
3     return z
4 c = calc(a,b)   #(a.b)為實參
5 print(c)      

預設參數

1 def stu_register(name, age, country, course):
 2     print("----注冊學生資訊------")
 3     print("姓名:", name)
 4     print("age:", age)
 5     print("國籍:", country)
 6     print("課程:", course)
 7 
 8 
 9 stu_register("小麗", 22, "CN", "python_devops")
10 stu_register("小明", 21, "CN", "linux")
11 stu_register("小王", 25, "CN", "linux")      

發現 country 這個參數 基本都 是"CN", 就像我們在網站上注冊使用者,像國籍這種資訊,你不填寫,預設就會是 中國, 這就是通過預設參數實作的,把country變成預設參數非常簡單

是以,我們可以通過下面代碼簡化代碼:

def stu_register(name, age, course,country="CN"):      

這樣,這個參數在調用時不指定,那預設就是CN,預設你選的值,預設參數!

注意:跟上一段代碼比較,為什麼預設參數放到後面呢?

簡單來講就是會産生歧義。
不妨想一想,如果确實如你所說,有預設值的參數位于無預設值之前,則調用函數時就必須使用key=Value的形式,而不能使用直接送入Value的形式了。
為了調用函數時可以更便捷地使用後者,而同時又不産生歧義,在定義函數時,無預設值參數就必須位于前面了。考慮到定義函數隻要一次,調用函數可能是很多地方、很多人使用,定義函數時稍微注意點是可以了解的了。      

關鍵參數

正常情況下,給函數傳參數要按順序,不想按順序就可以用關鍵參數,隻需指定參數名即可,但記住一個要求就是,關鍵參數必須放在位置參數之後。

關鍵字參數:

1 def tes(x=1,y=2):
2     print(x)
3     print(y)
4 tes()      

位置參數:

1 def tet1(x,y):
2     print(x)
3     print(y)
4 tet1(1,2)      

非固定參數:

若你的函數在定義時不确定使用者想傳入多少個參數,就可以使用非固定參數

#*args參數組,将位置參數(一一對應的位置)放到元組
def tes(*args):
    print(args)
tes(1,2,34,5,6)
#結果:(1, 2, 34, 5, 6)      

還可以有一個**kwargs

1 def tes(**kwargs):
2     print(kwargs)
3 tes(name='young',age='23',sex='1')      

将上述幾個參數組合:

1 def tes(name,age=23,*args,**kwargs):
 2     print(name)
 3     print(age)
 4     print(args)
 5     print(kwargs)
 6 tes('young',3,5,6,sex='man',job='IT')
 7 '''
 8 結果:
 9 young
10 3
11 (5, 6)
12 {'sex': 'man', 'job': 'IT'}
13 '''      

局部變量:

1 name = "哈哈"
2 
3 def change_name(name):
4     print("before:", name)
5     name = "Young"
6     print("after", name)
7 
8 change_name(name)
9 print("真的改了嗎?", name)      

輸出:

before: 哈哈
after Young
真的改了嗎? 哈哈      

可以通過global來實作

1 name = "哈哈"
 2 
 3 def change_name(obj):
 4     global name
 5     print("before:", name)
 6     name = "Young"
 7     print("after", name)
 8 
 9 change_name(name)
10 print("确實改了!", name)      
before: 哈哈
after Young
确實改了! Young      

全局與局部變量

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

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

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

在定義局部變量的子程式内,局部變量起作用;在其它地方全局變量起作用

3.傳回值

要想擷取函數的執行結果,就可以用return語句把結果傳回

注意:

  1. 函數在執行過程中隻要遇到return語句,就會停止執行并傳回結果,so 也可以了解為 return 語句代表着函數的結束
  2. 如果未在函數中指定return,那這個函數的傳回值為None

嵌套函數:

python允許在定義函數的時候,其函數體内又包含另外一個函數的完整定義,這就是我們通常所說的嵌套定義。為什麼?因為函數是用def語句定義的,凡是其他語句可以出現的地方,def語句同樣可以出現。

像這樣定義在其他函數内的函數叫做内部函數,内部函數所在的函數叫做外部函數。當然,我們可以多層嵌套,這樣的話,除了最外層和最内層的函數之外,其它函數既是外部函數又是内部函數。

1 spam = 99
2 def tester():
3     def nested():
4         global spam
5         print('current=',spam)
6         spam += 1
7     return nested
8 #注意:列印 print 那行的代碼調用是tester()()
9 #而不是tester().nested()      

4.遞歸

在函數内部,可以調用其他函數。如果一個函數在内部調用自身本身,這個函數就是遞歸函數。

1 def calc(n):
2     print(n)
3     if int(n/2)>0:
4         return calc(int(n/2))
5     print("->",n)
6 calc(10)      
1 10
2 5
3 2
4 1
5 -> 1      

遞歸特性:

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

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

3. 遞歸效率不高,遞歸層次過多會導緻棧溢出(在計算機中,函數調用是通過棧(stack)這種資料結構實作的,每當進入一個函數調用,棧就會加一層棧幀,每當函數傳回,棧就會減一層棧幀。由于棧的大小不是無限的,是以,遞歸調用的次數過多,會導緻棧溢出)

堆棧相關知識:http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html 

遞歸執行個體, 二分查找:

python基礎3
python基礎3
1 data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
 2  
 3  
 4 def binary_search(dataset,find_num):
 5     print(dataset)
 6  
 7     if len(dataset) >1:
 8         mid = int(len(dataset)/2)
 9         if dataset[mid] == find_num:  #find it
10             print("找到數字",dataset[mid])
11         elif dataset[mid] > find_num :# 找的數在mid左面
12             print("\033[31;1m找的數在mid[%s]左面\033[0m" % dataset[mid])
13             return binary_search(dataset[0:mid], find_num)
14         else:# 找的數在mid右面
15             print("\033[32;1m找的數在mid[%s]右面\033[0m" % dataset[mid])
16             return binary_search(dataset[mid+1:],find_num)
17     else:
18         if dataset[0] == find_num:  #find it
19             print("找到數字啦",dataset[0])
20         else:
21             print("沒的分了,要找的數字[%s]不在清單裡" % find_num)
22  
23  
24 binary_search(data,66)      

View Code

5.匿名函數

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

1 def calc(n):
2     return n ** n
3 print(calc(3))
4 # 換成匿名函數
5 calc = lambda n: n ** n
6 print(calc(3))      

匿名函數主要是和其它函數搭配使用的:

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

1 4 9 16 25

6.函數式程式設計介紹

函數是Python内建支援的一種封裝,我們通過把大段代碼拆成函數,通過一層一層的函數調用,就可以把複雜任務分解成簡單的任務,這種分解可以稱之為面向過程的程式設計。函數就是面向過程的程式設計的基本單元。

函數式程式設計中的函數這個術語不是指計算機中的函數(實際上是Subroutine),而是指數學中的函數,即自變量的映射。也就是說一個函數的值僅決定于函數參數的值,不依賴其他狀态。比如sqrt(x)函數計算x的平方根,隻要x不變,不論什麼時候調用,調用幾次,值都是不變的。

Python對函數式程式設計提供部分支援。由于Python允許使用變量,是以,Python不是純函數式程式設計語言。

一、定義

簡單說,"函數式程式設計"是一種

"程式設計範式"

(programming paradigm),也就是如何編寫程式的方法論。

主要思想是把運算過程盡量寫成一系列嵌套的函數調用。舉例來說,現在有這樣一個數學表達式:

 (1 + 2) * 3 - 4      

傳統的過程式程式設計,可能這樣寫:

 var a = 1 + 2;

 var b = a * 3;

 var c = b - 4;      

函數式程式設計要求使用函數,我們可以把運算過程定義為不同的函數,然後寫成下面這樣:

  var result = subtract(multiply(add(1,2), 3), 4);      

這段代碼再演進以下,可以變成這樣

add(1,2).multiply(3).subtract(4)      

這基本就是自然語言的表達了。再看下面的代碼,大家應該一眼就能明白它的意思吧:

merge([1,2],[3,4]).sort().search("2")      

是以,函數式程式設計的代碼更容易了解。

7.高階函數

變量可以指向函數,函數的參數能接收變量,那麼一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數。

def add(a,b,f):
    return f(a)+f(b)
res = add(2,-3,abs)
print(res)      

8.内置參數

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

幾個内置方法用法提醒:

python基礎3
python基礎3
#compile
f = open("函數遞歸.py")
data =compile(f.read(),'','exec')
exec(data)


#print
msg = "又回到最初的起點"
f = open("tofile","w")
print(msg,"記憶中你青澀的臉",sep="|",end="",file=f)


# #slice
# a = range(20)
# pattern = slice(3,8,2)
# for i in a[pattern]: #等于a[3:8:2]
#     print(i)
#
#


#memoryview
#usage:
#>>> memoryview(b'abcd')
#<memory at 0x104069648>
#在進行切片并指派資料時,不需要重新copy原清單資料,可以直接映射原資料記憶體,
import time
for n in (100000, 200000, 300000, 400000):
    data = b'x'*n
    start = time.time()
    b = data
    while b:
        b = b[1:]
    print('bytes', n, time.time()-start)

for n in (100000, 200000, 300000, 400000):
    data = b'x'*n
    start = time.time()
    b = memoryview(data)
    while b:
        b = b[1:]
    print('memoryview', n, time.time()-start)