14 执行环境 - 《Python 核心编程》

􀁺 可调用对象
􀁺 代码对象
􀁺 语句和内置函数
􀁺 执行其他程序
􀁺 终止执行
􀁺 各类操作系统接口
􀁺 相关模块
14.1 可调用对象
    许多的python 对象都是我们所说的可调用的,即是任何能通过函数操作符“()”来调用的对象。
    要调用可调用对象,函数操作符得紧跟在可调用对象之后。
    可调用对象可以通过函数式编程接口来进行调用,如apply(),filter(),map(),以及reduce()。
    Python 有4 种可调用对象:函数,方法,类,以及一些类的实例。 这些对象的任何引用或者别名都是可调用的。
函数
    内建函数(BIFs)
        BIF 是用c/c++写的,编译过后放入python 解释器,然后把它们作为第一(内建)名字空间的 一部分加载进系统。
        这些函数在_bulitin_模块里,并作为__builtins__模 块导入到解释器中。
        从内部机制来看,因为BIFs 和内建方法(BIMs)属于相同的类型。
        内建函数的特殊属性
            BIF 属性                描述
            bif.__doc__           文档字符串(或None)
            bif.__name__        字符串类型的文档名字
            bif.__self__            设置为None(保留给built-in 方法)
            bif.__module__     存放bif 定义的模块名字(或None)
    用户定义的函数(UDF)
        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 中使用,但在别 处定义;)
    lambda 表达式和用户自定义对函数
        lambda 表达式也返回一个函数对象,但是lambda 表达式不是用def 语句创建的,而是用lambda 关键字。
        lambda 表达式没有给命名绑定的代码提供基础结构,变量仅是个别名, 并不是函数对象的名字。
        通过lambda 来创建函数的对象和用户自定义函数具有相同的属性;__name__ 或者func_name 属性给定为字符串"<lambda>"。
            >>> def f():
            ... pass
            ...
            >>> b = lambda : 1
            >>> f.func_name
            'f'
            >>> type(f)
            <type 'function'>
            >>> b.func_name
            '<lambda>'
            >>> type(b)
            <type 'function'>
            >>>
方法
    用户自定义方法是被定义为类的一部分的函数。
    许多python 数据 类型,比如列表和字典,也有方法,这些被称为内建方法。
    为了进一步说明“所有权“的类型,方法通过对象的名字和句点属性标识进行命名。
    内建方法(BIMs)
        只有内建类型(BIT)有BIM.
        BIM 和BIF 两者也都享有相同属性,不同之处在于BIM 的__self__属性指向一个Python 对象,而BIF 指向None。
            >>> help({}.keys)
            Help on built-in function keys:
           
            keys(...)
                D.keys() -> list of D's keys
           
            >>>
 
       
    用户定义的方法(UDM)
        UDM(User-defined method,用户定义的方法)包含在类定义之中,只是拥有标准函数的包装, 仅有定义它们的类可以使用,如果没有在子类定义中被覆盖掉,也可以通过子类实例来调用它们。
        UDM 与类对象是关联的(非绑定方法),但是只能通过类的实例来调用(绑 定方法)。
        UDMs 无论是否绑定,所有的UMD 都是相同的类型——“实例方法“。
            >>> class C(object):    # define class
            ... def f(self):    # define UDM
            ... pass
            ...
            >>> c = C()    # instantiation
            >>> type(c.f)    # type of bound method
            <type 'instancemethod'>
            >>> type(C.f)    # type of unbound method
            <type 'instancemethod'>
            >>> C.f
            <unbound method C.f>
            >>> c.f
            <bound method C.f of <__main__.C object at 0x00000000026FF9E8>>
            >>>
           
           
    "调用”类的结果便是创建了实例,即大家所知道的实 例化。
    程序员可以通过实现 __int__()方法,来自定义实例化过程,实例化调用的任何参数都会传入到构造函数里。
