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

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,是因為這兩個不同的對象有著相同的值。

? 與對象的標識碼類似,對象的類型也是不可更改的??梢杂脙冉ê瘮祎ype()取得對象的類型。

? 有的對象的值是可以改變的,這類對象叫作可變對象;而另外一些對象在創建后其值是不可改變的(如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中的靜態變量,累計了以前的結果。是這樣嗎?當然不是,這都是“對象、名字、綁定”這些思想惹的“禍”?!叭f物皆對象”,還記得嗎?這里,函數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>
            国产精品私人影院| 亚洲激情欧美激情| 午夜久久tv| 中日韩高清电影网| 中日韩美女免费视频网站在线观看| 久久久一区二区三区| 午夜精品福利在线| 亚洲图片激情小说| 亚洲欧美日韩一区| 亚洲一区二区三区在线看 | 激情久久一区| 红桃av永久久久| 激情一区二区三区| 亚洲欧洲在线观看| 亚洲一区二区高清| 久久综合精品国产一区二区三区| 亚洲欧美日产图| 久久久久国产精品一区二区| 久久夜精品va视频免费观看| 免费亚洲电影在线| 国产精品久久久久久久7电影 | 一区二区三区日韩在线观看 | 久久裸体视频| 久久亚洲精品欧美| 国产精品久久久久久久久久久久久久| 国产亚洲午夜| 在线亚洲免费视频| 久久精品二区三区| 亚洲国产精品欧美一二99| 久久综合五月| 亚洲欧美日韩在线一区| 欧美高清在线一区二区| 国模私拍一区二区三区| 亚洲素人一区二区| 亚洲狠狠丁香婷婷综合久久久| 美国成人直播| 欧美一区二区三区精品| 欧美日韩国产a| 欧美精品在线视频观看| 亚洲第一中文字幕在线观看| 欧美日韩一区二区三区四区在线观看| 欧美日韩在线免费观看| 日韩一级免费| 制服丝袜激情欧洲亚洲| 欧美日韩国产欧| 亚洲欧美国产一区二区三区| 日韩午夜免费| 国产精品久久久久免费a∨| 亚洲男人av电影| 亚洲免费影视| 在线观看亚洲精品视频| 欧美高清视频在线| 国产精品久久久久久妇女6080| 久久免费午夜影院| 欧美日本在线看| 久久综合久久综合久久| 麻豆精品一区二区综合av| 最新日韩中文字幕| 日韩亚洲欧美一区二区三区| 国产精品夜色7777狼人| 亚洲激情在线| 国内视频精品| 亚洲精品网站在线播放gif| 国产三级精品在线不卡| 久久综合色88| 欧美三级不卡| 农夫在线精品视频免费观看| 国产精品国产三级国产普通话蜜臀| 欧美在线资源| 国产农村妇女精品一区二区| 亚洲精品在线免费| 亚洲精品日日夜夜| 亚洲一区影院| 亚洲一区中文| 欧美性大战久久久久久久蜜臀| 精品69视频一区二区三区| 亚洲激情小视频| 日韩一级裸体免费视频| 欧美高清自拍一区| 欧美国产精品一区| 尤物精品国产第一福利三区| 欧美亚洲在线视频| 欧美资源在线| 亚洲国内精品| 欧美电影打屁股sp| 91久久精品国产91性色| 亚洲精品国产欧美| 欧美日韩一区二区在线观看| 91久久久久久国产精品| 99av国产精品欲麻豆| 国产精品a久久久久久| 午夜亚洲性色视频| 欧美成人蜜桃| 一本久道久久久| 国产亚洲精品久久久久久| 久久精品国产91精品亚洲| 久久久九九九九| 日韩午夜黄色| 黑人极品videos精品欧美裸| 欧美成人精品不卡视频在线观看 | 国产精品国产三级国产专播精品人| 蜜桃伊人久久| 亚洲欧美另类久久久精品2019| 久久精品2019中文字幕| 一区二区三欧美| 影音先锋久久| 国产一区91| 欧美性做爰毛片| 欧美日韩久久不卡| 猫咪成人在线观看| 久久久久久久久一区二区| 亚洲欧美日韩另类| av成人天堂| 一区二区在线观看视频| 欧美亚州一区二区三区 | 日韩亚洲欧美高清| 亚洲高清在线观看一区| 亚洲二区视频在线| 亚洲国内自拍| 亚洲免费观看在线观看| 亚洲国产欧美一区| 亚洲欧洲三级| 亚洲精品在线一区二区| 影音先锋另类| 亚洲精品国精品久久99热一| 亚洲国产天堂久久综合| 亚洲九九爱视频| 亚洲深夜影院| 久久久青草婷婷精品综合日韩| 午夜免费日韩视频| 欧美成人免费视频| 日韩午夜av在线| 久久都是精品| 欧美在线播放| 欧美午夜女人视频在线| 国产精品高潮呻吟久久| 亚洲高清视频一区| 亚洲一区二区精品在线| 午夜精品久久久| 亚洲国产高清在线| 亚洲永久在线观看| 亚洲国产婷婷综合在线精品| 午夜精品一区二区三区在线| 欧美激情精品久久久久久黑人| 国产精品久久999| 亚洲精品视频二区| 免费中文日韩| 久久久精品2019中文字幕神马| 欧美日韩精品| 亚洲国产精品久久人人爱蜜臀 | 亚洲欧美久久久| 亚洲视频一二| 欧美大片免费久久精品三p | 亚洲精品孕妇| 亚洲三级视频在线观看| 久久久天天操| 最新高清无码专区| 欧美+亚洲+精品+三区| 久久av红桃一区二区小说| 国产欧美va欧美不卡在线| 亚洲欧美精品suv| 欧美在线看片| 国产日韩欧美a| 亚洲电影免费在线观看| 久久se精品一区二区| 在线观看国产日韩| 欧美成人r级一区二区三区| 欧美激情精品久久久六区热门| 日韩一区二区精品葵司在线| 日韩一级不卡| 国模私拍视频一区| 亚洲韩日在线| 在线播放不卡| 中国成人黄色视屏| 国产自产女人91一区在线观看| 鲁大师成人一区二区三区 | 午夜久久tv| 亚洲久久成人| 99精品久久| 99v久久综合狠狠综合久久| 久久av一区二区三区漫画| 一区二区三区蜜桃网| 久久婷婷丁香| 玖玖国产精品视频| 好看的日韩视频| 亚洲欧美日韩在线观看a三区| 在线视频中文亚洲| 欧美日韩国产探花| 99av国产精品欲麻豆| 麻豆精品在线视频| 久久久久久久高潮| 国产色综合久久| 欧美在线短视频| 久久精品亚洲一区二区三区浴池| 欧美伦理a级免费电影| 亚洲国产精品久久人人爱蜜臀| 亚洲国产精品视频一区| 你懂的视频欧美| 亚洲欧洲一区二区在线播放| 一区二区三区国产在线|