python_函數與函數編程

爲便於代碼維護,絕大多數子程序都被分解並重新組織爲函數以使代碼模塊化。 在 Python中定義一個函數很簡單,Python從其它函數編程語言中借鑑了很多有用的思路用來簡化某些特定任務。本章的主題是函數,匿名函數,函數編程 特性及eval()與execfile() 函數和exec語句.還詳細描述了列表內涵(list comprehensions),一個強大的列表構建方法.

 

1.1. 函數

 

函數使用def語句定義:

<script type="text/javascript"> function isnumbered(obj) { return obj.childNodes.length && obj.firstChild.childNodes.length && obj.firstChild.firstChild.className == 'LineNumber'; } function nformat(num,chrs,add) { var nlen = Math.max(0,chrs-(''+num).length), res = ''; while (nlen>0) { res += ' '; nlen-- } return res+num+add; } function addnumber(did, nstart, nstep) { var c = document.getElementById(did), l = c.firstChild, n = 1; if (!isnumbered(c)) if (typeof nstart == 'undefined') nstart = 1; if (typeof nstep == 'undefined') nstep = 1; n = nstart; while (l != null) { if (l.tagName == 'SPAN') { var s = document.createElement('SPAN'); s.className = 'LineNumber' s.appendChild(document.createTextNode(nformat(n,4,' '))); n += nstep; if (l.childNodes.length) l.insertBefore(s, l.firstChild) else l.appendChild(s) } l = l.nextSibling; } return false; } function remnumber(did) { var c = document.getElementById(did), l = c.firstChild; if (isnumbered(c)) while (l != null) { if (l.tagName == 'SPAN' && l.firstChild.className == 'LineNumber') l.removeChild(l.firstChild); l = l.nextSibling; } return false; } function togglenumber(did, nstart, nstep) { var c = document.getElementById(did); if (isnumbered(c)) { remnumber(did); } else { addnumber(did,nstart,nstep); } return false; } </script> <script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-638ad5b5acd0cd7867515a1197393a04be469f84_000/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 add
(
x
,
y
)
:


2 return x + y

 

要調用一個函數,只要使用函數名加上小括號括起來的參數表就可以了,例如 a = add(3,4) . 參數的順序和個數必須和函數定義中的相匹配.否則會引發TypeError 異常.

定義函數的時可以使用參數默認值,如:

def foo(x,y,z = 42):

若函數定義中有存在默認值的參數,這個參數就是可選參數.

默認參數的值在函數定義的時候就被決定,並且不會改變,例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-a0aca893cf0512efc34cfe5ed08cdfbfbfaad673_001/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 10


2 def foo ( x = a ) :
3 print x
4 a = 5 # Reassign 'a'.
5 foo ( ) # Prints '10' (默認值沒有改變)

 

但是,若使用可變對象作爲默認參數值,則會有意料之外的情況發生:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-8418a8c5c68e589c62e63dc21ee24afc47d1f66b_002/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 [
10
]


2 def foo ( x = a ) :
3 print x
4 a . append ( 20 )
5 foo ( ) # Prints '[10, 20]'

 

如果最後一個參數名前有星號(*),函數就可以接受可變數量的參數,這些不定數量的參數將做爲一個元組傳遞給函數:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-bf0220ac4182ea6902897e2f2ce62764acc077bf_003/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 fprintf
(
file
,
 fmt
,
 *
args
)
:


2 file . write ( fmt % args )
3
4 # fprintf.args 被賦值爲 (42, "hello world", 3.45)
5 fprintf ( out , "%d %s %f" , 42 , "hello world" , 3.45 )

 

在這個例子中,所有剩下的參數都被放入一個元組,賦值給args. 使用*args還可以把元組args傳遞給另個函數:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-818123963ea8872025e895c5094db179f6c4916a_004/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 printf
(
fmt
,
 *
args
)
:


2 # Call another function and pass along args
3 fprintf ( sys . stdout , fmt , * args )

 

