青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Welcome to 陳俊峰's ---BeetleHeaded Man Blog !

  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
  58 隨筆 :: 32 文章 :: 18 評論 :: 0 Trackbacks

python的對象與名字綁定(轉貼,此文甚好)

i = 1

? 這是一個再簡單不過的賦值語句,即便是才開始學習編程的新手也能脫口而出它的含義 -- “設置變量i的值為1”。

i = 2

? “將變量i的值改為2”,當看到接下來這行代碼時,你腦海中肯定會立即浮現這樣的念頭。

? 這難道會有問題嘛?這簡簡單單的一行賦值語句其實包含了python中的三個重要概念:名字、綁定和對象。
python對賦值語句作出了自己的定義:
? “符值語句是用來將名字綁定(或重新綁定)到某個對象的操作,而且它也可用來修改可變對象的屬性或
對象中所包含的成員。”

? 名字綁定到對象這個概念在python中隨處可見,可以說是python的最基本而且最重要的概念之一。如果
沒有很好理解這一點,一些意想不到的結果就會在您的代碼中悄然出現。

? 先來看一個簡單例子:

>>> a = {'g':1}
>>> b = a*4
>>> print b
[{'g': 1}, {'g': 1}, {'g': 1}, {'g': 1}]
>>> b[0]['g'] = 2
>>> print b

? 出乎意料嘛?請慢慢看完這篇文章。

1. 對象
? “萬物皆對象”(Everything is object),這是python這種面向對象語言所倡導的理念。在我們熟悉的C++中,1只是一個整型數,而不是一個對象。但在python中,1卻是一個實實在在的對象,您可以用dir(1)來顯示它的屬性。

? 在python中,所有對象都有下面三個特征:
?* 唯一的標識碼(identity)
?* 類型
?* 內容(或稱為值)

? 一旦對象被創建,它的標識碼就不允許更改。對象的標識碼可以有內建函數id()獲取,它是一個整型數。您可以將它想象為該對象在內存中的地址,其實在目前的實現中標識碼也就是該對象的內存地址。

>>> class c1:
?pass
...
>>> obj = c1()
>>> obj
<__main__.c1 instance at 0x00AC0738>
>>> id(obj)
11274040

? 換算一下,11274040就是十六進制的0x00AC0738。

>>> id(1)
7957136

? 這就是前面提到的1這個對象的標識碼,也就是它在內存中的地址。

? 當用is操作符比較兩個對象時,就是在比較它們的標識碼。更確切地說,is操作符是在判斷兩個對象是否是同一個對象。
>>> [1] is [1]
? 其結果是False,是因為這是兩個不同的對象,存儲在內存中的不同地方。

>>> [1] == [1]
? 其結果是True,是因為這兩個不同的對象有著相同的值。

? 與對象的標識碼類似,對象的類型也是不可更改的。可以用內建函數type()取得對象的類型。

? 有的對象的值是可以改變的,這類對象叫作可變對象;而另外一些對象在創建后其值是不可改變的(如1這個對象),這類對象叫作恒定對象。對象的可變性是由它的類型決定的,比如數值型(number)、字符串型(string)以及序列型(tuple)的對象是恒定對象;而字典型(dictionary)和列表型(list)的對象是可變對象。

? 除了上面提到的三個特征外,一個對象可能:
?* 沒有或者擁有多個方法
?* 沒有或者有多個名字

2. 名字
? 名字是對一個對象的稱呼,一個對象可以只有一個名字,也可以沒有名字或取多個名字。但對象自己卻不知道有多少名字,叫什么,只有名字本身知道它所指向的是個什么對象。給對象取一個名字的操作叫作命名,python將賦值語句認為是一個命名操作(或者稱為名字綁定)。

? 名字在一定的名字空間內有效,而且唯一,不可能在同一個名字空間內有兩個或更多的對象取同一名字。

? 讓我們再來看看本篇的第一個例子:i = 1。在python中,它有如下兩個含義:
?* 創建一個值為1的整型對象
?* "i"是指向該整型對象的名字(而且它是一個引用)
?
3. 綁定
? 如上所講的,綁定就是將一個對象與一個名字聯系起來。更確切地講,就是增加該對象的引用計數。眾所周知,C++中一大問題就是內存泄漏 -- 即動態分配的內存沒有能夠回收,而解決這一問題的利器之一就是引用計數。python就采用了這一技術實現其垃圾回收機制。
?
? python中的所有對象都有引用計數。

