国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

2015/10/9Python基礎(chǔ)(21):可調(diào)用和可執(zhí)行對(duì)象

2019-11-14 16:58:22
字體:
供稿:網(wǎng)友

在Python中有多種運(yùn)行外部程序的方法,比如,運(yùn)行操作系統(tǒng)命令或另外的Python腳本,或執(zhí)行一個(gè)磁盤上的文件,或通過網(wǎng)絡(luò)來運(yùn)行文件。這完全取決于想要干什么。特定的環(huán)境包括:
  在當(dāng)前腳本繼續(xù)運(yùn)行
  創(chuàng)建和管理子進(jìn)程
  執(zhí)行外部命令或程序
  執(zhí)行需要輸入的命令
  通過網(wǎng)絡(luò)來調(diào)用命令
  執(zhí)行命令來創(chuàng)建需要處理的輸出
  執(zhí)行其他的Python腳本
  執(zhí)行一系列動(dòng)態(tài)生成的Python語句
  導(dǎo)入Python模塊
  Python中,內(nèi)建和外部模塊都可以提供上述各種功能。程序員得根據(jù)實(shí)現(xiàn)的需要,從這些模塊中選擇合適的處理方法。

可調(diào)用對(duì)象

許多Python對(duì)象都是我們所說的可調(diào)用的,即是任何通過函數(shù)操作符()來調(diào)用的對(duì)象。Python有4中可調(diào)用對(duì)象:函數(shù),方法,類,以及一些類的實(shí)例。

1.函數(shù)
Python有3中不同類型的函數(shù)對(duì)象,第一種是內(nèi)建函數(shù)。
內(nèi)建函數(shù)(BIFs)
BIF是用C/CPP寫的,編譯過后放入Python解釋器,然后把它們作為第一(內(nèi)建)名字空間的一部分加載進(jìn)系統(tǒng)。這些函數(shù)在_builtin_模塊里,并作為__builtins__模塊導(dǎo)入到解釋器中。
可以用dir()列出函數(shù)的所有屬性:

>>> dir(type)['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__', '__delattr__', '__dict__', '__dictoffset__', '__doc__', '__eq__', '__flags__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__instancecheck__', '__itemsize__', '__le__', '__lt__', '__module__', '__mro__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__rePR__', '__setattr__', '__sizeof__', '__str__', '__subclasscheck__', '__subclasses__', '__subclasshook__', '__weakrefoffset__', 'mro']


從內(nèi)部機(jī)制來看,因?yàn)锽IFs和內(nèi)建方法(BIMs)屬于相同類型,所以對(duì)BIF或者BIM調(diào)用type()的結(jié)果是:

>>> type(dir)<type 'builtin_function_or_method'>

 

用戶定義的函數(shù)(UDF)
UDF通常是用Python寫的,定義在模塊的最高級(jí),因此會(huì)作為全局名字空間的一部分裝置到系統(tǒng)中。函數(shù)也可以在其他函數(shù)體內(nèi)定義,我們可以對(duì)多重嵌套作用域中的屬性進(jìn)行訪問。
從內(nèi)部機(jī)制來看,用戶自定義的函數(shù)是“函數(shù)”類型的:

>>> def foo():pass>>> type(foo)<type 'function'>

 

lambda表達(dá)式
lambda表達(dá)式和用戶自定義函數(shù)相比,略有不同。雖然它們也是返回一個(gè)函數(shù)對(duì)象,但是不是用def語句創(chuàng)建的,而是用lambda關(guān)鍵字:
因?yàn)閘ambda表達(dá)式?jīng)]有給命名綁定的代碼提供基礎(chǔ)結(jié)構(gòu),所以要通過函數(shù)式編程接口來調(diào)用,或把它們的引用賦值給一個(gè)變量,然后就可以直接調(diào)用或者再通過函數(shù)來調(diào)用。變量?jī)H是個(gè)別名,并不是函數(shù)對(duì)象的名字。
通過lambda來創(chuàng)建函數(shù)的對(duì)象除了沒有命名之外,和UDF有相同的屬性;__name__或者func_name屬性給定位字符串"<lambda>"

>>> lambdaFunc = lambda x: x * 2>>> lambdaFunc(12)24>>> type(lambdaFunc)<type 'function'>>>> lambdaFunc.__name__'<lambda>'

 


如果是UDF的名字,則是這樣:

>>> def foo():pass>>> foo.__name__'foo'

 