你也可以明確給每個形參名字綁定一個特定值(這稱爲關鍵字參數),然後傳遞給一個函數,如下:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-a980e149c70b82f26a6e2bc5ef049ad9cbcc2a95_005/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 foo
(
w
,
x
,
y
,
z
)
:


2 print w , x , y , z
3
4 #以關鍵字參數形式調用函數
5 foo ( x = 3 , y = 22 , w = 'hello' , z = [ 1 , 2 ] )

 

使用這種方式調用函數,參數可以是任意順序(不必與定義時順序相同).但是,除非你省略的參數有默認值,否則你必須顯式的給函數中所有形參名字指定一個值.如果是省略了某個必須的參數或你提供了一個函數定義中不存在的形參名字,就會引發TypeError 異常.

傳統的參數與關鍵字參數可以在同一個函數調用中混合使用,一個前提是必須先給出固定位置的參數,例如:

foo('hello', 3, z=[1,2], y=22)

 

如果一個函數定義中的最後一個形參有 ** (雙星號)前綴,所有正常形參之外的其他的關鍵字參數都將被放置在一個字典中傳遞給函數,例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-3294f9a5a9bd5dcd9c26a543a20d18d41eea16a3_006/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 spam
(
**
parms
)
:


2 print "You supplied the following args:"
3 for k in parms . keys ( ) :
4 print "%s = %s" % ( k , parms [ k ] )
5 spam ( x = 3 , a = "hello" , foobar = ( 2 , 3 ) )

 

常規參數,*參數及**參數可以同時使用,這時**參數必須位於參數表的最後:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-ccd0373dbb488ee12bff382270e639b0ad5506ba_007/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
# Accept variable number of positional or keyword arguments


2 def spam ( x , * args , ** keywords ) :
3 print x , args , keywords

 

使用**關鍵字語法也可以把關鍵字參數傳遞給另一個函數,如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-34a88bee436fea5a604d127fa0d90b41fcc82687_008/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 callfunc
(
func
,
 *
args
,
 **
kwargs
)
:


2 print args
3 print kwargs
4 func ( * args , ** kwargs )

 

從Python 2.1開始,函數和方法可以擁有任意的屬性,例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-d45d038442b9608b7d247d6a2cb511896da8a90b_009/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 foo
(
)
:


2 print "Hello world"
3
4 foo . secure = 1
5 foo . private = 1

 

 

       注意:這僅僅是自定義函數的特權,內建函數或者類的方法是沒有這種行爲的。 --WeiZhong

 

函數的屬性被儲存在一個字典中(函數的 __dict__ 屬性).

某些特定應用程序如語法分析器或網絡應用程序需要在一個函數中攜帶附加信息,函數屬性完美的滿足了這一需求.在Python2.1之前,只能用文檔字符串來儲存這些信息(這有很大的侷限性,比如只能存儲字符串對象,並且有違文檔字符串功能的初衷).

 

1.2. 參數傳遞和返回值

 

當調用一個函數時,它的參數是按引用傳遞給.如果函數的實參一個可變對象(如列表或字典),則函數內對該對象的修改將會影響到函數之外。例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-007a55b5b70e7914f897b7c3f34f0a8a436c2498_010/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 [
1
,
2
,
3
,
4
,
5
]


2 def foo ( x ) :
3 x [ 3 ] = - 55 # 修改 x 中的一個元素
4
5 foo ( a ) # 傳遞 a
6 print a # 顯示 [1,2,3,-55,5]

 

return語句用於從函數中返回一個對象。如果沒有指定返回對象或者return語句被省略,則會返回一個None對象.如果要返回多個值,可以通過返回一個元組或其它包含對象來完成。

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-5547ce6fe2ec07e336eafa6242a281f92400ee2d_011/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 factor
(
a
)
:


2 d = 2
3 while ( d <= ( a / 2 ) ) :
4 if ( ( a / d ) * d == a ) :
5 return ( ( a / d ) , d )
6 d = d + 1
7 return ( a , 1 )

 

