python核心編程--第十四章

python核心編程--第十四章
 
  • 發表於 4年前 
  • 閱讀 771 
  • 收藏 15 
  • 點贊 0 
  • 評論 3

獨家直播!大數據應用場景全解析>>>   

              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模塊。。。。。

發佈了18 篇原創文章 · 獲贊 11 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章