类的实例
        python 给类提供了名为__call__的特别方法,该方法允许程序员创建可调用的对象(实例)。默
    认情况下,__call__()方法是没有实现的,这意味着大多数实例都是不可调用的。然而,如果在类
    定义中覆盖了这个方法,那么这个类的实例就成为可调用的了。调用这样的实例对象等同于调用
    __call__()方法。自然地,任何在实例调用中给出的参数都会被传入到__call()__中。……那么foo()
    就和foo.__call__(foo)的效果相同, 这里foo 也作为参数出现,因为是对自己的引用,实例将自
    动成为每次方法调用的第一个参数。如果 ___call___()有参数,比如,(self, arg),那么foo(arg)
    就和调用foo.__call__(foo, arg)一样。
    记住只有定义类的时候实现了__call__方法,类的实例才能成为可调用的。
        >>> class C(object):
        ... def __call__(self, *args):
        ... print "I'm callable ! Called withe args:\n", args
        ...
        >>> c = C() # instantiation
        >>> c # our instance
        <__main__.C object at 0x00000000025281D0>
        >>> callable(c) # instance is callable
        True
        >>> c() # instance invoked
        I'm callable ! Called withe args:
        ()
        >>> c('hello', 'callable objects') # invoked with arguments
        I'm callable ! Called withe args:
        ('hello', 'callable objects')
        >>>
14.2 代码对象
    python 语句,赋值, 表达式只是构成可执行代码块的拼图的很小一部分,无法像可调用物那样被调用,这些代码块被称为代码对象。
    每个可调用物的核心都是代码对象,由语句,赋值,表达式,以及其他可调用物组成。
    一般说来,代码对象可以作为函数或者方法调用的一部分来执行,也可用exec 语句或内建函数 eval()来执行。
    从整体上看,一个python 模块的代码对象是构成该模块的全部代码。
    函数对象仅是代码对象的包装,方法则是 给函数对象的包装。
14.3 可执行的对象声明和内建函数
    Python 提供了大量的BIF 来支持可调用/可执行对象,其中包括exec 语句。
    这些函数帮助程序 员执行代码对象,也可以用内建函数complie()来生成代码对象。
   
callable()
    callable()是一个布尔函数,确定一个对象是否可以通过函数操作符(())来调用。
    如果函数可 调用便返回True,否则便是False。
        >>> callable(dir)
        True
        >>> callable(1)
        False
        >>> def foo():pass
        ...
        >>> callable(foo)
        True
        >>> class C(object):
        ... def __call__(self):
        ... pass
        ...
        >>> c = C()
        >>> callable(c)
        True
        >>>
compile()
   
    可求值表达式
        >>> eval_code = compile('100 + 200', '', 'eval')
        >>> eval_code
        <code object <module> at 00000000025301B0, file "", line 1>
        >>>
        >>> eval(eval_code)
        300
    单一可执行语句
        >>> single_code = compile('print "Hello world!"', '', 'single')
        >>> single_code
        <code object <module> at 00000000026FDBB0, file "", line 1>
        >>> exec single_code
        Hello world!
        >>> eval(single_code)
        Hello world!
        >>>
    可执行语句组
        >>> exec_code = compile("""
        ... req = input('Count how many numbers? ')
        ... for eachNum in range(req):
        ... print eachNum
        ... """, '', 'exec')
        >>> exec_code
        <code object <module> at 00000000026FD9B0, file "", line 2>
        >>> exec exec_code
        Count how many numbers? 3
        0
        1
        2
        >>> eval(exec_code)
        Count how many numbers? 5
        0
        1
        2
        3
        4
        >>>
eval()
    eval()对表达式求值,后者可以为字符串或内建函数complie()创建的预编译代码对象。
    第二个和第三个参数,都为可选 的,分别代表了全局和局部名字空间中的对象。
        如果给出这两个参数,globals 必须是个字典,locals可以是任意的映射对象,比如,一个实现了__getitem__()方法的对象。
        如果都没给出这两个参数,分别默认为globals()和locals()返回的对象,如果只传入 了一个全局字典,那么该字典也作为locals 传入。
