python變數和引數

hiekay發表於2018-12-24

對於變數和引數, x=3中x是變數,它不是引數,但是在函式y=3x+4中,x是變數,也是引數。下面這一段來自微軟網站的比較高度抽象,而且意義涵蓋深遠。

引數和變數之間的差異 (Visual Basic)

多數情況下,過程必須包含有關呼叫環境的一些資訊。執行重複或共享任務的過程對每次呼叫使用不同的資訊。此資訊包含每次呼叫過程時傳遞給它的變數、常量和表示式。

若要將此資訊傳遞給過程,過程先要定義一個形參,然後呼叫程式碼將一個實參傳遞給所定義的形參。 您可以將形參當作一個停車位,而將實參當作一輛汽車。 就像一個停車位可以在不同時間停放不同的汽車一樣,呼叫程式碼在每次呼叫過程時可以將不同的實參傳遞給同一個形參。

形參表示一個值,過程希望您在呼叫它時傳遞該值。

當您定義 Function 或 Sub 過程時,需要在緊跟過程名稱的括號內指定形參列表。對於每個形參,您可以指定名稱、資料型別和傳入機制(ByVal (Visual Basic) 或 ByRef (Visual Basic))。您還可以指示某個形參是可選的。這意味著呼叫程式碼不必傳遞它的值。

每個形參的名稱均可作為過程內的區域性變數。形參名稱的使用方法與其他任何變數的使用方法相同。

實參表示在您呼叫過程時傳遞給過程形參的值。呼叫程式碼在呼叫過程時提供引數。

呼叫 Function 或 Sub 過程時,需要在緊跟過程名稱的括號內包括實參列表。每個實參均與此列表中位於相同位置的那個形參相對應。

與形參定義不同,實參沒有名稱。每個實參就是一個表示式,它包含零或多個變數、常數和文字。求值的表示式的資料型別通常應與為相應形參定義的資料型別相匹配,並且在任何情況下,該表示式值都必須可轉換為此形參型別。

這段引文,發現裡面有幾個關鍵詞:引數、變數、形參、實參。本來想弄清楚引數和變數,結果又冒出另外兩個東東,更混亂了。
在Python中,沒有這麼複雜。

看完上面讓人暈頭轉向的引文之後,再看下面的程式碼,就會豁然開朗了。

>>> def add(x):     #x是引數
...     a = 10      #a是變數
...     return a+x
... 
>>> x = 3           #x是變數,只不過在函式之外
>>> add(x)          #這裡的x是引數,但是它由前面的變數x傳遞物件3
13
>>> add(3)          #把上面的過程合併了
13

全域性變數和區域性變數

下面是一段程式碼,注意這段程式碼中有一個函式funcx(),這個函式裡面有一個變數x=9,在函式的前面也有一個變數x=2

x = 2

def funcx():
    x = 9
    print "this x is in the funcx:-->",x

funcx()
print "--------------------------"
print "this x is out of funcx:-->",x

那麼,這段程式碼輸出的結果是什麼呢?看:

this x is in the funcx:--> 9
--------------------------
this x is out of funcx:--> 2

從輸出看出,執行funcx(),輸出了funcx()裡面的變數x=9;然後執行程式碼中的最後一行,print “this x is out of funcx:–>”,x

特別要關注的是,前一個x輸出的是函式內部的變數x;後一個x輸出的是函式外面的變數x。兩個變數彼此沒有互相影響,雖然都是x。從這裡看出,兩個X各自在各自的領域內起到作用,那麼這樣的變數稱之為區域性變數

有區域性,就有對應的全部,在漢語中,全部變數,似乎有歧義,幸虧漢語豐富,於是又取了一個名詞:全域性變數

x = 2
def funcx():
    global x
    x = 9
    print "this x is in the funcx:-->",x

funcx()
print "--------------------------"
print "this x is out of funcx:-->",x