以上是三種函數(shù)對(duì)象

2.方法
用戶自定義方法是被定義為類的一部分的函數(shù)。許多Python的數(shù)據(jù)類型,比如列表和字典,也有方法,被稱為內(nèi)建方法。為了說明所有權(quán)的類型,方法通過對(duì)象的名字和句點(diǎn)屬性標(biāo)識(shí)符命名。

內(nèi)建方法(BIMs)
剛剛我們說了BIF和BIM的類似之處。只有內(nèi)建類型有內(nèi)建方法。對(duì)于內(nèi)建方法,type()工廠函數(shù)給出了和BIF一樣的輸出。

>>> type([].append)<type 'builtin_function_or_method'>

 

此外BIM和BIF兩者有相同屬性。不同之處在于BIM的__self__屬性指向一個(gè)Python對(duì)象,BIF指向None。

用戶定義的方法(UDM)
UDM包含在類定義之中,只是擁有標(biāo)準(zhǔn)函數(shù)的包裝,僅有定義他們的類可以使用。如果沒有在子類定義中被覆蓋,也可以通過子類實(shí)例來調(diào)用它們。

3.類
調(diào)用類的結(jié)果就是創(chuàng)建了實(shí)例,也就是實(shí)例化。

4.類的實(shí)例
Python給類提供了名為__call__的特別方法,該方法允許程序員創(chuàng)建可調(diào)用的對(duì)象(實(shí)例)。默認(rèn)情況下,__call__()方法是沒有實(shí)現(xiàn)的,這意味著大多數(shù)情況下實(shí)例是不可調(diào)用的。然而,如果在類中覆蓋了這個(gè)方法,那么這個(gè)類的實(shí)例就成為可調(diào)用的了。調(diào)用這樣的實(shí)例對(duì)象等同于調(diào)用__call__()方法。如:foo()和foo.__call__(foo)的效果相同,這里的foo也作為參數(shù)出現(xiàn),因?yàn)槭菍?duì)自己的引用,實(shí)例將自動(dòng)成為每次方法調(diào)用的第一個(gè)參數(shù),如果__call__()有參數(shù),那么foo(arg)就和foo.__call__(foo, arg)一樣。

 

代碼對(duì)象

可調(diào)用對(duì)象是Python執(zhí)行環(huán)境里最重要的部分,然而這并不是全部。Python語句,賦值,表達(dá)式,甚至還有模塊構(gòu)成了更宏大的場(chǎng)面。這些可執(zhí)行對(duì)象無法像可調(diào)用物那樣被調(diào)用。這些代碼塊被稱為代碼對(duì)象。

每個(gè)可調(diào)用物的核心都是代碼對(duì)象,由語句,賦值,表達(dá)式,以及其他可調(diào)用物組成。查看一個(gè)模塊意味著觀察一個(gè)較大的、包含了模塊中所有代碼的對(duì)象。然后代碼分成語句,賦值,表達(dá)式,以及可調(diào)用物。可調(diào)用物又可以遞歸分解到下一層,那里有它自己的代碼對(duì)象。
一般來說,代碼對(duì)象可以作為函數(shù)或者方法調(diào)用的一部分來執(zhí)行,也可用exec語句或內(nèi)建函數(shù)eval()來執(zhí)行。從整體上看,一個(gè)Python模塊的代碼對(duì)象是構(gòu)成該模塊的全部代碼。
如果要執(zhí)行Python代碼,那么該代碼必須先要轉(zhuǎn)換成字節(jié)編譯的代碼(又稱字節(jié)碼)。這才是真正的代碼對(duì)象。然而,它們不包含任何關(guān)于它們執(zhí)行環(huán)境的信息,這便是可調(diào)用物存在的原因,它被用來包裝一個(gè)代碼對(duì)象并提供額外的信息。
UDF有 udf.func_code 屬性就是代碼對(duì)象。UDM的udm.im_func也是一個(gè)函數(shù)對(duì)象,他同樣有它自己的udm.im_func.func_code代碼對(duì)象。這樣的話,你會(huì)發(fā)現(xiàn),函數(shù)對(duì)象僅是代碼對(duì)象的包裝,方法則是給函數(shù)對(duì)象的包裝。當(dāng)研究到最底層,便是一個(gè)代碼對(duì)象。

 


可執(zhí)行的對(duì)象聲明和內(nèi)建函數(shù)

Python提供了大量的BIF來支持可調(diào)用/可執(zhí)行對(duì)象。