如果返回值是一個元組,可以通過下面的方式來將返回值一次賦給多個獨立變量:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-5134f67974abb24297d6480355e3e694f18ce846_012/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
x
,
y
 =
 factor
(
1243
)
    # 返回的值被賦值給 x 和 y.


2 ( x , y ) = factor ( 1243 ) # 同樣的效果

 

 

1.3. 作用域規則

 

當 一個函數開始運行,就會創建一個新的局部名字空間。該名字空間用來存放函數的形參名字及該函數中所使用的全部局部變量名。當解析一個變量名時,解釋器首先 在這個局部名字空間中搜索.如果沒有找到,再接着搜索全局名字空間.一個函數的全局名字空間就是定義該函數的模塊.如果在全局名字空間中還沒有找到匹配, 解釋器接着在內建名字空間中搜索.若仍然找不到這個變量名,則引發NameError 異常.

名字空間的一個特性是:在函數內部即使有一個變量與一個全局變量同名,也各不相干(因爲它們位於不同的名字空間).例如下邊的代碼:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-20a711fc6cc270504d31426ccfe1ca220f2c013a_013/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 42


2 def foo ( ) :
3 a = 13
4 foo ( )
5 print a

 

盡 管我們在函數 foo 中修改了變量 a 的值,這個例子返回的結果仍然是 42 .如果一個變量在函數內部被賦值,則它一定是這個函數的局部變量(除非事先使用了 global 關鍵字)。在函數foo中的變量 a 其實是一個全新的值爲 13 的對象,與函數外的 a 是不同的對象. 要在函數內部使用全局變量, 你應該在函數內使用global語句. global語句明確的聲明一個或多個變量(如果有多個變量,以逗號分隔這些變量)屬於全局名字空間. 例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-5d9d00797d826ee834b97caa45b2f014e58be3fc_014/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 42


2 def foo ( ) :
3 global a # 'a' 在全局名字空間
4 a = 13
5 foo ( )
6 print a

 

所 有的Python版本都允許嵌套的函數定義.但在Python 2.1之前的版本,嵌套函數並未提供嵌套作用域.因此在老版本的Python中,嵌套函數的運行結果有可能與你的預期不同。比如下面這個例子,雖然它是合 法的,但在Python2.0中,它的執行並不象你想象的那樣:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-c26648707c48d6bbb8779efb31f5d81519802226_015/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 bar
(
)
:


2 x = 10
3 def spam ( ) : # 嵌套函數定義
4 print 'x is ' , x # 在bar()的全局名字空間中尋找x
5 while x > 0 :
6 spam ( ) # 若在Python2.0中運行該代碼 程序會報錯 : NameError on 'x'
7 x -= 1

 

在Python2.1之前的版本中,當嵌套函數spam()運行時,它的全局名字空間會與bar()相同,都是函數被定義的模塊.所以spam()無法得到它希望得到的bar()名字空間中的變量,這就引發了NameError 異常.

從Python 2.1開始支持嵌套作用域(這樣,上邊的例子就會正常運行):解釋器將首先在局部名字空間中搜索變量名,然後一層層向外搜索,最後搜索全局名字空間和內建名字空間。注意嵌套範圍在Python 2.1是一個可選的功能,只有當你的程序包含 from __future__ import nested_scopes  時才啓用該功能.(具體細節參見在第十章--運行環境).另外,如果你需要考慮和較老Python版本的兼容性,那麼就應該避免使用嵌套函數.

        注:Python 2.4中該功能已經是內建功能,不需要做那個 from __future__ import nested_scopes 操作了 --WeiZhong

 

如果一個局部變量在它被賦值之前使用,會引發一個UnboundLocalError 異常,例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-ac2397bd3b0e8d866b9ad37e10204c6d4ca096f1_016/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 foo
(
)
:


