【python官方文件】深入理解python函式定義

橘子oly發表於2016-10-08

開始看python官方文件啦!中文的,附上地址: python官方文件_中文

一.預設引數值:

對於稍有些python基礎的同學們都會使用Python的函式定義和函式的預設值吧,畢竟跟其他語言也是大同小異的。但是你知道預設引數值是如何使用的嗎?

預設值只被賦值一次 ”。這個性質使得預設值是可變物件時會有所不同。看下面的例子:

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))
def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))
輸出:


這就引出了兩個問題:

1)什麼是可變物件?

2)為什麼會出現不同的輸出?

對於問題1,我們首先要明白的是“在python中,萬物皆物件。” 實際上,python中不存在所謂的傳值呼叫,一切傳遞的都是物件的引用,也可以認為是傳址。

Python在heap中分配的物件分成兩類:可變物件和不可變物件。所謂可變物件是指,物件的內容可變,而不可變物件是指物件內容不可變。

不可變(immutable):int、字串(string)、float、(數值型number)、元組(tuple)

可變(mutable):字典型(dictionary)、列表型(list)

由上圖可知,對於不可變物件的改變只是建立了新物件,改變了變數的物件引用。

>>>x = 1
>>>y = 1
>>>x = 1
>>> x is y  #判斷x,y是否為同一個物件
True
>>>y is z
True

由上可知,因為整數為不可變,x,y,z在記憶體中均指向一個值為1的記憶體地址,也就是說,x,y,z均指向的是同一個地址。

不可變物件帶來的好處---減少重複值對記憶體空間的使用,壞處---如果要修改這個變數繫結的值,如果記憶體中沒用存在該值的記憶體塊,那麼必須重新開闢一塊記憶體,把新地址與變數名繫結。而不是修改變數原來指向的記憶體塊的值,這回給執行效率帶來一定的降低。

不可變物件:


對於問題2,“Python函式引數對於可變物件,函式內對引數的改變會影響到原始物件;對於不可變物件,函式內對引數的改變不會影響到原始引數”。因為對預設引數,函式只會賦值一次,如果其為可變物件,那麼函式內部是指節對該物件進行操作修改,而若為為不可變物件,那麼函式內部改變的是函式內變數的指向物件。


二.函式引數型別

函式引數包括位置引數和關鍵字引數兩種,不同之處在於

1)函式呼叫時,位置引數需要靠位置來確定其對應哪個引數,位置變化會影響函式執行結果;

def a1(x,y,z):
>>>    return x,y,z
>>>print a1(1,2,3)
(1,2,3)

>>>def a2(x,y,z):
>>>    return x,z,y
>>>print a1(1,2,3)
(1,3,2)

2)函式呼叫時,關鍵字引數指定其對應的引數,位置不會影響執行結果。

>>>def x(name,Profession):
>>>    return '%s is %s' %(name,Profession)
>>>print x(name='Amy',Profession='Student')
Amy is Student

>>>print x(Profession='Student',name='Amy')
Amy is Student

三.可變引數列表

思想:通過元組或字典來實現可變長度的引數列表呼叫。實現方式為*name(元組)和**name(字典)。栗子:

def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    keys = sorted(keywords.keys())
    for kw in keys:
        print(kw, ":", keywords[kw])
cheeseshop("Limburger", "It's very runny, sir.",
           "It's really very, VERY runny, sir.",
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")

其輸出如下:

-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch
相應地,也可以輸入元組或字典通過*/**來實現分解,栗子

def parrot(voltage, state='a stiff', action='voom'):
    print("-- This parrot wouldn't", action)
    print("if you put", voltage, "volts through it.")
    print("E's", state, "!")

d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
parrot(**d)
其輸出如下:

("-- This parrot wouldn't", 'VOOM')
('if you put', 'four million', 'volts through it.')
("E's", "bleedin' demised", '!')


四.lambda表示式

簡單來說,程式設計中提到的 lambda 表示式,通常是在需要一個函式,但是又不想費神去命名一個函式的場合下使用,也就是指匿名函式

具體看這個(懶得寫了orz....)

點選開啟連結


相關文章