i=i+1

* 這創建了一個新的對象,其值為i+1。
* "i"這個名字指向了該新建的對象,該對象的引用計數加一,而"i"以前所指向的老對象的
? 引用計數減一。
* "i"所指向的老對象的值并沒有改變。
* 這就是為什么在python中沒有++、--這樣的單目運算符的一個原因。

3.1 引用計數
? 對象的引用計數在下列情況下會增加:
?* 賦值操作
?* 在一個容器(列表,序列,字典等等)中包含該對象

? 對象的引用計數在下列情況下會減少:
?* 離開了當前的名字空間(該名字空間中的本地名字都會被銷毀)
?* 對象的一個名字被綁定到另外一個對象
?* 對象從包含它的容器中移除
?* 名字被顯示地用del銷毀(如:del i)

? 當對象的引用計數降到0后,該對象就會被銷毀,其所占的內存也就得以回收。

4. 名字綁定所帶來的一些奇特現象

例4.1:
>>> li1 = [7, 8, 9, 10]
>>> li2 = li1
>>> li1[1] = 16
>>> print li2
[7, 16, 9, 10]

注解:這里li1與li2都指向同一個列表對象[7, 8, 9, 10],“li[1] = 16”是改變該列表中的第2個元素,所以通過li2時同樣會看到這一改動。

例4.2:
>>> b = [{'g':1}]*4
>>> print b
[{'g': 1}, {'g': 1}, {'g': 1}, {'g': 1}]
>>> b[0]['g'] = 2
>>> print b
[{'g': 2}, {'g': 2}, {'g': 2}, {'g': 2}]

例4.3:
>>> b = [{'g':1}] + [{'g':1}] + [{'g':1}] + [{'g':1}]
>>> print b
[{'g': 1}, {'g': 1}, {'g': 1}, {'g': 1}]
>>> b[0]['g'] = 2
>>> print b
[{'g': 2}, {'g': 1}, {'g': 1}, {'g': 1}]

注解:在有的python書中講到乘法符號(*)就相當于幾個加法的重復,即認為例4.2應該與4.3的結果一致。
????? 其實不然。例4.2中的b這個列表中的每一個元素{'g': 1}其實都是同一個對象,可以用id(b[n])進行驗證。而例4.3中則是四個不同的對象。我們可以采用名字綁定的方法消除這一歧義:

>>> a = {'g' : 1}
>>> b = [a]*4
>>> b[0]['g'] = 2
>>> print b
[{'g': 2}, {'g': 2}, {'g': 2}, {'g': 2}]
>>> print a
{'g': 2}

>>> a = {'g' : 1}
>>> b = [a] + [a] + [a] + [a]
>>> b[0]['g'] = 2
>>> print b
[{'g': 2}, {'g': 2}, {'g': 2}, {'g': 2}]
>>> print a
{'g': 2}

? 不過對于恒定對象而言,“*”和連續加法的效果一樣。比如,b=[1] * 4 就等同于 b=[1]+[1]+[1]+[1]。

5. 函數的傳參問題
? 函數的參數傳遞也是一個名字與對象的綁定過程,而且是綁定到另外一個名字空間(即函數體內部的名字空間)。python對賦值語句的獨特看法又會對函數的傳遞造成什么影響呢?

5.1 傳值?傳址?
? 在學習C++的時候我們都知道有兩種參數傳遞方式:傳值和傳址。而在python中所有的參數傳遞都是引用傳遞(pass reference),也就是傳址。這是由于名字是對象的一個引用這一python的特性而自然得來的,在函數體內部對某一外部可變對象作了修改肯定會將其改變帶到函數以外。讓我們來看看下面
這個例子:

例5.1
>>> a = [1, 2, 3]
>>> def foo(par):
...?par[1] = 10
...
>>> foo(a)
>>> print a
[1, 10, 3]

? 因此,在python中,我們應該拋開傳遞參數這種概念,時刻牢記函數的調用參數是將對象用另外一個名字空間的名字綁定。在函數中,不過是用了另外一個名字,但還是對這同一個對象進行操作。