2 print i # 導致UnboundLocalError exception異常
3 i = 0

 

 

1.4. 遞歸

 

Python 對遞歸函數調用的次數作了限制.函數 sys.getrecursionlimit()返回當前允許的最大遞歸次數,而函數sys.setrecursionlimit()可以改變該函數的返 回值.默認的最大遞歸次數爲1000.當一個函數遞歸次數超過最大遞歸次數時,就會引發RuntimeError 異常.

 

1.5. apply()函數

 

apply(func [, args [, kwargs ]]) 函數用於當函數參數已經存在於一個元組或字典中時間接的調用函數. args是一個包含將要提供給函數的按位置傳遞的參數的元組. 如果省略了args,任何參數都不會被傳遞. kwargs是一個包含關鍵字參數的字典.下面的語句效果是一樣的:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-f53550a28eb8336bac2bbc772c48843a62e17531_017/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
foo
(
3
,
"x"
,
 name
=
'Dave'
,
 id
=
12345
)


2 apply ( foo , ( 3 , "x" ) , { 'name' : 'Dave' , 'id' : 12345 } )

 

在Python較老的版本里, apply()是在當參數已經位於元組或字典中時調用函數的唯一機制.不過現在,你還可以使用更直接更簡單的方式,如下:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-ffcfc46641a6873e48387ba8cfd41ebe4d9c1347_018/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 (
3
,
"x"
)


2 b = { 'name' : 'Dave' , 'id' : 12345 }
3 foo ( * a , ** b ) # 與上邊的代碼相同

 

 

1.6. lambda操作符

 

lambda語句用來創建一個匿名函數(沒和名字綁定的函數):

lambda args: expression

args是一個用逗號分隔的參數, expressin是一個調用這些參數的表達式,例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-02a8a230a0ad27a3e866b00828587fa0866edc5d_019/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 lambda
 x
,
y
 :
 x
+
y


2 print a ( 2 , 3 ) # 打印出 5

 

lambda定義的代碼必須是一個合法的表達式.多重語句和其他非表達式語句(如print, for, while等)不能出現在lambda語句中. lambda表達式也遵循和函數一樣的作用域規則.

        lambda 已經是過時的語句,即將被廢除。 --WeiZhong

 

 

1.7. map(), zip(), reduce(), 和filter()

 

t = map(func, s )函數將序列s中的每個元素傳遞給func函數做參數, 函數的返回值組成了列表 t. 即t[i] = func(s[i]). 需要注意的是, func函數必須有隻有一個參數,例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-d8c06e94cb073ea214f86a5fd3f66bb189ab4c53_020/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 [
1
,
 2
,
 3
,
 4
,
 5
,
 6
]


2 def foo ( x ) :
3 return 3 * x
4 b = map ( foo , a ) # b = [3, 6, 9, 12, 15, 18]

 

上邊的例子中的函數也可以用匿名函數來創建:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-cc818fe76756ca194238b178d00bd216879541a9_021/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
b
 =
 map
(
lambda
 x
:
 3
*
x
,
 a
)
   # b = [3, 6, 9, 12, 15, 18]


 

map ()函數也可以用於多個列表,如 t = map(func, s1, s2, ..., sn ). 如果是這種形式,t中的每個元素 t [i ] = func(s1[i ], s2[i ], ..., sn[i ]) .func函數的形參個數必須和列表的個數(n)相同,結果與s1,s2, ... sn中的最長的列表的元素個數相同.在計算過程中,短的列表自動用None擴充爲統一長度的列表.

如果函數func爲None,則func就被當成是恆等函數處理。這樣函數就返回一個包含元組的列表:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-77f249441f0dbdca8b75649e31386b3a52a8d312_022/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
a
 =
 [
1
,
2
,
3
,
4
]


2 b = [ 100 , 101 , 102 , 103 ]
3 c = map ( None , a , b ) # c = [(1,100), (2,101), (3,102), (4,103)]

 

