今天是2014年8月4日,這段時間災禍接連發生,顯示不久前昆山的工廠爆炸,死傷不少,然后是云南地震,也有死傷。為所有在災難中受傷害的人們獻上禱告。
在[《永遠強大的函數》](https://github.com/qiwsir/ITArticles/blob/master/BasicPython/106.md)那一講中,老齊我([http://qiwsir.github.io)已經向看官們簡述了一下變量,之后我們就一直在使用變量,每次使用變量,都要有一個操作,就是賦值。本講再次提及這個兩個事情,就是要讓看官對變量和賦值有一個知其然和知其所以然的認識。當然,最后能不能達到此目的,主要看我是不是說的通俗易懂了。如果您沒有明白,就說明我說的還不夠好,可以聯系我,我再為您效勞。](http://qiwsir.github.io%EF%BC%89%E5%B7%B2%E7%BB%8F%E5%90%91%E7%9C%8B%E5%AE%98%E4%BB%AC%E7%AE%80%E8%BF%B0%E4%BA%86%E4%B8%80%E4%B8%8B%E5%8F%98%E9%87%8F%EF%BC%8C%E4%B9%8B%E5%90%8E%E6%88%91%E4%BB%AC%E5%B0%B1%E4%B8%80%E7%9B%B4%E5%9C%A8%E4%BD%BF%E7%94%A8%E5%8F%98%E9%87%8F%EF%BC%8C%E6%AF%8F%E6%AC%A1%E4%BD%BF%E7%94%A8%E5%8F%98%E9%87%8F%EF%BC%8C%E9%83%BD%E8%A6%81%E6%9C%89%E4%B8%80%E4%B8%AA%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%B0%B1%E6%98%AF%E8%B5%8B%E5%80%BC%E3%80%82%E6%9C%AC%E8%AE%B2%E5%86%8D%E6%AC%A1%E6%8F%90%E5%8F%8A%E8%BF%99%E4%B8%AA%E4%B8%A4%E4%B8%AA%E4%BA%8B%E6%83%85%EF%BC%8C%E5%B0%B1%E6%98%AF%E8%A6%81%E8%AE%A9%E7%9C%8B%E5%AE%98%E5%AF%B9%E5%8F%98%E9%87%8F%E5%92%8C%E8%B5%8B%E5%80%BC%E6%9C%89%E4%B8%80%E4%B8%AA%E7%9F%A5%E5%85%B6%E7%84%B6%E5%92%8C%E7%9F%A5%E5%85%B6%E6%89%80%E4%BB%A5%E7%84%B6%E7%9A%84%E8%AE%A4%E8%AF%86%E3%80%82%E5%BD%93%E7%84%B6%EF%BC%8C%E6%9C%80%E5%90%8E%E8%83%BD%E4%B8%8D%E8%83%BD%E8%BE%BE%E5%88%B0%E6%AD%A4%E7%9B%AE%E7%9A%84%EF%BC%8C%E4%B8%BB%E8%A6%81%E7%9C%8B%E6%88%91%E6%98%AF%E4%B8%8D%E6%98%AF%E8%AF%B4%E7%9A%84%E9%80%9A%E4%BF%97%E6%98%93%E6%87%82%E4%BA%86%E3%80%82%E5%A6%82%E6%9E%9C%E6%82%A8%E6%B2%A1%E6%9C%89%E6%98%8E%E7%99%BD%EF%BC%8C%E5%B0%B1%E8%AF%B4%E6%98%8E%E6%88%91%E8%AF%B4%E7%9A%84%E8%BF%98%E4%B8%8D%E5%A4%9F%E5%A5%BD%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%81%94%E7%B3%BB%E6%88%91%EF%BC%8C%E6%88%91%E5%86%8D%E4%B8%BA%E6%82%A8%E6%95%88%E5%8A%B3%E3%80%82/)
## 變量和對象
在[《learning python》](http://shop.oreilly.com/product/0636920028154.do)那本書里面,作者對變量、對象和引用的關系闡述的非常明了。我這里在很大程度上是受他的啟發。感謝作者Mark Lutz先生的巨著。
應用《learning python》中的一個觀點:**變量無類型,對象有類型**
在python中,如果要使用一個變量,不需要提前聲明,只需要在用的時候,給這個變量賦值即可。這里特別強調,只要用一個變量,就要給這個變量賦值。
所以,像這樣是不行的。
~~~
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
~~~
反復提醒:一定要注意看報錯信息。如果光光地寫一個變量,而沒有賦值,那么python認為這個變量沒有定義。賦值,不僅僅是給一個非空的值,也可以給一個空值,如下,都是允許的
~~~
>>> x = 3
>>> lst = []
>>> word = ""
>>> my_dict = {}
~~~
在前面講述中,我提出了一個類比,就是變量通過一根線,連著對象(具體就可能是一個int/list等),這個類比被很多人接受了,算是我老齊的首創呀。那么,如果要用一種嚴格的語言來描述,變量可以理解為一個系統表的元素,它擁有過指向對象的命名空間。太嚴肅了,不好理解,就理解我那個類比吧。變量就是存在系統中的一個東西,這個東西有一種能力,能夠用一根線與某對象連接,它能夠釣魚。
對象呢?展開想象。在機器的內存中,系統分配一個空間,這里面就放著所謂的對象,有時候放數字,有時候放字符串。如果放數字,就是int類型,如果放字符串,就是str類型。
接下來的事情,就是前面說的變量用自己所擁有的能力,把對象和自己連接起來(指針連接對象空間),這就是引用。引用完成,就實現了賦值。
[](https://github.com/qiwsir/ITArticles/blob/master/Pictures/12601.png)
看到上面的圖了吧,從圖中就比較鮮明的表示了變量和對象的關系。所以,嚴格地將,只有放在內存空間中的對象(也就是數據)才有類型,而變量是沒有類型的。這么說如果還沒有徹底明白,就再打一個比喻:變量就好比釣魚的人,湖水里就好像內存,里面有好多魚,有各種各樣的魚,它們就是對象。釣魚的人(變量)的任務就是用某種方式(魚兒引誘)把自己和魚通過魚線連接起來。那么,魚是有類型的,有鰱魚、鯽魚、帶魚(帶魚也跑到湖水了了,難道是淡水帶魚?呵呵,就這么扯淡吧,別較真),釣魚的人(變量)沒有這種類型,他釣到不同類型的魚。
這個比喻太爛了。湊合著理解吧。看官有好的比喻,別忘記分享。
同一個變量可以同時指向兩個對象嗎?絕對不能腳踩兩只船。如果這樣呢?
~~~
>>> x = 4
>>> x = 5
>>> x
5
~~~
變量x先指向了對象4,然后指向對象5,當后者放生的時候,自動跟第一個對象4接觸關系。再看x,引用的對象就是5了。那么4呢?一旦沒有變量引用它了,它就變成了孤魂野鬼。python是很吝嗇的,它絕對不允許在內存中存在孤魂野鬼。凡是這些東西都被看做垃圾,而對垃圾,python有一個自動的收回機制。
在網上找了一個圖示說明,很好,引用過來(來源:[http://www.linuxidc.com/Linux/2012-09/69523.htm)](http://www.linuxidc.com/Linux/2012-09/69523.htm%EF%BC%89)
~~~
>>> a = 100 #完成了變量a對內存空間中的對象100的引用
~~~
如下圖所示:
[](https://github.com/qiwsir/ITArticles/blob/master/Pictures/12602.png)
然后,又操作了:
~~~
>>> a = "hello"
~~~
如下圖所示:
[](https://github.com/qiwsir/ITArticles/blob/master/Pictures/12603.png)
原來內存中的那個100就做為垃圾被收集了。而且,這個收集過程是python自動完成的,不用我們操心。
那么,python是怎么進行垃圾收集的呢?在[Quora](http://www.quora.com/)上也有人問這個問題,我看那個回答很精彩,做個鏈接,有性趣的讀一讀吧。[Python (programming language): How does garbage collection in Python work?](http://www.quora.com/Python-programming-language-1/How-does-garbage-collection-in-Python-work)
## is和==的效果
以上過程的原理搞清楚了,下面就可以深入一步了。
~~~
>>> l1 = [1,2,3]
>>> l2 = l1
~~~
這個操作中,l1和l2兩個變量,引用的是一個對象,都是[1,2,3]。何以見得?如果通過l1來修改[1,2,3],l2引用對象也修改了,那么就證實這個觀點了。
~~~
>>> l1[0] = 99 #把對象變為[99,2,3]
>>> l1 #變了
[99, 2, 3]
>>> l2 #真的變了吔
[99, 2, 3]
~~~
再換一個方式:
~~~
>>> l1 = [1,2,3]
>>> l2 = [1,2,3]
>>> l1[0] = 99
>>> l1
[99, 2, 3]
>>> l2
[1, 2, 3]
~~~
l1和l2貌似指向了同樣的一個對象[1,2,3],其實,在內存中,這是兩塊東西,互不相關。只是在內容上一樣。就好像是水里長的一樣的兩條魚,兩個人都釣到了,當不是同一條。所以,當通過l1修改引用對象的后,l2沒有變化。
進一步還能這么檢驗:
~~~
>>> l1
[1, 2, 3]
>>> l2
[1, 2, 3]
>>> l1 == l2 #兩個相等,是指內容一樣
True
>>> l1 is l2 #is 是比較兩個引用對象在內存中的地址是不是一樣
False #前面的檢驗已經說明,這是兩個東東
>>> l3 = l1 #順便看看如果這樣,l3和l1應用同一個對象
>>> l3
[1, 2, 3]
>>> l3 == l1
True
>>> l3 is l1 #is的結果是True
True
~~~
某些對象,有copy函數,通過這個函數得到的對象,是一個新的還是引用到同一個對象呢?看官也可以做一下類似上面的實驗,就曉得了。比如:
~~~
>>> l1
[1, 2, 3]
>>> l2 = l1[:]
>>> l2
[1, 2, 3]
>>> l1[0] = 22
>>> l1
[22, 2, 3]
>>> l2
[1, 2, 3]
>>> adict = {"name":"qiwsir","web":"qiwsir.github.io"}
>>> bdict = adict.copy()
>>> bdict
{'web': 'qiwsir.github.io', 'name': 'qiwsir'}
>>> adict["email"] = "qiwsir@gmail.com"
>>> adict
{'web': 'qiwsir.github.io', 'name': 'qiwsir', 'email': 'qiwsir@gmail.com'}
>>> bdict
{'web': 'qiwsir.github.io', 'name': 'qiwsir'}
~~~
不過,看官還有小心有點,python不總按照前面說的方式出牌,比如小數字的時候
~~~
>>> x = 2
>>> y = 2
>>> x is y
True
>>> x = 200000
>>> y = 200000
>>> x is y #什么道理呀,小數字的時候,就用緩存中的.
False
>>> x = 'hello'
>>> y = 'hello'
>>> x is y
True
>>> x = "what is you name?"
>>> y = "what is you name?"
>>> x is y #不光小的數字,短的字符串也是
False
~~~
賦值是不是簡單地就是等號呢?從上面得出來,=的作用就是讓變量指針指向某個對象。不過,還可以再深入一些。走著瞧吧。
- 第零部分 獨上高樓,望盡天涯路
- 嘮叨一些關于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