https://my.oschina.net/voler/blog/138826
14.1 可調用對象
許多的python對象都是我們所說的可調用的,即是任何能通過函數操作符“()”來調用的對象。要調用可調用對象,函數操作符得緊跟在可調用對象之後。python有4種可調用對象:函數,方法,類,以及一些類的實例。記住:這些對象的任何引用或者別名都是可調用的。
14.1.1 函數
內建函數(BIFs)
內建函數在_builtin_模塊裏,並作爲_builtin_模塊導入到解釋器中。
BIF 屬性 描述
bif.__doc__ 文檔字符串(或None)
bif.__name__ 字符串類型的文檔名字
bif.__self__ 設置爲None(保留給built-in 方法)
bif.__module__ 存放bif 定義的模塊名字(或None)
我們可以用dir來列出模塊的所有屬性
用戶定義的函數(UDF)
UDF 屬性 描述
udf.__doc__ 文檔字符串(也可以用udf.func_doc)
udf.__name__ 字符串類型的函數名字(也可以用 udf.func_name)
udf.func_code 字節編譯的代碼對象
udf.func_defaults 默認的參數元組
udf.func_globals 全局名字空間字典; 和從函數內部調用globals(x)一樣
udf.func_dict 函數屬性的名字空間
udf.func_doc (見上面的udf.__doc__)
udf.func_name (見上面的udf.__name__)
udf.func_closure 包含了自由變量的引用的單元對象元組
14.1.2 方法
用戶自定義方法是被定義爲類的一部分的函數。許多python數據類型,比如列表和字典,也有方法,這些被稱爲內建方法。
BIM 屬性 描述
bim.__doc__ 文檔字串
bim.__name__ 字符串類型的函數名字
bim.__self__ 綁定的對象
內建方法:
>>> dir([].append)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
用戶定義的方法(UDM)
UDM包含在類定義之中,只是擁有標準函數的包裝,僅有定義它們的類可以使用。如果沒有在子類定義中被覆蓋掉,也可以通過子類實例來調用它們。UDM與類對象是關聯的(非綁定方法),但是隻能通過類的實例來調用(綁定方法)。無論UDMs是否綁定,所有的UDM都是相同的類型--“實例方法”。
>>> class C(object): # define class # 定義類
... def foo(self): pass # define UDM # 定義UDM
...
>>> c = C() # instantiation # 實例化
>>> type(C) # type of class # 類的類別
<type 'type'>
>>> type(c) # type of instance # 實例的類別
<class '__main__.C'>
>>> type(C.foo) # type of unbound method # 非綁定方法的類別
<type 'instancemethod'>
>>> type(c.foo) # type of bound method # 綁定方法的類別
<type 'instancemethod'>
>>> C.foo
<unbound method C.foo>
>>> c.foo
<bound method C.foo of <__main__.C object at 0x02115D50>>
>>> c
<__main__.C object at 0x02115D50>
UDM 屬性 描述 udm.__doc__ 文檔字符串(與udm.im_fuc.__doc__相同)
udm.__name__ 字符串類型的方法名字(與umd.im_func.__name__相同)
udm.__module__ 定義udm 的模塊的名字(或none)
udm.im_class 方法相關聯的類(對於綁定的方法;如果是非綁定,那麼爲要求udm 的類)
udm.im_func 方法的函數對象(見UDFs)
udm.im_self 如果綁定的話爲相關聯的實例,如果非綁定位爲none
14.1.3 類
利用類的可調用性來創建實例。
>>> class C(object):
def __init__(self, *args):
print "instantiated with these arguments:\n", args
>>> c1 = C()
instantiated with these arguments:
()
>>> c2 = C("the number of the counting shall be",3)
instantiated with these arguments:
('the number of the counting shall be', 3)
14.1.4 類的實例
python給類提供了名爲__call__的特別方法,該方法允許程序員創建可調用的對象實例。
>>> class C(object):
def __call__(self, *args):
print "i am callable!called with args:\n", args
>>> c = C()
>>> c
<__main__.C object at 0x02115E10>
>>> callable(c)
True
>>> c()
i am callable!called with args:
()
>>> c(3)
i am callable!called with args:
(3,)
14.2 代碼對象
可調用的對象是python 執行環境裏最重要的部分,然而他們只是冰山一角。python 語句,賦值,表達式,甚至還有模塊構成了更宏大的場面。這些可執行對象無法像可調用物那樣被調用。更確切地說,這些對象只是構成可執行代碼塊的拼圖的很小一部分,而這些代碼塊被稱爲代碼對象。
每個可調用物的核心都是代碼對象,由語句,賦值,表達式,以及其他可調用物組成。察看一個模塊意味着觀察一個較大的、包含了模塊中所有代碼的對象。然後代碼可以分成語句,賦值,表達式,以及可調用物。可調用物又可以遞歸分解到下一層,那兒有自己的代碼對象。
一般說來,代碼對象可以作爲函數或者方法調用的一部分來執行,也可用exec 語句或內建函數eval()來執行。從整體上看,一個python 模塊的代碼對象是構成該模塊的全部代碼。
如果要執行python 代碼,那麼該代碼必須先要轉換成字節編譯的代碼(又稱字節碼)。這纔是真正的代碼對象。然而,它們不包含任何關於它們執行環境的信息,這便是可調用物存在的原因,它被用來包裝一個代碼對象並提供額外的信息。
14.3 可執行的對象聲明和內建函數
14.3.1 callable()
callable()是一個布爾函數,確定一個對象是否可以通過函數操作符(())來調用。如果函數可調用則返回true,否則返回false。
>>> callable(dir)
True
>>> callable(1)
False
>>> def foo():pass
>>> callable(foo)
True
>>> class C(object):pass
>>> callable(C)
True
14.3.2 compile()
compile()函數允許程序員在運行時刻迅速生成代碼對象,然後就可以用exec語句或者內建函數eval()來執行這些對象或者對它們進行求值。一個很重要的觀點是:exec和eval都可以執行字符串格式的python代碼。當執行字符串形式的代碼時,每次都必須對這些代碼進行字節編譯處理。compile函數提供了一次性字節代碼預編譯,以後每次調用的時候,都不用編譯了。
compile 的三個參數都是必需的,第一參數代表了要編譯的python 代碼。第二個字符串,雖然是必需的,但通常被置爲空串。該參數代表了存放代碼對象的文件的名字(字符串類型)。compile 的通常用法是動態生成字符串形式的Python 代碼, 然後生成一個代碼對象——代碼顯然沒有存放在任何文件。
最後的參數是個字符串,它用來表明代碼對象的類型。有三個可能值:
'eval' 可求值的表達式[和eval()一起使用]
'single' 單一可執行語句[和exec 一起使用]
'exec' 可執行語句組[和exec 一起使用]
可求值表達式:
>>> eval_code = compile("100+200","","eval")
>>> eval(eval_code)
300
單一可執行語句
>>> single_code = compile("print 'hello world!'","", "single")
>>> single_code
<code object <module> at 021174E8, file "", line 1>
>>> exec single_code
hello world!
可執行語句組:
exec_code = compile("""
req = input("count how many numbers?")
for eachNum in range(req):
print eachNum,
""","","exec")
程序輸出:
>>> exec exec_code
count how many numbers?6
0 1 2 3 4 5
14.3.3 eval()
eval()對表達式求值,後者可以爲字符串或內建函數complie()創建的預編譯代碼對象。這是eval()第一個也是最重要的參數.......這便是你想要執行的對象。第二個和第三個參數,都爲可選的,分別代表了全局和局部名字空間中的對象。如果給出這兩個參數,globals 必須是個字典,locals可以是任意的映射對象,比如,一個實現了__getitem__()方法的對象。(在2.4 之前,local 必須是一個字典)如果都沒給出這兩個參數,分別默認爲globals()和locals()返回的對象,如果只傳入了一個全局字典,那麼該字典也作爲locals 傳入
>>> eval("100+200")
300
14.3.4 exec
和eval()相似,exec 語句執行代碼對象或字符串形式的python 代碼。類似地,用compile()預編譯重複代碼有助於改善性能,因爲在調用時不必經過字節編譯處理。exec 語句只接受一個參數,下面便是它的通用語法:
exec obj
exec """
x = 0
print "x is currently:",x
while x < 5:
x += 1
print "incrementing x to:",x
"""
程序輸出:
>>>
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5
當然,exec也可以執行文件對象,我們上面的代碼在文件xcount.py中:
>>> f = open("xcount.py")
>>> exec f
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5
>>> exec f
>>> f.close()
>>> f = open("xcount.py")
>>> exec f
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5
中間出現exec f後沒任何反應,是因爲文件也是順序執行下來的,已經到末尾了,所以exec f當然沒任何反應。重新打開文件再執行即可。
當然,我們也可以這樣做:
>>> f = open("xcount.py")
>>> exec f
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5
>>> f.seek(0)
>>> exec f
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5
14.3.5 input()
內建函數input()是eval()和raw_input()的組合,等價於eval(raw_input()).
從功能上看,input 不同於raw_input(),因爲raw_input()總是以字符串的形式,逐字地返回用戶的輸入。input()履行相同的的任務;而且,它還把輸入作爲python 表達式進行求值。這意味着input()返回的數據是對輸入表達式求值的結果:一個python 對象。
下面的例子確實讓我吃驚:
>>> aString = raw_input("enter a list:")
enter a list:[123,"xyz",45.67]
>>> aString
'[123,"xyz",45.67]'
>>> type(aString)
<type 'str'>
>>> aList = input("enter a list:")
enter a list:[123,"xyz",45.67]
>>> aList
[123, 'xyz', 45.67]
>>> type(aList)
<type 'list'>
雖然用戶輸入字符串,但是input()把輸入作爲python對象來求值並返回表達式的結果。
14.3.6 使用python在運行時生成和執行python代碼
第一個例子是loopmake.py 腳本,一個簡單的、迅速生成和執行循環的計算機輔助軟件工程(CASE)。它提示用戶給出各種參數(比如,循環類型(while 或for), 迭代的數據類型[數字或序列]),生成代碼字串,並執行它
dashes = "\n" + "-"*50
exec_dict = {
"f":"""
for %s in %s:
print %s
""",
"s":"""
%s=0
%s = %s
while %s < len(%s):
print %s[%s]
%s = %s + 1
""",
"n":"""
%s = %d
while %s < %d:
print %s
%s = %s + %d
"""
}
def main():
ltype = raw_input("loop type?(for/while)")
dtype = raw_input("data type?(number/seq)")
if dtype == "n":
start = input("starting value?")
stop = input("ending value(non-inclusive)?")
step = input("stepping value?")
seq = str(range(start, stop, step))
else:
seq = raw_input("enter sequence:")
var = raw_input("iterative variable name?")
if ltype == "f":
exec_str = exec_dict["f"] % (var, seq, var)
elif ltype == "w":
if dtype == "s":
svar = raw_input("enter sequence name?")
exec_str = exec_dict["s"] %\
(var, svar, seq, var, svar, svar, var,var,var)
elif dtype == "n":
exec_str = exec_dict["n"] %\
(var, start, var, stop, var, var, var, step)
print dashes
print "your custom-generated code:" + dashes
print exec_str + dashes
print "test execution of the code:" + dashes
exec exec_str
print dashes
if __name__ == "__main__":
main()
我坦白說,這個程序特別的好玩。技術含量提高的,但是更重要的是:好玩:
>>>
loop type?(for/while)w
data type?(number/seq)n
starting value?0
ending value(non-inclusive)?4
stepping value?1
iterative variable name?counter
--------------------------------------------------
your custom-generated code:
--------------------------------------------------
counter = 0
while counter < 4:
print counter
counter = counter + 1
--------------------------------------------------
test execution of the code:
--------------------------------------------------
0
1
2
3
--------------------------------------------------
>>>
loop type?(for/while)f
data type?(number/seq)n
starting value?0
ending value(non-inclusive)?4
stepping value?1
iterative variable name?counter
--------------------------------------------------
your custom-generated code:
--------------------------------------------------
for counter in [0, 1, 2, 3]:
print counter
--------------------------------------------------
test execution of the code:
--------------------------------------------------
0
1
2
3
--------------------------------------------------
>>>
loop type?(for/while)w
data type?(number/seq)s
enter sequence:[932,"grail",3.0,"arrrghhh"]
iterative variable name?eachIndex
enter sequence name?myList
--------------------------------------------------
your custom-generated code:
--------------------------------------------------
eachIndex=0
myList = [932,"grail",3.0,"arrrghhh"]
while eachIndex < len(myList):
print myList[eachIndex]
eachIndex = eachIndex + 1
--------------------------------------------------
test execution of the code:
--------------------------------------------------
932
grail
3.0
arrrghhh
--------------------------------------------------
有條件的執行代碼:
def foo():
return True
def bar():
"bar() does not do much"
return True
foo.__doc__ = "foo() does not do much"
foo.tester = """
if foo():
print "passed"
else:
print "failed"
"""
for eachAttr in dir():
obj = eval(eachAttr)
if isinstance(obj, type(foo)):
if hasattr(obj, "__doc__"):
print "\nfunction '%s' has a doc string:\n\t%s" % (eachAttr, obj.__doc__)
if hasattr(obj, "tester"):
print "function '%s' has a tester...executing" % eachAttr
exec obj.tester
else:
print "function '%s' has no tester...skipping" % eachAttr
else:
print "%s is not a function" % eachAttr
程序輸出:
>>>
__builtins__ is not a function
__doc__ is not a function
__name__ is not a function
__package__ is not a function
function 'bar' has a doc string:
bar() does not do much
function 'bar' has no tester...skipping
function 'foo' has a doc string:
foo() does not do much
function 'foo' has a tester...executing
passed
14.4 執行其他(python)程序
當討論執行其他程序時,我們把它們分類爲python程序和其他所有的非python程序,後者包括了二進制可執行文件或其他腳本語言的源代碼。
14.4.1 導入
第一次導入模塊會執行模塊最高級的代碼。如果你想某些功能不被執行,那麼就縮進它,然後放入 if __name__ == "__main__"中去即可。
14.4.2 execfile()
顯然,導入模塊不是從另外的python腳本中執行python腳本最可取的方法。那也就不是導入過程。導入模塊的副作用是導致最高級代碼運行。
f = open(filename,"r")
exec f
f.close()
等價於:
execfile(filename)
雖然上述代碼執行了一個模塊,但是僅可以在現有的執行環境下運行(比如,它自己的全局和局部的名字空間)。在某些情況下,可能需要用不同全局和局部的名字空間集合,而不是默認的集合來執行模塊。execfile() 函數的語法非常類似於eval()函數的。
execfile(filename, globals=globals(), locals=locals())
14.4.3 將模塊作爲腳本執行
通過shell或者DOS來執行即可。
14.5 執行其他(非python)程序
14.5.1 os.system()
接收字符串形式的系統命令並執行它。當執行命令的時候,python的運行是掛起的。當我們的執行完成之後,將會以system()的返回值給出退出狀態,python的執行也會繼續。
>>> import os
>>> result = os.system("dir")
>>> result
0
結果是出現DOS黑框框,然後一閃而過。。。。。。。
14.5.2 os.popen()
不理解這個函數。。。。。。
後面剩下的10也就不看了,主要是現在沒涉及到多平臺的開發,看了也忘,而且例子多數在linux下,無法操作。
14.10 練習
14–1. 可調用對象。 說出python 中的可調用對象。exec 語句和內建函數eval()有什麼不同?
可通過函數操作符(())來調用的對象是可調用對象。而exec通常直接執行一個字符串,eval()通常執行的是表達式。
14–2. input()和raw.input()。 內建函數raw_input()和input()有什麼不同?
input()操作的是表達式,並把表達式直接顯示出來,而raw_input()則用適當的形式(爲字符串)來顯示。
14–3. 執行環境。創建運行其他python 腳本的python 腳本
execfile("file1.txt")
execfile("file2.txt")
execfile("file3.txt")
程序輸出:
>>>
hello world
4
0 1 2 3 4
而file1.txt的內容爲:
print "hello world"
file2.txt的內容爲:
print 1+1+2
file3.txt的內容爲:
for i in range(5):
print i,
14–4. os.system()。選擇熟悉的系統命令,該命令執行任務時不需要輸入,也不輸出到屏幕或根本不輸出任何東西。調用os.system()運行程序
>>> import os
>>> os.system("date")
程序輸出:
14–5. commands.getoutput().用commands.getoutput()解決前面的問題
在windows平臺上貌似不行吧,我直接運行都無commands模塊。。。。。