上 邊這個例子也可以用 zip(s1 , s2 , ..., sn ) 函數來完成. zip()用來將幾個序列組合成一個包含元組的序列,序列中的每個元素t[i ] = (s1[i ], s2[i ], ..., sn[i ]). 與map()不同的是, zip()函數將所有較長的序列序列截的和最短序列一樣長:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-ccf8c2d96bab1585770bd278131bebf5fe7079a5_023/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
d
 =
 [
1
,
2
,
3
,
4
,
5
,
6
,
7
]


2 e = [ 10 , 11 , 12 ]
3 f = zip ( d , e ) # f = [(1,10), (2,11), (3,12)]

 

reduce(func , s )函數從一個序列收集信息,然後只返回一個值(例如求和,最大值,等).它首先以序列的前兩個元素調用函數,再將返回值和第三個參數作爲參數調用函數,依次執行下去,返回最終的值. func函數有且只有兩個參數.例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-22e2138782d539f9c345ea88d99eb004e0141fae_024/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
def
 sum
(
x
,
y
)
:


2 return x + y
3
4 b = reduce ( sum , a ) # b = (((1+2)+3)+4) = 10

 

filter(func ,s)是個序列過慮器,它使用func()函數來過濾s中的元素。使func返回值爲false的元素被丟棄,其它的存入filter函數返回的列表中,例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-b5cf1f86512d1d9783ec0578a638e1f661d7363d_025/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
c
 =
 filter
(
lambda
 x
:
 x
 <
 4
,
 a
)
   # c = [1, 2, 3]


 

如果函數func爲None,則func就被當成是恆等函數處理。這樣,函數就返回序列s中值爲True的元素.

 

1.8. 列表內涵

 

列表內涵可以代替許多調用map()和filter()函數的操作.列表內涵的一般形式是:

[表達式 for item1 in 序列1
for item2 in 序列2
...
for itemN in 序列N
if 條件表達式]

 

上邊的例子等價於:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-2bf68218f0a12e311c22ed87ead55e43d9946edd_026/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
s
 =
 [
]


2 for item1 in sequence1 :
3 for item2 in sequence2 :
4 . . .
5 for itemN in sequenceN :
6 if condition : s . append ( expression )

 

Listing 6.1 中的例子可以幫助你理解列表內涵

Listing 6.1 列表內涵

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-9e8f518eb4c4de70d904817c6c8937c10deecb79_027/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
import
 math


2 a = [ - 3 , 5 , 2 , - 10 , 7 , 8 ]
3 b = 'abc'
4 c = [ 2 * s for s in a ] # c = [-6,10,4,-20,14,16]
5 d = [ s for s in a if s >= 0 ] # d = [5,2,7,8]
6 e = [ ( x , y ) for x in a # e = [(5,'a'),(5,'b'),(5,'c'),
7 for y in b # (2,'a'),(2,'b'),(2,'c'),
8 if x > 0 ] # (7,'a'),(7,'b'),(7,'c'),
9 # (8,'a'),(8,'b'),(8,'c')]
10 f = [ ( 1 , 2 ) , ( 3 , 4 ) , ( 5 , 6 ) ]
11 g = [ math . sqrt ( x * x + y * y ) # f = [2.23606, 5.0, 7.81024]
12 for x , y in f ]
13 h = reduce ( lambda x , y : x + y , # 平方根的和
14 [ math . sqrt ( x * x + y * y )
15 for x , y in f ] )

 

提供給列表內涵的序列不必等長,因爲系統內部使用嵌套的一系列for循環來迭代每個序列中的每個元素,然後由if從句處理條件表達式,若條件表達式爲真,計算表達式的值並放入到列表內涵返回的序列中. if從句是可選的.

當使用列表內涵來構建包含元組的列表時,元組的值必須放在括號裏.例如 [(x,y) for x in a for y in b] 是一個合法的語句,而[x,y for x in a for y in b] 則不是.