exec
    exec 语句执行代码对象或字符串形式的python 代码, 还可以接受有效的python 文件对象。
    通用语法:
        exec obj
        被执行的对象(obj)可以只是原始的字符串,比如单一语句或是语句组,它们也可以预编译成 一个代码对象(分别用'single'和'exec"参数)。
        >>> f = file('xcount.py.txt', 'r')
        >>> exec f
        Enter your number? 1
        0
        1
        >>> from os.path import getsize
        >>> getsize(f.name)
        83L
        >>> f.tell()
        83L
        >>> f.close()
        >>>   
input()
    内建函数input()是eval()和raw_input()的组合,等价于eval(raw_input())。
        >>> type(raw_input())
        1
        <type 'str'>
        >>> type(input())
        1
        <type 'int'>
        >>>
14.4 执行其他(Python)程序
    我们把其他程序分类为python 程序和其他所有的非python 程序,后者包 括了二进制可执行文件或其他脚本语言的源代码。
导入
    第一次导入模块会执行模块最高级的代码。
    不管你是否需要,这就是python 导入的行为。
    提醒,只有属于模块最高级的代码才是全局变量,全局类,和全局函数声明。
                核心笔记:当模块导入后,就执行所有的模块
        这只是一个善意的提醒:在先前的第3 章和第12 章已经谈过了,现在再说一次,当导入python
        模块后,就执行所有的模块!当导入python 模块后,会执行该模块!当你导入foo 模块时候,它运行
        所有最高级别的(即没有缩进的)python 代码,比如,'main()’。如果foo 含有bar 函数的声明,
        那么便执行def foo(...)。再问一次为什么会这样做呢?…… 由于某些原因,bar 必须被识别为foo
        模块中一个有效的名字,也就是说bar 在foo 的名字空间中,其次,解释器要知道它是一个已声明
        的函数,就像本地模块中的任何一个函数。现在我们知道要做什么了,那么如何处理那些不想每次
        导入都执行的代码呢?缩进它,并放入if __name__ == '__main__' 的内部。
execfile()
    导入模块不是从另外的python 脚本中执行python 脚本最可取的方法。
    导入模块的副作用是导致最高级代码运行。
    execfile() 函数的语法非常类似于eval()函数的。
        execfile(filename[, globals[, locals]])
            >>> execfile('xcount.py')
            Enter your number? 2
            0
            1
            2
            module.name = __main__
            >>>
将模块作为脚本执行
    python2.4 里加入了一个新的命令行选项(或开关),允许从shell 或DOS 提示符,直接把模块 作为脚本来执行。
14.5 执行其他(非Python)程序
        在python 程序里我们也可以执行非python 程序。这些程序包括了二进制可执行文件,其他的
    shell 脚本等等。所有的要求只是一个有效的执行环境,比如,允许文件访问和执行,脚本文件必须
    能访问它们的解释器(perl, bash,等等),二进制必须是可访问的(和本地机器的构架兼容) 。
    最终,程序员必须考虑python 脚本是否必须和其他将要执行的程序通信。
           
           
os.system()
    system() 函数,接收字符串形式的系统命令并执行它。
    当执行命令的时候,python 的运行是挂起的,当我们的执行完成之后,将会以system()的返回值形式给出退出状态,python 的执行也会继续。
    system()通常和不会产生输出的命令一起使用,其中的一些命令包括了压缩或转换文件的程序,挂载磁盘到系统的程序,或其他执行特定任务的命令。
        ---通过退出状态显示成功或失败而不是通过输入和/或输出通信。
        ---通常的约定是利用退出状态,0 表示成功,非零表示其他类型的错误。
            >>> os.listdir(os.getcwd())
            ['DF_BQ_1.0', 'hello.cs', 'hello.dll']
            >>> os.system('dir')
             Volume in drive E has no label.
             Volume Serial Number is 163D-BE02
           
             Directory of E:\csharp
           
            05/30/2014 08:25 <DIR> .
            05/30/2014 08:25 <DIR> ..
            05/16/2014 20:58 <DIR> DF_BQ_1.0
            05/30/2014 08:29 337 hello.cs
            05/30/2014 08:24 3,072 hello.dll
                           2 File(s) 3,409 bytes
                           3 Dir(s) 119,161,438,208 bytes free
            0
            >>> os.system('uname -a')
            'uname' is not recognized as an internal or external command,
            operable program or batch file.
            1
            >>>
os.popen()
    popen()函数是文件对象和system()函数的结合,popen()返回一个类文件对象,建立一个指向那个程序的单向连接,然后如访问文件一样访问这个程序。
        >>> import os
        >>> f = os.popen('dir')
        >>> for l in f:
        ... l
        ...
        ' Volume in drive E has no label.\n'
        ' Volume Serial Number is 163D-BE02\n'
        '\n'
        ' Directory of E:\\csharp\n'
        '\n'
        '05/30/2014 08:25 <DIR> .\n'
        '05/30/2014 08:25 <DIR> ..\n'
        '05/16/2014 20:58 <DIR> DF_BQ_1.0\n'
        '05/30/2014 08:29 337 hello.cs\n'
        '05/30/2014 08:24 3,072 hello.dll\n'
        ' 2 File(s) 3,409 bytes\n'
        ' 3 Dir(s) 119,161,438,208 bytes free\n'
        >>>
os.fork(), os.exec*(),os.wait*()        
        
os.spawn*()
 
subprocess 模块
    替换 os.system() call()的函数取代了os.system()       
 1 >>> from subprocess import call
 2 >>> call(('dir', r'd:\tmp'), shell=True)
 3  Volume in drive D is LENOVO
 4  Volume Serial Number is C0E1-9EE6
 5 
 6  Directory of d:\tmp
 7 
 8 08/18/2015  17:43    <DIR>          .
 9 08/18/2015  17:43    <DIR>          ..
10 08/17/2015  12:07    <DIR>          build
11 08/17/2015  12:07            72,020 hello.c
12 08/17/2015  12:07            12,800 hello.pyd
13 08/17/2015  12:01                81 hello.pyx
14 08/18/2015  11:59               710 mtsleep2.py
15 08/18/2015  17:43               907 mtsleep4.py
16 08/18/2015  16:51               937 mysleep3.py
17 08/17/2015  12:02               151 setup.py
18 08/18/2015  11:38               802 threadingdemo.py
19 08/17/2015  12:05    <DIR>          venv
20                8 File(s)         88,408 bytes
21                4 Dir(s)  769,548,058,624 bytes free
22 0
23 >>>
    取代os.popen() 创建Popen()实例的取代调用os.popen()函数
            >>> from subprocess import Popen, PIPE
            >>> f = Popen(('uname', '-a'), stdout=PIPE).stdout
            >>> data = f.readline()
            >>> f.close()
            >>> print data,
            Linux starship 2.4.18-1-686 #4 Sat Nov 29 10:18:26 EST 2003 i686
            GNU/Linux
相关函数
   
14.6 受限执行
        在python 历史某个时期内,存在着使用了rexec 和bastion 模块的限制执行的概念。第一个
    模块允许沙盒(sandbox)中的执行代码修改内建对象。第二个模块用来过滤属性和包装你的类。然
    而,由于一个显著的缺点和弥补安全漏洞的困难,这些模块便被废弃了。那些维护使用了这些模块
    的老代码的人员可能会用到这两个模块的文档。
14.6 结束执行
        当程序运行完成,所有模块最高级的语句执行完毕后退出,我们便称这是干净的执行。可能有
    很多情况,需要从python 提前退出,比如某种致命错误,或是不满足继续执行的条件的时候。
        在python 中,有各种应对错误的方法。其中之一便是通过异常和异常处理。另外一个方法便是
    建造一个“清扫器”方法,这样便可以把代码的主要部分放在if 语句里,在没有错误的情况下执行,
    因而可以让错误的情况“正常地“终结。然而,有时也需要在退出调用程序的时候,返回错误代码
    以表明发生何种事件。
sys.exit() and SystemExit
    立即退出程序并返回调用程序的主要方式是sys 模块中的exit()函数。
    sys.exit()的语法为:
        sys.exit(status=0) 
    当调用sys.exit()时,就会引发systemExit()异常。
    除非对异常进行监控(在一个try 语句和 合适的except 子句中),异常通常是不会被捕捉到或处理的,解释器会用给定的状态参数退出,如果没有给出的话,该参数默认为0。
    System Exit 是唯一不看作错误的异常。它仅仅表示要退出python 的愿望。 
    sys.exit()经常用在命令调用的中途发现错误之后,比如,如果参数不正确,无效,或者参数 数目不正确。
sys.exitfunc()
        sys.exitfunc()默认是不可用的,但你可以改写它以提供额外的功能。当调用了sys.exit()并
    在解释器退出之前,就会用到这个函数了。这个函数不带任何参数的,所以你创建的函数也应该是
    无参的。
        如果sys.exitfunc 已经被先前定义的exit 函数覆盖了,最好的方法是把这段代码作为你exit()
    函数的一部分来执行。一般说来,exit 函数用于执行某些类型的关闭活动,比如关闭文件和网络连
    接,最好用于完成维护任务,比如释放先前保留的系统资源。
os._exit()
    os 模块的_exit()函数不应该在一般应用中使用。(平台相关,只适用特定的平台,比如基于Unix 的平台,以及Win32 平台)。
    其语法为: 
        os._exit(status)
        这个函数提供的功能与sys.exit()和sys.exitfunc()相反,根本不执行任何清理便立即退出
        python。与sys.exit()不同,状态参数是必需的。通过sys.exit()退出是退出解释器的首选方法。
os.kill()
    os 模块的kill()函数模拟传统的unix 函数来发送信号给进程。
    kill()参数是进程标识数(PID) 和你想要发送到进程的信号。
    发送的典型信号为SIGINT, SIGQUIT,或更彻底地,SIGKILL,来使进程终结。
14.8 各种操作系统接口
    
   
 
   
 
 
 
 
 
posted @ 2015-08-18 18:22  小麦粉  阅读(520)  评论(0编辑  收藏  举报