5.2 缺省參數
? 使用缺省參數,是我們喜愛的一種作法。這可以在調用該函數時節省不少的擊鍵次數,而且代碼也顯得更加簡潔。更重要的是它從某種意義上體現了這個函數設計的初衷。
? 但是python中的缺省參數,卻隱藏著一個玄機,初學者肯定會在上面栽跟頭,而且這個錯誤非常隱秘。先看看下面這個例子:

例5.2
>>> def foo(par=[]):
...?par.append(0)
...?print par
...?
>>> foo()?????????????????????? # 第一次調用
[0]
>>> foo()?????????????????????? # 第二次調用
[0, 0]

? 出了什么問題?這個參數par好像類似與C中的靜態變量,累計了以前的結果。是這樣嗎?當然不是,這都是“對象、名字、綁定”這些思想惹的“禍”。“萬物皆對象”,還記得嗎?這里,函數foo當然也是一個對象,可以稱之為函數對象(與一般的對象沒什么不同)。先來看看這個對象有些什么屬性。

>>> dir(foo)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']

? 單從名字上看,“func_defaults”很可能與缺省參數有關,看看它的值。

>>> foo.func_defaults????????? # 顯示這個屬性的內容
([0, 0],)
>>> foo()????????????????????? # 第三次調用
[0, 0, 0]
>>> foo.func_defaults????????? # 再來看看這個屬性
([0, 0, 0],)

? 果不其然,就是這個序列對象(tuple)包含了所有的缺省參數。驗證一下:

>>> def fooM(par1, def1=1, def2=[], def3='str'):?????????? # 定義一個有多個缺省參數的函數
...?def2.append(0)
...?print par1, def1, def2, def3
...
>>> fooM.func_defaults
(1, [], 'str')

? 在函數定義中有幾個缺省參數,func_defaults中就會包括幾個對象,暫且稱之為缺省參數對象(如上列中的1,[]和'str')。這些缺省參數對象的生命周期與函數對象相同,從函數使用def定義開始,直到其消亡(如用del)。所以即便是在這些函數沒有被調用的時候,但只要定義了,缺省參數對象就會一直存在。

? 前面講過,函數調用的過程就是對象在另外一個名字空間的綁定過程。當在每次函數調用時,如果沒有傳遞任何參數給這個缺省參數,那么這個缺省參數的名字就會綁定到在func_defaults中一個對應的缺省參數對象上。
>>> fooM(2)
? 函數fooM內的名字def1就會綁定到func_defaults中的第一個對象,def2綁定到第二個,def3則是第三個。
所以我們看到在函數foo中出現的累加現象,就是由于par綁定到缺省參數對象上,而且它是一個可變對象(列表),par.append(0)就會每次改變這個缺省參數對象的內容。

? 將函數foo改進一下,可能會更容易幫助理解:
>>> def foo(par=[]):
...?print id(par)????????????????? # 查看該對象的標識碼
...?par.append(0)
...?print par
...
>>> foo.func_defaults????????????????? # 缺省參數對象的初始值
([],)
>>> id(foo.func_defaults[0])?????????? # 查看第一個缺省參數對象的標識碼
11279792?????????????????????????????? # 你的結果可能會不同
>>> foo()???????????????????????????????
11279792?????????????????????????????? # 證明par綁定的對象就是第一個缺省參數對象
[0]
>>> foo()
11279792?????????????????????????????? # 依舊綁定到第一個缺省參數對象
[0, 0]???????????????????????????????? # 該對象的值發生了變化
>>> b=[1]
>>> id(b)
11279952
>>> foo(b)???????????????????????????? # 不使用缺省參數
11279952?????????????????????????????? # 名字par所綁定的對象與外部名字b所綁定的是同一個對象
[1, 0]
>>> foo.func_defaults
([0, 0],)????????????????????????????? # 缺省參數對象還在那里,而且值并沒有發生變化
>>> foo()???????????????????
11279792?????????????????????????????? # 名字par又綁定到缺省參數對象上
([0, 0, 0],)

? 為了預防此類“問題”的發生,python建議采用下列方法:
>>> def foo(par=[]):
...?if par is None:
...??par = []
...?par.append(0)
...?print par

? 使用None作為哨兵,以判斷是否有參數傳入,如果沒有,就新創建一個新的列表對象,而不是綁定到缺省
參數對象上。

