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 属性 描述
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
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 514.3.3 eval()
eval()对表达式求值,后者可以为字符串或内建函数complie()创建的预编译代码对象。这是eval()第一个也是最重要的参数.......这便是你想要执行的对象。第二个和第三个参数,都为可选的,分别代表了全局和局部名字空间中的对象。如果给出这两个参数,globals 必须是个字典,locals可以是任意的映射对象,比如,一个实现了__getitem__()方法的对象。(在2.4 之前,local 必须是一个字典)如果都没给出这两个参数,分别默认为globals()和locals()返回的对象,如果只传入了一个全局字典,那么该字典也作为locals 传入
>>> eval("100+200") 30014.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: 514.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+2file3.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模块。。。。。