zoukankan      html  css  js  c++  java
  • 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。

    以下略。

  • 相关阅读:
    一个bug案例分析
    《需求工程》阅读随笔-1.做什么和怎么做
    连贯接口(fluent interface)的Java实现及应用。
    代码覆盖率检测工具大全
    腾讯的一个移动端测试小工具GT
    用复制mysql/data 文件夹 下面的数据库的形式来复制数据库出现的问题
    淘客API升级后的解决方案,怎么采集淘宝的商品数据
    方维团购系统,给供货商添加省市地址
    支付宝担保交易收款接口使用
    方维分享系统首页,插入新品,用来做优化
  • 原文地址:https://www.cnblogs.com/autoria/p/4574300.html
Copyright © 2011-2022 走看看