python核心編程--第十四章

14.1 可調用對象 python

許多的python對象都是咱們所說的可調用的,便是任何能經過函數操做符「()」來調用的對象。要調用可調用對象,函數操做符得緊跟在可調用對象以後。python有4種可調用對象:函數,方法,類,以及一些類的實例。記住:這些對象的任何引用或者別名都是可調用的。 linux

14.1.1 函數 程序員

內建函數(BIFs) shell

內建函數在_builtin_模塊裏,並做爲_builtin_模塊導入到解釋器中。 windows

BIF 屬性 描述
bif.__doc__             文檔字符串(或None)
bif.__name__          字符串類型的文檔名字
bif.__self__             設置爲None(保留給built-in 方法)
bif.__module__         存放bif 定義的模塊名字(或None) app

咱們能夠用dir來列出模塊的全部屬性 ssh

用戶定義的函數(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 方法 oop

用戶自定義方法是被定義爲類的一部分的函數。許多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模塊。。。。。

相關文章
相關標籤/搜索