1.callable()
callable()是一個(gè)布爾函數(shù),確定一個(gè)對(duì)象是否可以用函數(shù)操作符()來調(diào)用。如果可調(diào)用便返回True,否則便是False。

2.compile()
compile()函數(shù)允許程序員在運(yùn)行時(shí)刻迅速生成代碼對(duì)象,然后就可以用exec語句或者內(nèi)建函數(shù)eval()來執(zhí)行這些對(duì)象或者他們進(jìn)行求值。
compile的三個(gè)參數(shù)都是必需的,第一參數(shù)代表了要編譯的Python代碼。第二個(gè)參數(shù)是字符串,雖然是必需的,但通常被置為空串,該參數(shù)代表了存放代碼對(duì)象的文件的名字(字符串類型)。compile的通常用法是動(dòng)態(tài)生成字符串形式的Python代碼,然后生成一個(gè)代碼對(duì)象——代碼顯然沒有存放在任何文件。最后的參數(shù)是個(gè)字符串,用來表明代碼的類型。有三個(gè)可能值:
'eval' 可求值的表達(dá)式[和eval()一起使用]
'single' 單一可執(zhí)行語句[和exec一起使用]
'exec' 可執(zhí)行與劇組[和exec一起使用]

可求值表達(dá)式

>>> eval_code = compile('10-2','','eval')>>> eval(eval_code)8

 

單一可執(zhí)行語句

>>> single_code = compile('print "Hello world"','','single')>>> single_code<code object <module> at 024DC698, file "", line 1>>>> exec single_codeHello world

 

可執(zhí)行語句組

>>> exec_code = compile("""req = input('Count how many numbers?')for eachNum in range(req):  print eachNum""",'','exec')>>> exec exec_codeCount how many numbers?6012345

 

3.eval()
eval()對(duì)表達(dá)式求值,表達(dá)式可以為字符串或內(nèi)建函數(shù)compile()創(chuàng)建的預(yù)編譯代碼對(duì)象。這個(gè)對(duì)象是第一個(gè)也是最重要的參數(shù)。第二個(gè)和第三個(gè)參數(shù)是可選的,分別代表了全局和局部名稱空間中的對(duì)象。如果給出了這兩個(gè)參數(shù),全局必須是個(gè)字典,局部可以是任意的映射對(duì)象。如果沒有給出這兩個(gè)參數(shù),分別默認(rèn)為globals()和locals()返回的對(duì)象。如果只傳入了一個(gè)全局字典,那么該字典也作為局部參數(shù)傳入。
這是eval()的一個(gè)例子。

>>> eval('123')123>>> int('123')123>>> eval('123+234')357>>> int('123+234')Traceback (most recent call last):File "<pyshell#10>", line 1, in <module>int('123+234')ValueError: invalid literal for int() with base 10: '123+234'

 

開始,我們傳入'123'給eval()和int()的時(shí)候,返回了相同的結(jié)果,但是方式是不盡相同的,eval()接受引號(hào)內(nèi)的字符串把它作為Python表達(dá)式求值,int()接受代表整數(shù)的字符串并把它轉(zhuǎn)換為整數(shù)。而當(dāng)我們輸入'123+234'時(shí),情況就不一樣了。int()調(diào)用就失敗了。可以認(rèn)為eval()函數(shù)對(duì)表達(dá)式兩端的引號(hào)視而不見,將它執(zhí)行在解釋器上,返回結(jié)果。