最後,你應該注意在一個列表內涵中定義的變量是與列表內涵本身有同樣的作用域,在列表內涵計算完成後會繼續存在.例如 [x for x in a] 會覆蓋內涵外先前定義的x ,最終 x 的值會是 a 中的最後一個元素的值.

 

1.9. eval(), exec, execfile(),和compile()

 

eval(str [,globals [,locals ]])函數將字符串str當成有效Python表達式來求值,並返回計算結果。

同樣地, exec語句將字符串str當成有效Python代碼來執行.提供給exec的代碼的名稱空間和exec語句的名稱空間相同.

最後,execfile(filename [,globals [,locals ]])函數可以用來執行一個文件,看下面的例子:

        >>> eval('3+4')
7
>>> exec 'a=100'
>>> a
100
>>> execfile(r'c:/test.py')
hello,world!
>>>

 

默認的,eval(),exec,execfile()所運行的代碼都位於當前的名字空間中. eval(), exec,和 execfile()函數也可以接受一個或兩個可選字典參數作爲代碼執行的全局名字空間和局部名字空間. 例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-35fcd0d4f44116f6acfa023ac2b2be739afd0ed3_028/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
globals
 =
 {
'x'
:
 7
,


2 'y' : 10 ,
3 'birds' : [ 'Parrot' , 'Swallow' , 'Albatross' ]
4 }
5 locals = { }
6
7 # 將上邊的字典作爲全局和局部名稱空間
8 a = eval ( "3*x + 4*y" , globals , locals )
9 exec "for b in birds: print b" in globals , locals # 注意這裏的語法
10 execfile ( "foo.py" , globals , locals )

 

如果你省略了一個或者兩個名稱空間參數,那麼當前的全局和局部名稱空間就被使用.如果一個函數體內嵌嵌套函數或lambda匿名函數時,同時又在函數主體中使用exec或execfile()函數時, 由於牽到嵌套作用域,會引發一個SyntaxError 異 常.(此段原文:If you omit one or both namespaces, the current values of the global and local namespaces are used. Also,due to issues related to nested scopes, the use of exec or execfile() inside a function body may result in a SyntaxError exception if that function also contains nested function definitions or uses the lambda operator.)

        在Python2.4中俺未發現可以引起異常 --WeiZhong

 

注意例子中exec語句的用法和eval(), execfile()是不一樣的. exec是一個語句(就象print或while), 而eval()和execfile()則是內建函數.

        exec(str) 這種形式也被接受,但是它沒有返回值。 --WeiZhong

 

當 一個字符串被exec,eval(),或execfile()執行時,解釋器會先將它們編譯爲字節代碼,然後再執行.這個過程比較耗時,所以如果需要對某 段代碼執行很多次時,最好還是對該代碼先進行預編譯,這樣就不需要每次都編譯一遍代碼,可以有效提高程序的執行效率。

compile(str ,filename ,kind )函數將一個字符串編譯爲字節代碼, str是將要被編譯的字符串, filename是定義該字符串變量的文件,kind參數指定了代碼被編譯的類型-- 'single'指單個語句, 'exec'指多個語句, 'eval'指一個表達式. cmpile()函數返回一個代碼對象,該對象當然也可以被傳遞給eval()函數和exec語句來執行,例如:

<script type="text/javascript"> document.write('<a href="#" οnclick="return togglenumber(/'CA-7aa187a4683423d30c2327c6f1b2c095e4ca15f0_029/', 1, 1);" / class="codenumbers">切換行號<//a>'); </script> 切換行號
   1 
str
 =
 "for i in range(0,10): print i"


2 c = compile ( str , '' , 'exec' ) # 編譯爲字節代碼對象
3 exec c # 執行
4
5 str2 = "3*x + 4*y"
6 c2 = compile ( str2 , '' , 'eval' ) # 編譯爲表達式
7 result = eval ( c2 ) # 執行
發佈了71 篇原創文章 · 獲贊 2 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章