python核心编程--第十四章

孤街浪徒 提交于 2020-02-29 21:47:54

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


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!