4.exec
和eval()相似,exec語句執(zhí)行代碼對(duì)象或字符串形式的Python代碼。類似地,用compile()預(yù)編譯重復(fù)代碼有助于改善性能,因?yàn)樵谡{(diào)用時(shí)不必經(jīng)過字節(jié)編譯處理。exec只接受一個(gè)參數(shù),語法是:

exec obj

obj可以是原始的字符串,比如單一語句或語句組,也可以預(yù)編譯層一個(gè)代碼對(duì)象。

>>> exec """x = 0print 'x is currently:',xwhile x < 5:  x += 1  print 'incrementing x to:',x"""x is currently: 0incrementing x to: 1incrementing x to: 2incrementing x to: 3incrementing x to: 4incrementing x to: 5

 


exec還可以接受有效的Python文件對(duì)象。如果我們用上面的多行代碼創(chuàng)建一個(gè)xcount.py的文件,那么也可以這樣執(zhí)行相同代碼:

>>> f = open('xcount.py') # open the file>>> exec f # execute the filex is currently: 0incrementing x to: 1incrementing x to: 2incrementing x to: 3incrementing x to: 4incrementing x to: 5

 

上面我們調(diào)用了文件f,如果在完成后繼續(xù)調(diào)用它

>>> exec f>>>


調(diào)用會(huì)失敗。并不是真正的失敗,只是不再做任何事。事實(shí)上,exec已從文件中讀取了全部數(shù)據(jù)且停留在文件末尾(EOF)。當(dāng)用相同的文件對(duì)象對(duì)exec進(jìn)行調(diào)用的時(shí)候,沒有可執(zhí)行的代碼了,所以exec什么都不做。
我們可以用tell()方法來告訴我們處于文件的何處,然后用os.path.getsize()來告訴我們腳本由多大。然后就會(huì)發(fā)現(xiàn),這兩個(gè)數(shù)字完全一樣:

>>> f.tell()116>>> f.close()>>> from os.path import getsize>>> getsize('xcount.py')116

 

如果想在不關(guān)閉和重新打開文件的情況下再次運(yùn)行它,可以用seek()到文件最開頭并再次調(diào)用exec。假定我們還沒有調(diào)用f.close(),那么:

>>> f.seek(0)>>> exec fx is currently: 0incrementing x to: 1incrementing x to: 2incrementing x to: 3incrementing x to: 4incrementing x to: 5>>> f.close()

 

5.input()
之前用到的內(nèi)建函數(shù)input()是eval()和raw_input()的組合,等價(jià)于eval(raw_input()),input()和raw_input()一樣有一個(gè)可選的參數(shù)給用戶字符串提示。
input不同于raw_input(),input()返回的數(shù)據(jù)是對(duì)輸入表達(dá)式求值的結(jié)果,是一個(gè)Python對(duì)象。

6.使用Python在運(yùn)行時(shí)生成和執(zhí)行Python代碼
書上提供了兩個(gè)例子,這兩個(gè)例子在運(yùn)行時(shí)吧Python代碼作為字符串并執(zhí)行。
第一個(gè)例子是loopmake.py腳本。一個(gè)簡(jiǎn)單迅速和執(zhí)行循環(huán)的計(jì)算機(jī)輔助軟件工程。提示用戶給出各種參數(shù),生成代碼字符串,并執(zhí)行它。

dashes = '/n' + '-' * 50exec_dict = {'f':'''               #for loopfor %s in %s:    print %s''','s':'''               # sequence while loop%s = 0%s = %swhile %s < len(%s):    print %s[%s]    %s = %s + 1''','n':'''                # counting while loop%s = %dwhile %s < %d:    print %s    %s = %s + %d'''}def main():    ltype = raw_input('Loop type? (For/While)')    dtype = raw_input('Data type? (Number/Sequence)')    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 'The custom-generated code for you is:' + dashes    print exec_str + dashes    print 'The execution of the code:' + dashes    exec exec_str    print dashesif __name__ == '__main__':    main()    

 

有興趣的人可以執(zhí)行一下這段代碼,十分有趣,可以幫助你生成代碼并執(zhí)行。反正我寫這段代碼的時(shí)候感覺到了exec和input的強(qiáng)大。

第二個(gè)例子是有條件地執(zhí)行代碼
這是代碼:

def foo():    return Truedef bar():    'bar() does not do much'    return Truefoo.__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

 

下面是執(zhí)行后的結(jié)果:

>>> "__builtins__" is not a function"__doc__" is not a function"__file__" is not a function"__name__" is not a function"__package__" is not a functionFunction "bar" has a doc string:bar() does not do muchFunction "bar" has no tester... skippingFunction "foo" has a doc string:foo() does not do muchFunction "foo" has a tester... executingPASSED

 

代碼并不難理解,但其所做的事的確很有趣不是么?


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 金山区| 肥东县| 于都县| 石台县| 京山县| 剑阁县| 双流县| 常德市| 电白县| 镶黄旗| 周宁县| 湘乡市| 西平县| 建湖县| 建宁县| 吐鲁番市| 鹿泉市| 通辽市| 平遥县| 通道| 焉耆| 文昌市| 南皮县| 墨脱县| 商洛市| 鲜城| 浦东新区| 内黄县| 垫江县| 夹江县| 鄂州市| 东山县| 五家渠市| 巴中市| 北川| 桑植县| 醴陵市| 中超| 澳门| 棋牌| 雷波县|