国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - 深入講解Python函數中參數的使用及默認參數的陷阱

深入講解Python函數中參數的使用及默認參數的陷阱

2020-08-16 12:10Jacman Python

這篇文章主要介紹了Python函數中參數的使用及默認參數的陷阱,文中將函數的參數分為必選參數、默認參數、可變參數和關鍵字參數來講,要的朋友可以參考下

C++里函數可以設置缺省參數,Java不可以,只能通過重載的方式來實現,python里也可以設置默認參數,最大的好處就是降低函數難度,函數的定義只有一個,并且python是動態語言,在同一名稱空間里不能有想多名稱的函數,如果出現了,那么后出現的會覆蓋前面的函數。

?
1
2
3
4
5
6
def power(x, n=2):
  s = 1
  while n > 0:
    n = n - 1
    s = s * x
  return s

看看結果:

?
1
2
3
4
>>> power(5)
25
>>> power(5,3)
125

注意: 必選參數在前,默認參數在后,否則Python的解釋器會報錯。
建議:*當函數有多個參數時,把變化大的參數放前面,變化小的參數放后面。變化小的參數就可以作為默認參數。
默認參數也有坑,看看下面的代碼,先定義一個list,添加一個end再返回:

?
1
2
3
def add_end(L=[]):
  L.append('END')
  return L

看看調用結果:

?
1
2
3
4
5
6
7
8
9
10
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

這里需要解釋一下,Python函數在定義的時候,默認參數L的值就被計算出來了,即[]。此時L指向[]。所以如果L中的內容改變了,下次調用引用的內容也就不再是[]了。所以要牢記一點定義默認參數必須指向不可變對象!。

可變參數
第一種方法,傳入的參數為一個list或者tuple。

?
1
2
3
4
5
def calc(numbers):
  sum = 0
  for n in numbers:
    sum = sum + n * n
  return sum

調用方式:

?
1
2
3
4
>>> calc([1, 2, 3])
14
>>> calc((1, 3, 5, 7))
84

第二種方式,直接傳入多個參數,函數內部會自動用一個tuple接收。

?
1
2
3
4
5
def calc(*numbers):
  sum = 0
  for n in numbers:
    sum = sum + n * n
  return sum

調用方式:

?
1
2
3
4
>>> calc(1, 2)
5
>>> calc()
0

這個時候如果還想把一個list或者tuple里的數據傳進去,可以這樣:

?
1
2
3
>>> nums = [1, 2, 3]
>>> calc(*nums)
14

關鍵字參數
關鍵字參數允許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝為一個dict。

?
1
2
def person(name, age, **kw):
  print 'name:', name, 'age:', age, 'other:', kw

調用示例:

?
1
2
3
4
5
6
>>> person('Michael', 30)
name: Michael age: 30 other: {}
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

參數組合
在Python中定義函數,可以用必選參數、默認參數、可變參數和關鍵字參數,這4種參數都可以一起使用,或者只用其中某些,但是請注意,參數定義的順序必須是:必選參數、默認參數、可變參數和關鍵字參數。
遞歸函數
基本的也沒什么可講的,和Java/C++里一樣,就是調用本身的一種。這里重點介紹一下尾遞歸優化。事實上尾遞歸和循環效果是一樣的,很顯然的一個優點那就是可以防止遞歸調用棧溢出。
定義:在函數返回的時候調用自身,并且,return語句不能包含表達式。編譯器或者解釋器可以對其做優化,無論調用多少次,只占用一個棧幀,不會出現溢出的情況。
舉個簡單的例子,以階乘函數為例:

?
1
2
3
4
def fact(n):
  if n==1:
    return 1
  return n * fact(n - 1)

如果傳入的n很大,就可能會溢出,這是由于return n * fact(n - 1)引入了乘法表達式,就不是尾遞歸了。把代碼改一下:

?
1
2
3
4
5
6
7
def fact(n):
  return fact_iter(n, 1)
 
def fact_iter(num, product):
  if num == 1:
    return product
  return fact_iter(num - 1, num * product)

默認參數陷阱
Python的函數定義提供了默認參數這個選擇,使得函數的定義和使用更加的靈活,但是也會帶來一些坑,例如之前的一個例子:
函數定義:

?
1
2
3
def add_end(L=[]):
  L.append('END')
  return L

調用函數的結果:

?
1
2
3
4
5
6
7
8
9
10
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

很明顯這個與函數的定義初衷不符,用一句話解釋就是:
Default values are computed once, then re-used.
為了深入研究這個問題,我們來看看另一個例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# coding=utf-8
 
def a():
  print "a executed"
  return []
 
def b(x=a()):
  print "id(x):", id(x)
  x.append(5)
  print "x:", x
 
for i in range(2):
  print "不帶參數調用,使用默認參數"
  b()
  print b.__defaults__
  print "id(b.__defaults__[0]):", id(b.__defaults__[0])
 