6.總結
? * python是一種純粹的面向對象語言。
? * 賦值語句是名字和對象的綁定過程。
? * 函數的傳參是對象到不同名字空間的綁定。

7.參考資料
? * 《Dive Into Python》,Mark Pilgrim,http://diveintopython.org, 2003。
? * 《Python Objects》,Fredrik Lundh,http://www.effbot.org/zone/python-objects.htm
? * 《An Introduction to Python》,David M. Beazley,http://systems.cs.uchicago.edu/~beazley/tutorial/beazley_intro_python/intropy.pdf
? *? 從Python官方網站(http://www.python.org)上可以了解到所有關于Python的知識。

posted on 2005-06-25 10:41 I love linux 閱讀(670) 評論(2) ?編輯?收藏收藏至365Key 所屬分類: Python

評論

#?re: python的對象與名字綁定(轉貼,此文甚好) 2005-12-28 16:43 jarodzz

因此,在python中,我們應該拋開傳遞參數這種概念,時刻牢記函數的調用參數是將對象用另外一個名字空間的名字綁定。在函數中,不過是用了另外一個名字,但還是對這同一個對象進行操作。

def foolyou(a):
a=a+1

if __name__=='__main__':
b=1
foolyou(b)
print b

what is b now???回復??

#?re: python的對象與名字綁定(轉貼,此文甚好)2006-01-04 16:15 asdf_asdf

a=a+1 已經是另一個"引用"了
>>> def foolyou(a):
print id(a)
a=a+1
print id(a)

>>> b
1
>>> foolyou(b)
148479408
148479396
>>> id(b)
148479408??回復??

posted on 2006-04-17 19:27 Jeff-Chen 閱讀(422) 評論(0)  編輯 收藏 引用 所屬分類: Python
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲午夜激情免费视频| 亚洲欧美日韩专区| 欧美日韩国产亚洲一区| 国产精品视频久久久| 欧美一区激情| 欧美午夜电影完整版| 久久久久久久久久久一区| 性色av一区二区三区在线观看| 欧美一区二区三区视频免费| 亚洲午夜久久久| 午夜视频在线观看一区| 韩曰欧美视频免费观看| 樱花yy私人影院亚洲| 亚洲国产精品成人精品| 日韩亚洲欧美中文三级| 亚洲女同性videos| 久久精品一区二区三区不卡牛牛| 欧美电影免费| 女人色偷偷aa久久天堂| 欧美极品欧美精品欧美视频| 欧美午夜www高清视频| 国产精品一区二区三区四区五区| 蜜臀av性久久久久蜜臀aⅴ四虎| 亚洲剧情一区二区| 亚洲视频在线观看免费| 香蕉久久一区二区不卡无毒影院| 亚洲电影免费观看高清完整版在线观看 | 欧美黑人国产人伦爽爽爽| 欧美另类高清视频在线| 午夜欧美大尺度福利影院在线看 | 亚洲二区在线视频| 欧美性理论片在线观看片免费| 亚洲一区二区视频在线观看| 欧美一区二区三区视频在线观看| 中文无字幕一区二区三区| 亚洲欧美日韩视频二区| 免费在线观看一区二区| 日韩亚洲欧美成人| 久久久精品午夜少妇| 欧美日韩精品免费观看视一区二区| 欧美一区二区免费| 免费久久99精品国产自在现线| 欧美专区在线观看一区| 亚洲视频图片小说| 久久久青草婷婷精品综合日韩 | 亚洲精品视频在线观看免费| 欧美在线播放一区二区| 欧美综合二区| 亚洲伦伦在线| 欧美高潮视频| 亚洲天堂久久| 欧美韩日一区| 在线精品福利| 尤物99国产成人精品视频| 亚洲在线免费观看| 亚洲高清二区| 久久综合久久综合久久| 精品91在线| 久久视频在线视频| 亚洲欧美日韩网| 亚洲国产成人porn| 欧美精品导航| 亚洲精品欧美| 最新中文字幕一区二区三区| 久久久久久久一区| 亚洲男女自偷自拍| 午夜精彩国产免费不卡不顿大片| 亚洲影视中文字幕| 国产精品xvideos88| 亚洲色图制服丝袜| 日韩视频二区| 国产精品成人aaaaa网站| 一区二区高清| 亚洲私人影院| 国产精品中文字幕在线观看| 欧美一级久久| 久久爱另类一区二区小说| 免费永久网站黄欧美| 伊人激情综合| 亚洲国产精品悠悠久久琪琪| 欧美肥婆在线| 亚洲一区二区3| 亚洲——在线| 黑人一区二区三区四区五区| 99视频有精品| 亚洲先锋成人| 国产一区二区三区高清| 麻豆精品一区二区综合av| 欧美激情精品久久久久| 在线视频一区二区| 国产麻豆综合| 欧美福利在线| 午夜激情一区| 亚洲国产精品女人久久久| 亚洲日韩中文字幕在线播放| 国产精品福利在线| 国产精品99久久久久久有的能看 | 免费观看不卡av| 最新国产乱人伦偷精品免费网站 | 欧美一区二区三区视频免费| 亚欧美中日韩视频| 在线国产精品播放| 一区二区三区回区在观看免费视频| 久久国产精品72免费观看| 亚洲国产人成综合网站| 一区二区久久久久| 亚洲高清视频在线| 亚洲午夜成aⅴ人片| 最新亚洲激情| 久久精品日韩欧美| 性久久久久久久久久久久| 欧美sm视频| 亚洲区中文字幕| 亚洲综合视频一区| 一本一本大道香蕉久在线精品| 亚洲国产日本| 国产精品美女久久| 亚洲一区欧美二区| 蜜桃av一区| 欧美wwwwww| 一区二区三区在线视频观看| 亚洲欧美日韩精品久久亚洲区| 欧美日韩三级视频| 欧美不卡激情三级在线观看| 国产三级欧美三级日产三级99| 久久国产乱子精品免费女 | 亚洲精品国产欧美| 久久夜色精品国产| 欧美亚洲一区| 99在线热播精品免费99热| 久久久久久久久久久久久久一区| 国产一级久久| 亚洲黄色免费| 久久综合给合| 麻豆成人在线播放| 国产精品成人一区| 一区二区三区四区国产精品| 欧美国产日韩xxxxx| 久久中文精品| 欧美搞黄网站| 国产香蕉97碰碰久久人人| 亚洲欧美一区二区三区极速播放 | 久久午夜电影网| 国产午夜精品理论片a级大结局| 一区二区三区www| 久久久国产精品一区二区中文 | 中文国产成人精品久久一| 在线看不卡av| 免费观看久久久4p| 噜噜噜久久亚洲精品国产品小说| 一区二区视频欧美| 欧美国产亚洲另类动漫| 亚洲精品少妇30p| 欧美激情精品久久久久久蜜臀| 欧美一区=区| 亚洲精品在线一区二区| 久久精品99无色码中文字幕| 国模吧视频一区| 亚洲精品乱码久久久久久蜜桃91| 欧美高清视频免费观看| 久久一区二区三区超碰国产精品| 欧美不卡福利| 蜜臀a∨国产成人精品| 亚洲欧洲另类| 欧美精品一区二区三区很污很色的 | 亚洲一区二区成人| 亚洲天堂免费观看| 国产区欧美区日韩区| 亚洲人成在线播放| 亚洲一区二区三区在线| 中日韩在线视频| 国产免费成人| 艳妇臀荡乳欲伦亚洲一区| 欧美伊人久久大香线蕉综合69| 日韩视频中文| 亚洲亚洲精品三区日韩精品在线视频| 亚洲视频免费看| 国产精品国产三级国产| 亚洲一级在线观看| 99视频精品全部免费在线| 欧美日韩国产综合视频在线| 亚洲人成人99网站| 亚洲欧美激情在线视频| 欧美激情2020午夜免费观看| 午夜精品视频网站| 久久蜜臀精品av| 欧美人与禽猛交乱配| 久久er99精品| 伊伊综合在线| 国产精品视频一二| 久久国产精品第一页| 欧美国产先锋| 欧美一区二区视频观看视频| 久久久精品国产免费观看同学| 激情综合网址| 欧美成人精品三级在线观看| 一本色道88久久加勒比精品| 亚洲一区二区精品视频| 国产视频精品va久久久久久| 久久久噜噜噜久久中文字免|