14ch

14.1可调用对象

Python有四种可调用对象(可以通过函数操作符‘()’来调用的对象):函数、方法、类、类的实例

14.1.1函数

1.内建函数(BIF)

内建函数是用C/C++写的,编译过后放入Python解释器,然后把它们作为第一名称空间的一部分加载进系统。如之前章节所述,这些函数在_bulitin_模块里,并作为__builtins__模块导入到解释器中

属性 描述
bif.__doc__ 文档字符串(或None)
bif.__name__ 字符串类型的文档名字
bif.__self__ 设置为None(保留给内建方法)
bif.__module__ 存放bif定义的模块名字(或None)

可以用dir()列出函数的所有属性

>>> 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']

从内部机制来看,因为内建函数和内建方法属于相同的类型,所以对BIF或者BIM调用type()的结果是

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

注意这不能应用于工厂函数,因为type()正好会返回产生对象的类型

2.用户定义的函数(UDF)

用户定义的函数通常是用Python写的,定义在模块的最高级,因此会作为全局名称空间的一部分装载到系统中。函数也可以在其他函数体内定义,并且由于在2.2中嵌套作用域的改进,我们现在可以对多重嵌套作用域中的属性进行访问。可以用func_closure属性来勾住在其他地方定义的属性。

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 包含了自由变量的引用的单元对象元组(自用变量在UDF中使用,但在别处定义)

3.lambda表达式

通过lambda来创建函数的对象除了没有命名之外,享有和用户自定义函数相同的属性,__name__或者func_name属性给定为字符串"<lambda>"。

14.1.2方法

1.内建方法

对于内建方法,type()工厂函数给出了和内建函数相同的输出。此外,内建方法和内建函数两者也享有相同属性,不同之处在于内建方法的__self__属性指向一个Python对象,而内建函数指向None。

对于类和实例都可以通过dir来获取方法属性,对于内建方法也是如此。

2.用户定义的方法(UDM)

用户定义的方法包含在类定义之中,只是拥有标准函数的包装,仅有定义它们的类可以使用。如果没有在子类定义中被覆盖掉,也可以通过子类实例来调用它们。正如13章中解释的,UDM与类对象是关联的(非绑定方法),但是只能通过类的实例来调用(绑定方法)。

