對于變量和參數,不管是已經敲代碼多年的老鳥,還是剛剛接觸編程的小白,都會有時候清楚,有時候又有點模糊。因為,在實際應用中,它們之間分分離離,比如,敲代碼都知道,x=3中x是變量,它不是參數,但是在函數y=3x+4中,x是變量,也是參數。那么什么這兩個到底有什么區別和聯系呢?我在網上搜了一下,發現很多說法,雖然大同小異,但是似乎只有下面這一段來自[微軟網站](http://msdn.microsoft.com/zh-cn/library/9kewt1b3.aspx)的比較高度抽象,而且意義涵蓋深遠。我摘抄過來,看官讀一讀,是否理解,雖然是針對VB而言的,一樣有啟發。
> 參數和變量之間的差異 (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("qiwsir","qiwsir.github.io","python")
('qiwsir', 'qiwsir.github.io', 'python')
>>> foo("qiwsir",307,["qiwsir",2],{"name":"qiwsir","lang":"python"})
('qiwsir', 307, ['qiwsir', 2], {'lang': 'python', 'name': 'qiwsir'})
~~~
不管是什么,都一股腦地塞進了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('qiwsir',2,"python")
qiwsir
2
python
()
{}
>>> foo(1,2,3,4,5)
1
2
3
(4, 5)
{}
>>> foo(1,2,3,4,5,name="qiwsir")
1
2
3
(4, 5)
{'name': 'qiwsir'}
~~~
很good了,這樣就能夠足以應付各種各樣的參數要求了。
- 第零部分 獨上高樓,望盡天涯路
- 嘮叨一些關于Python的事情
- 為什么要開設本欄目
- 第一部分 積小流,至江海
- Python環境安裝
- 集成開發環境(IDE)
- 數的類型和四則運算
- 啰嗦的除法
- 開始真正編程
- 初識永遠強大的函數
- 玩轉字符串(1):基本概念、字符轉義、字符串連接、變量與字符串關系
- 玩轉字符串(2)
- 玩轉字符串(3)
- 眼花繚亂的運算符
- 從if開始語句的征程
- 一個免費的實驗室
- 有容乃大的list(1)
- 有容乃大的list(2)
- 有容乃大的list(3)
- 有容乃大的list(4)
- list和str比較
- 畫圈還不簡單嗎
- 再深點,更懂list
- 字典,你還記得嗎?
- 字典的操作方法
- 有點簡約的元組
- 一二三,集合了
- 集合的關系
- Python數據類型總結
- 深入變量和引用對象
- 賦值,簡單也不簡單
- 坑爹的字符編碼
- 做一個小游戲
- 不要紅頭文件(1): open, write, close
- 不要紅頭文件(2): os.stat, closed, mode, read, readlines, readline
- 第二部分 窮千里目,上一層樓
- 正規地說一句話
- print能干的事情
- 從格式化表達式到方法
- 復習if語句
- 用while來循環
- 難以想象的for
- 關于循環的小伎倆
- 讓人歡喜讓人憂的迭代
- 大話題小函數(1)
- 大話題小函數(2)
- python文檔
- 重回函數
- 變量和參數
- 總結參數的傳遞
- 傳說中的函數條規
- 關于類的基本認識
- 編寫類之一創建實例
- 編寫類之二方法
- 編寫類之三子類
- 編寫類之四再論繼承
- 命名空間
- 類的細節
- Import 模塊
- 模塊的加載
- 私有和專有
- 折騰一下目錄: os.path.<attribute>
- 第三部分 昨夜西風,亭臺誰登
- 網站的結構:網站組成、MySQL數據庫的安裝和配置、MySQL的運行
- 通過Python連接數據庫:安裝python-MySQLdb,連接MySQL
- 用Pyton操作數據庫(1):建立連接和游標,并insert and commit
- 用Python操作數據庫(2)
- 用Python操作數據庫(3)
- python開發框架:框架介紹、Tornado安裝
- Hello,第一個網頁分析:tornado網站的基本結構剖析:improt模塊、RequestHandler, HTTPServer, Application, IOLoop
- 實例分析get和post:get()通過URL得到數據和post()通過get_argument()獲取數據
- 問候世界:利用GAE建立tornado框架網站
- 使用表單和模板:tornado模板self.render和模板變量傳遞
- 模板中的語法:tornado模板中的for,if,set等語法
- 靜態文件以及一個項目框架
- 模板轉義
- 第四部分 暮然回首,燈火闌珊處
- requests庫
- 比較json/dictionary的庫
- defaultdict 模塊和 namedtuple 模塊
- 第五部分 Python備忘錄
- 基本的(字面量)值
- 運算符
- 常用的內建函數
- 擴展閱讀(來自網絡文章)
- 人生苦短,我用Python