以上兩段程式碼的不同之處在於,後者在函式內多了一個global x,這句話的意思是在宣告x是全域性變數,也就是說這個x跟函式外面的那個x同一個,接下來通過x=9將x的引用物件變成了9。所以,就出現了下面的結果。

this x is in the funcx:--> 9
--------------------------
this x is out of funcx:--> 9

好似全域性變數能力很強悍,能夠統帥函式內外。但是,要注意,這個東西要慎重使用,因為往往容易帶來變數的換亂。內外有別,在程式中一定要注意的。

不確定引數的數量

在設計函式的時候,有時候我們能夠確認引數的個數,比如一個用來計算圓面積的函式,它所需要的引數就是半徑(πr^2),這個函式的引數是確定的。

然而,有很多不確定性,那麼函式的引數的個數,也當然有不確定性,函式怎麼解決這個問題呢?python用這樣的方式解決引數個數的不確定性:

def add(x,*arg):
    print x         #輸出引數x的值
    result = x
    print arg       #輸出通過*arg方式得到的值
    for i in arg:
        result +=i
    return result

print add(1,2,3,4,5,6,7,8,9)    #賦給函式的引數個數不僅僅是2個

執行此程式碼後,得到如下結果:

1                       #這是函式體內的第一個print,引數x得到的值是1
(2, 3, 4, 5, 6, 7, 8, 9) #這是函式內的第二個print,引數arg得到的是一個元組
45                      #最後的計算結果

上面這個輸出的結果表現相當不介面友好,如果不對照著原函式,根本不知道每行列印的是什麼東西。

從上面例子可以看出,如果輸入的引數過多,其它引數全部通過*arg,以元組的形式傳給了引數(變數)arg。這裡用了一個模糊的詞語:引數(變數),這樣的表述意思是,在傳入資料的前,arg在函式頭部是引數,當在函式語句中,又用到了它,就是變數。也就是在很多時候,函式中的引數和變數是不用那麼太區分較真的,只要知道物件是通過什麼渠道、那個東西傳到了什麼目標即可。

為了能夠更明顯地看出args(名稱可以不一樣,但是符號必須要有),可以用下面的一個簡單函式來演示:

>>> def foo(*args):
...     print args      #列印通過這個引數得到的物件
... 
>>> #下面演示分別傳入不同的值,通過引數*args得到的結果

>>> foo(1,2,3)
(1, 2, 3)

>>> foo("hiekay","hiekay.github.io","python")
(`hiekay`, `hiekay.github.io`, `python`)

>>> foo("hiekay",307,["hiekay",2],{"name":"hiekay","lang":"python"})
(`hiekay`, 307, [`hiekay`, 2], {`lang`: `python`, `name`: `hiekay`})

不管是什麼,都一股腦地塞進了tuple中。

除了用args這種形式的引數接收多個值之外,還可以用*kargs的形式接收數值,不過這次有點不一樣:

>>> def foo(**kargs):
...     print kargs
...
>>> foo(a=1,b=2,c=3)    #注意觀察這次賦值的方式和列印的結果
{`a`: 1, `c`: 3, `b`: 2}

如果這次還用foo(1,2,3)的方式,會有什麼結果呢?

>>> foo(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 0 arguments (3 given)

到這裡可能想了,不是不確定性嗎?我也不知道引數到底會可能用什麼樣的方式傳值呀,這好辦,把上面的都綜合起來。

>>> def foo(x,y,z,*args,**kargs):
...     print x   
...     print y
...     print z
...     print args
...     print kargs        
... 
>>> foo(`hiekay`,2,"python")
hiekay
2
python
()
{}
>>> foo(1,2,3,4,5)
1
2
3
(4, 5)
{}
>>> foo(1,2,3,4,5,name="hiekay")
1
2
3
(4, 5)
{`name`: `hiekay`}

很good了,這樣就能夠足以應付各種各樣的引數要求了。


相關文章