属性 描述
udm.__doc__ 文档字符串(与udm.im_fuc.__doc__相同)
udm.__name__ 字符串类型的方法名字(与udm.im_fuc.__name__相同)
udm.__module__ 定义udm的模块的名字(或None
udm.im_class 方法相关联的类(如果是非绑定,那么为要求是udm的类
udm.im_func 方法的函数对象
udm.im_self 如果绑定的话为相关联的实例,否则为None

14.1.3 类

>>>class C(object):

  def __init__(self, *args):
    print 'Instantiated with these arguments: ', args

>>>c1=C('foo',3)

Instantiated with these arguments:
('foo',3)

14.1.4 类的实例

Python给类提供了名为__call__的特别方法,该方法允许创建可调用的对象(实例)。默认情况下__call__()方法是没有实现的,这意味着大多数实例都是不可调用的。

---恢复内容结束---

14.1可调用对象

Python有四种可调用对象(可以通过函数操作符‘()’来调用的对象):函数、方法、类、类的实例

14.1.1函数

1.内建函数(BIF)

内建函数是用C/C++写的,编译过后放入Python解释器,然后把它们作为第一名称空间的一部分加载进系统。如之前章节所述,这些函数在_bulitin_模块里,并作为__builtins__模块导入到解释器中

属性 描述
bif.__doc__ 文档字符串(或None)
bif.__name__ 字符串类型的文档名字
bif.__self__ 设置为None(保留给内建方法)
bif.__module__ 存放bif定义的模块名字(或None)

可以用dir()列出函数的所有属性

>>> 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']

从内部机制来看,因为内建函数和内建方法属于相同的类型,所以对BIF或者BIM调用type()的结果是

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

注意这不能应用于工厂函数,因为type()正好会返回产生对象的类型

2.用户定义的函数(UDF)

用户定义的函数通常是用Python写的,定义在模块的最高级,因此会作为全局名称空间的一部分装载到系统中。函数也可以在其他函数体内定义,并且由于在2.2中嵌套作用域的改进,我们现在可以对多重嵌套作用域中的属性进行访问。可以用func_closure属性来勾住在其他地方定义的属性。

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 包含了自由变量的引用的单元对象元组(自用变量在UDF中使用,但在别处定义)

3.lambda表达式

通过lambda来创建函数的对象除了没有命名之外,享有和用户自定义函数相同的属性,__name__或者func_name属性给定为字符串"<lambda>"。

14.1.2方法

1.内建方法

对于内建方法,type()工厂函数给出了和内建函数相同的输出。此外,内建方法和内建函数两者也享有相同属性,不同之处在于内建方法的__self__属性指向一个Python对象,而内建函数指向None。

对于类和实例都可以通过dir来获取方法属性,对于内建方法也是如此。

2.用户定义的方法(UDM)

用户定义的方法包含在类定义之中,只是拥有标准函数的包装,仅有定义它们的类可以使用。如果没有在子类定义中被覆盖掉,也可以通过子类实例来调用它们。正如13章中解释的,UDM与类对象是关联的(非绑定方法),但是只能通过类的实例来调用(绑定方法)。

属性 描述
udm.__doc__ 文档字符串(与udm.im_fuc.__doc__相同)
udm.__name__ 字符串类型的方法名字(与udm.im_fuc.__name__相同)
udm.__module__ 定义udm的模块的名字(或None
udm.im_class 方法相关联的类(如果是非绑定,那么为要求是udm的类
udm.im_func 方法的函数对象
udm.im_self 如果绑定的话为相关联的实例,否则为None

14.1.3 类

 1 >>> class C(object):
 2     def __init__(self, *args):
 3         print "instantiated with these arguments:
", args         
 4 >>> c1 = C()
 5 instantiated with these arguments:
 6 ()
 7 >>> c2 = C("the number of the counting shall be",3)
 8 instantiated with these arguments:
 9 ('the number of the counting shall be', 3)

14.1.4类的实例

Python给类提供了名为__call__的特别方法,该方法允许程序员创建可调用的对象实例。默认情况下,__call__()方法是没有实现的,这意味着大多数实例是不可调用的。foo()就相当于foo.__call__(foo), foo(arg)相当于foo.__call__(foo,arg)。

 1 >>> class C(object):
 2     def __call__(self, *args):
 3         print "i am callable!called with args:
", args
 4 >>> c = C()
 5 >>> c
 6 <__main__.C object at 0x02115E10>
 7 >>> callable(c)
 8 True
 9 >>> c()
10 i am callable!called with args:
11 ()

14.2代码对象

每个可调用对象的核心都是代码对象,代码对象由语句statements、赋值assignments、表达式expressions、可调用对象组成。

如果要执行Python代码,那么该代码必须转换成字节编译的代码(字节码),这才是真正的代码对象。然而它们不包含任何关于它们执行环境的信息,这便是可调用对象存在的原因--包装一个代码对象并提供额外的信息。

14.3可执行的对象声明和内建函数

Python提供了大量的BIF来支持可调用/可执行对象

内建函数和语句 描述
calllable(obj) 如果obj可调用,返回True,否则返回FALSE
compile(string,file,type) 从type类型中创建代码对象;file是代码存放的地方(通常设为"")
eval(obj,globals=globals(),locals=locals()) 对obj进行求值,obj是已编译为代码对象的表达式,或是一个字符串表达式;可以给出全局或者/和局部的名称空间
exec obj 执行obj、单一的Python语句或者语句的集合,也就是说格式是代码对象或者字符串;obj也可以是一个文件对象(已经打开的有效Python脚本中)
input(prompt='') 等同于eval(raw_input(prompt=''))

14.3.1callable()

callable()是一个布尔函数,确定一个对象是否可以通过函数操作符()来调用。

14.3.2compile()

compile()函数允许程序员在程序运行时生成代码对象(字符串形式),然后用exec和eval()来执行代码。compile()的第三个参数表明代码对象的类型,有三个可能的值'eval'--可求值的表达式(与eval()搭配),'single'--单一可执行语句(与exec搭配),'exec'--可执行语句组(与exec搭配)。

1.可求值表达式

>>>eval_code = compile('100+200', '', 'eval')

>>>eval(eval_code)

300

2.单一可执行语句

>>> single_code = compile('print "Hello world!"', '','single')
>>> single_code
<code object <module> at 02085D58, file "", line 1>
>>> exec single_code
Hello world!

3.可执行语句组

>>> exec_code = compile("""
req = input('Count how many numbers?')
for eachNum in range(req):
    print eachNum
""", '', 'exec')
>>> exec exec_code
Count how many numbers?5
0
1
2
3
4

14.3.3 eval()

eval()的第一个参数可以是字符串或者compile()创建的预编译代码对象,第二个第三个参数都是可选的,分别是全局和局部名称空间中的对象,如果给出了这两个参数,那么global必须是个字典,locals可以是任意的映射对象,比如一个实现了__getitem__()方法的对象。如果只传入了一个全局字典,那么该字典也作为locals传入。

14.3.4 exec

exec的语法是exec obj

 1 >>> f = open("xcount.py")
 2 >>> exec f
 3 x is currently: 0
 4 incrementing x to: 1
 5 incrementing x to: 2
 6 incrementing x to: 3
 7 incrementing x to: 4
 8 incrementing x to: 5
 9 >>> exec f
10 >>> f.close()
11 >>> f = open("xcount.py")
12 >>> exec f
13 x is currently: 0
14 incrementing x to: 1
15 incrementing x to: 2
16 incrementing x to: 3
17 incrementing x to: 4
18 incrementing x to: 5

当obj为文件对象时,要记得关闭打开了的文件对象

14.3.5 input()

内建函数input()是eval()和raw_input()的组合,等价于eval(raw_input()),input()有一个可选的参数,用于给用户一个字符串提示。

14.3.6使用Python在运行时生成和执行Python代码

loopmake.py脚本是一个简单的、迅速生成和执行循环的计算机辅助软件工程(computer-aided software engineering, CASE)。它提示用户给出各种参数,生成代码并执行。

 1 dashes = "
" + "-"*50
 2 exec_dict = {
 3     "f":"""
 4 for %s in %s:
 5     print %s
 6 """,
 7     "s":"""
 8 %s=0
 9 %s = %s
10 while %s < len(%s):
11     print %s[%s]
12     %s = %s + 1
13 """,
14     "n":"""
15 %s = %d
16 while %s < %d:
17     print %s
18     %s = %s + %d
19 """
20     }
21 def main():
22     ltype = raw_input("loop type?(for/while)")
23     dtype = raw_input("data type?(number/seq)")
24     if dtype == "n":
25         start = input("starting value?")
26         stop = input("ending value(non-inclusive)?")
27         step = input("stepping value?")
28         seq = str(range(start, stop, step))
29     else:
30         seq = raw_input("enter sequence:")
31     var = raw_input("iterative variable name?")
32     if ltype == "f":
33         exec_str = exec_dict["f"] % (var, seq, var)
34     elif ltype == "w":
35         if dtype == "s":
36             svar = raw_input("enter sequence name?")
37             exec_str = exec_dict["s"] %
38                        (var, svar, seq, var, svar, svar, var,var,var)
39         elif dtype == "n":
40             exec_str = exec_dict["n"] %
41                        (var, start, var, stop, var, var, var, step)
42     print dashes
43     print "your custom-generated code:" + dashes
44     print exec_str + dashes
45     print "test execution of the code:" + dashes
46     exec exec_str
47     print dashes
48  
49 if __name__ == "__main__":
50     main()
loopmake.py

第二个例子着重描写了在第11章引入的函数属性,它是PEP232中的例子得到的灵感,可以用来进行单元测试

 1 def foo():
 2     return True
 3 def bar():
 4     "bar() does not do much"
 5     return True
 6 foo.__doc__ = "foo() does not do much"
 7 foo.tester = """
 8 if foo():
 9     print "passed"
10 else:
11     print "failed"
12     """
13 for eachAttr in dir():
14     obj = eval(eachAttr)
15     if isinstance(obj, type(foo)):
16         if hasattr(obj, "__doc__"):
17             print "
function '%s' has a doc string:
	%s" % (eachAttr, obj.__doc__)
18         if hasattr(obj, "tester"):
19             print "function '%s' has a tester...executing" % eachAttr
20             exec obj.tester
21         else:
22             print "function '%s' has no tester...skipping" % eachAttr
23     else:
24         print "%s is not a function" % eachAttr
funcAttrs.py

14.4 执行其他Python程序

核心笔记:模块会在导入时执行所有代码,如不希望这样应该在代码中加入 if __name__ == '__main__'。

14.4.2 execfile()

显然,导入模块不是在Python脚本中执行其它Python脚本的最好方法,我们可以使用:

f = open(filename, 'r')

exec f

f.close()

这等价于 execfile(filename)

虽然上述代码执行了一个模块,但是仅仅是在现有的执行环境下运行(比如它自己的全局和局部的名称空间)。在某些情况下可能需要不同全局和局部的名称空间。execfile(filename, globals=globals(), locals=locals())中的globals和locals参数是可选的,如果只给出了globals的值那么locals默认值也与globals一致。如果提供了locals的值,那么这个值必须是一个字典。(由于execfile不会确保不修改局部名称空间,所以在修改时的可靠做法是穿入一个虚假的locals字典以进行检查)。

14.4.3 将模块作为脚本执行

(略)

14.5 执行其他非Python程序

(略)

14.6受限执行

(略)

14.7结束执行

Python中主要有两种方法应对错误,其一是通过异常和异常处理,其二是把处理错误的代码放入if中。

14.7.1 sys.exit() and SystemExit

在调用sys.exit()时,就会引发systemExit()异常。除非对异常进行监控(放在try和except之中),否则异常通常是不会被捕捉或处理的,解释器会用给定的状态参数推出,如果没有给出这个状态参数,该参数默认为0。SystemExit是唯一不被看作错误的异常。

14.7.2 sys.exitfunc()

sys.exitfunc()默认是不可用的,但你可以改写它以提供额外的功能。

14.7.3os._exit()函数

os模块的_exit()函数不应该在一般应用中使用,这个函数的状态参数是必须的,并且不会执行任何清理便立即推出Python。

以下略。

原文地址:https://www.cnblogs.com/autoria/p/4574300.html