1. 參數類型
1.1 位置參數
顯然對位置和順序有要求,形參和實參必須一一對應,不可或缺
def show(msg):
print(msg)
s = "I love you!"
print(s) # I love you!
def sum(a,b):
return a+b
print(sum(3,4)) # 7
1.2 默認參數
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
power(5) # 25
- 在使用缺省參數後,對於函數的必填參數必須在前,默認參數在後
- 默認參數在一個函數中可以有多個
- 當函數有多個參數時,把變化大的參數放前面,變化小的參數放後面。變
化小的參數就可以作爲默認參數 - 函數調用時,優先傳入位置參數,然後剩下的默認參數允許不按照定義順序,但是必須指明傳入的形參的標識符,比如函數
resign(name, gender, age = 6, city= 'Beijing')
,可以這樣調用:resign('yee','male',city='Nanjing',age=8)
- 默認參數慎用可變對象,因爲每次調用對默認參數值的修改都會得到保
存,而不是新創建對象。Default values are computed once, then re-used.
# # # # # # # # # # # # # #
# 默認參數爲可變對象的後果 #
# # # # # # # # # # # # # #
def func(n,l=[]):
l.append(n)
return l
print(func(1)) # [1]
print(func(2)) # [1, 2]
1.3 不定長參數
在Python 函數中,還可以定義可變參數。顧名思義,可變參數就是傳入的參數個數是可變的,可以是1 個、2 個到任意個,還可以是0 個
def sum(*num):
total = 0
for n in num:
total += n
return total
sum(1) # 1
sum(2,3,4,5,6) # 20
sum() # 0
在定義函數時,在參數名前加“*
”就表示該參數是不定長參數,加了“*
”的參數會以元組(tuple)的形式導入。
def f(*para):
print(para)
f(1,2,3,4) # (1, 2, 3, 4)
f() # ()
如果已經有一個list 或者tuple,要調用一個可變參數怎麼辦?可以這樣做:
num = [2,4,6,7,9]
sum(num[0],num[1],num[2],num[3],num[4]) # 28
# 只要傳入時實參前加上“*”
sum(*num) # 28
*num
表示把num 這個list 的所有元素作爲可變參數傳進去。這種寫法相當有用,而且很常見。
1.4 關鍵字參數
之前說過,可變參數允許你傳入0 個或任意個參數,這些可變參數在函數調用時自動組裝
爲一個tuple;而關鍵字參數允許你傳入0 個或任意個含參數名的參數,這些關鍵字
參數在函數內部自動組裝爲一個dict。
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
person('yee',26,city='Nanjing') # name: yee age: 26 other: {'city': 'Nanjing'}
person('yee',26,city='Nanjing',job='student') # name: yee age: 26 other: {'city': 'Nanjing', 'job': 'student'}
關鍵字參數有什麼用?它可以擴展函數的功能。比如,在person 函數裏,我們保證能接收到 name 和 age 這兩個參數,但是,如果調用者願意提供更多的參數,我們也能收到。試想你正在做一個用戶註冊的功能,除了用戶名和年齡是必填項外,其他都是可選項,利用關鍵字參數來定義這個函數就能滿足註冊的需求。
注意一點,傳入的key 自動變成str 了
和可變參數類似,也可以先組裝出一個dict,然後,把該dict 轉換爲關鍵字參數傳進去
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, city=extra['city'], job=extra['job']) # name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra) # name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
**extra
表示把 extra 這個 dict 的所有 key-value 用關鍵字參數傳入到函數的**kw
參數,kw 將獲得一個dict,注意kw 獲得的dict 是extra 的一份拷貝,對 kw 的改動不會影響到函數外的 extra。此處注意,如果是普通參數傳的是字典這種可變對象,則形參和實參可是共用一個對象的,函數內對形參更改的話會影響外部實參。
1.5 命名關鍵字參數
對於關鍵字參數,函數的調用者可以傳入任意不受限制的關鍵字參數。至於到底傳入了哪些,就需要在函數內部通過kw 檢查,但是調用者仍可以傳入不受限制的關鍵字參數。
如果要限制關鍵字參數的名字,就可以用命名關鍵字參數,例如,只接收city和job 作爲關鍵字參數。這種方式定義的函數如下:
def person(name, age, *, city, job):
print(name,age,city,job)
和關鍵字參數**kw 不同,命名關鍵字參數需要一個特殊分隔符*,*後面的參數被視爲命名關鍵字參數,如果不加,將被視爲位置參數。調用方式如下:
person('Jack', 24, city='Beijing', job='Engineer') # Jack 24 Beijing Engineer
如果函數定義中已經有了一個可變參數,後面跟着的命名關鍵字參數就不再需要一個特殊分隔符“*”了:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
命名關鍵字參數必須傳入參數名,如 person 函數要傳入city=xxx
,這和位置參數不同,如果沒有傳入參數名,調用將報錯。
命名關鍵字參數可以有缺省值,從而簡化調用:
def person(name, age, *, city='Beijing', job):
print(name, age, city, job)
person('Jack', 24, job='Engineer') # Jack 24 Beijing Engineer
1.6 參數組合
在Python 中定義函數,這5 種參數都可以組合使用,但是請注意,參數定義的
順序必須是:
- 位置參數
- 帶默認值位置參數
- 可變參數
- 命名關鍵字參數
- 帶默認值的命名關鍵字參數
- 關鍵字參數
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
最神奇的是,通過一個 tuple 和 dict,你也可以調用上述函數:
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw) # a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
args = (1, 2, 3)
kw = {'d': 88, 'x': '#'}
f2(*args, **kw) # a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
所以,對於任意函數,都可以通過類似func(*args, **kw)的形式調用它,無論它的參數是如何定義的。
2. 參數傳遞
一般而言,可變對象是by cite,不可變對象是by value,有一個例外是關鍵字參數,字典本來是可變對象,但是此處仍然 by value
3. 變量作用域
Python 中,程序的變量並不是在哪個位置都可以訪問的,訪問權限決定於這個變量
是在哪裏賦值的。
變量的作用域決定了在哪一部分程序可以訪問哪個特定的變量名稱。Python 的作用
域一共有4 種,分別是:
- L(Local) 局部作用域
- E(Enclosing) 嵌套作用域
- G(Global) 全局作用域
- B(Built-in) 內置作用域(內置函數所在模塊的範圍)
以L –> E –> G –>B 的規則查找,即:在局部找不到,便會去局部外的局部找(例如閉包),再找不到就會去全局找,再者去內置中找。
g_count = 0 # 全局作用域
def outer():
o_count = 1 # 作用域在outer 中
def inner():
i_count = 2 # 作用域在inner 中
Python 中只有模塊(module),類(class)以及函數(def、lambda)纔會引入新的作用域,其它的代碼塊(如if/elif/else/、try/except、for/while 等)是不會引入新的作用域的,也就是說這些語句內定義的變量,外部也可以訪問。
還有一種情況,當全局作用域和局部作用域變量名相同時:
total = 0
def sum(m, n):
total = m + n
return total
sum(10,20) # 30
print(total) # 0
- global 關鍵字
如果在局部作用域中只是使用全局變量,而不做修改,則可以直接調用,但是,如果需要對全局變量進行修改的話,必須在修改前,用global 關鍵字聲明,注意只是聲明,不能初始化,如:global arg(√)
,global arg = 1(×)
- nonlocal 關鍵字
nonlocal 關鍵字用來在函數或其他作用域中使用外層(非全局)變量。簡單說吧,這是針對嵌套作用域情況,假設作用域層次從外到內編號爲 層次 中變量使用nonlocal 關鍵字聲明變量時,這個變量與層次 中的同名變量掛鉤,與層次爲 的其他作用域中的同名變量無關。
還有種特殊情況:
a=10
def test():
a = a + 1 # 調用函數時會報錯,變量未定義
print(a)