for i in range(2):
  print "帶參數調用,傳入一個list"
  b(list())
  print b.__defaults__
  print "id(b.__defaults__[0]):", id(b.__defaults__[0])

NOTE:稍微解釋一下,所有默認值都存儲在函數對象的__defaults__屬性中,這是一個列表,每一個元素均為一個默認參數值。
來看看輸出結果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a executed
不帶參數調用,使用默認參數
id(x): 140038854650552
x: [5]
([5],)
id(b.__defaults__[0]): 140038854650552
不帶參數調用,使用默認參數
id(x): 140038854650552
x: [5, 5]
([5, 5],)
id(b.__defaults__[0]): 140038854650552
帶參數調用,傳入一個list
id(x): 140038854732400
x: [5]
([5, 5],)
id(b.__defaults__[0]): 140038854650552
帶參數調用,傳入一個list
id(x): 140038854732472
x: [5]
([5, 5],)
id(b.__defaults__[0]): 140038854650552

簡單分析一下輸出結果:
第1行
在定義函數b(),即執行def語句,代碼第7行def b(x=a()):的時候,這句話使用了默認參數,所以在定義的時候會計算默認參數x的值,這個時候會調用a(),所以打印出了a executed。
第2~6行
第一次執行循環,代碼第14行調用b()沒有傳遞參數,使用默認參數,此時x=[],所以調用一次之后

?
1
print b.__defaults__

輸出結果為

 

復制代碼 代碼如下:
([5],)

第7~11行
第二次循環,代碼第14行調用b()沒有傳遞參數,使用默認參數。
注意:默認參數只會計算一次,也就是說那個內存區域就固定了,但是這個地址所指向的是一個list,內容可以改變,此時由于上一次調用x: [5],所以

 

?
1
print b.__defaults__

輸出結果為

?
1
([5, 5],)

第12~16行
第二個循環語句,第一次循環,代碼第20行傳入一個空的list,所以不使用默認參數,此時x=[],所以

?
1
print b.__defaults__

輸出結果為

 

復制代碼 代碼如下:
([5],)

第18~21行
第二個循環語句,第二次循環,代碼第20行傳入一個空的list,所以也不使用默認參數,此時仍然是x=[],所以

 

?
1
print b.__defaults__

輸出結果依然為

 

復制代碼 代碼如下:
([5],)

函數也是對象,因此定義的時候就被執行,默認參數是函數的屬性,它的值可能會隨著函數被調用而改變。其他對象不都是如此嗎?
牢記: 默認參數必須指向不變對象!代碼改一下如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# coding=utf-8
 
def a():
  print "a executed"
  return None
 
def b(x=a()):
  print "id(x):", id(x)
  if x is None:
    x = []
  x.append(5)
  print "x:", x
 
for i in range(2):
  print "不帶參數調用,使用默認參數"
  b()
  print b.__defaults__
  print "id(b.__defaults__[0]):", id(b.__defaults__[0])
 
for i in range(2):
  print "帶參數調用,傳入一個list"
  b(list())
  print b.__defaults__
  print "id(b.__defaults__[0]):", id(b.__defaults__[0])

此時的輸出結果看看是什么:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a executed
不帶參數調用,使用默認參數
id(x): 9568656
x: [5]
(None,)
id(b.__defaults__[0]): 9568656
不帶參數調用,使用默認參數
id(x): 9568656
x: [5]
(None,)
id(b.__defaults__[0]): 9568656
帶參數調用,傳入一個list
id(x): 140725126699632
x: [5]
(None,)
id(b.__defaults__[0]): 9568656
帶參數調用,傳入一個list
id(x): 140725126699704
x: [5]
(None,)
id(b.__defaults__[0]): 9568656

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 日韩欧美在 | 一级大片免费观看 | 久久久精品日本 | 黄色影院| 亚洲欧美在线视频 | 91av入口 | www.欧美.com| 国产一级片播放 | 一区视频在线 | 精品国产一区二区三区日日嗨 | 看日韩毛片 | 欧美亚洲第一页 | 美女一区二区三区 | 亚洲一区二区 | 亚洲网站在线观看 | 欧美日韩第一区 | 三a视频| 久久久久久久久久久网站 | 久久精品中文字幕 | 日本特黄特色aaa大片免费 | 国产中文字幕在线观看 | 狠狠干天天爱 | 一区二区在线不卡 | 久久久久久毛片免费看 | 国内精品一级毛片国产99 | 久久久成人免费 | 久久久久亚洲精品 | 一区二区三区在线看 | 激情久久婷婷 | 亚洲精品99 | 国产精品久久久久久久一区探花 | 91精品久久久久久久久久 | 日韩精品在线一区 | 日韩第一区 | 午夜精品美女久久久久av福利 | 精品综合在线 | www午夜 | 草草在线观看 | 99爱在线观看 | 中文字幕第二十六页页 | 日韩成人在线播放 |