📄 node8.html
字号:
<p> 当你import一个叫做 <tt class="module">spam</tt> 的module时,直译器会先在目前的目录寻找一个叫做 <span class="file">spam.py</span> 的档案,如果没找到,会再依据定义在 <a class="envvar" name="l2h-10">$PYTHONPATH</a> (一个环境变数)里面的所有路径来找。 <a class="envvar" name="l2h-10">$PYTHONPATH</a> 的语法与设定方法与 <a class="envvar" name="l2h-11">$PATH</a> 是一样的,也就是一连串的目录路径的名称。如果你没有设定 <a class="envvar" name="l2h-12">$PYTHONPATH</a> ,或是在这些目录当中也找不到的话,直译器会继续在一个安装时预设的目录来找,在Unix的机器上,通常这个目录是 <span class="file">.:/usr/local/lib/python</span> 。 </p> <p> 事实上,module的搜寻路径是依照存在 <code>sys.path</code> 这一个变数中的一个许多路径名称组成的list。这个变数当在Python直译器启动时,会从输入的script(或目前的目录)、 <a class="envvar" name="l2h-13">$PYTHONPATH</a> 、以及安装时设定的预设目录来读取所有的目录。如果你知道自己在做什么的话,你可以修改这个变数来改变直译器寻找module的路径。请参阅之后的标准模组(standardmodule)一段。 </p> <p> </p> <h2><a name="SECTION008120000000000000000"> 6.1.2 “编译过的”(``Compiled'') Python档案 </a> </h2> <p> 对于一些小的程式来说,如果使用很多标准的module,而又想加速启动的过程,你就可以用编译过的Python档案。比如你要找 <span class="file">spam.py</span> ,如果在你找到这个档案的目录里ey4又有一个叫做 <span class="file">spam.pyc</span> 的档案的话,这就表示 <tt class="module">spam</tt> 这个module有一个已经二元编译过的(``byte-compiled'')的版本可以使用。在 <span class="file">spam.pyc</span> 里面也会记录用来创造它的spam.py上一次被修改的时间,如果 <span class="file">.pyc</span> 里面所储存的时间与最新版本的 <span class="file">.py</span> 的修改时间不符合的话, <span class="file">.pyc</span> 档案就不会被使用。 </p> <p> 一般来说,你不需要做任何事来创造一个 <span class="file">spam.pyc</span> 档案。当你成功的编译一个 <span class="file">spam.py</span> 档时,自动的 <span class="file">spam.pyc</span> 档就会写入在同一个目录里。如果这个过程里有问题的话,系统不会当这是个错误情况(error)。相反的,如果写入的档案没有完全成功的写入的话,这个档案只会被认为是不正确的而忽视其存在。 <span class="file">spam.pyc</span> 档案的内容是独立于作业系统平台的,所以一个 Python module 的目录是可以被在各种不同架构下的多台机器所共享的。 </p> <p> 这里有一些给专家们的秘诀: </p> <p> </p> <ul> <li>当使用 <b class="programopt">-O</b> 这个选项启动Python直译器时,直译器产生会最佳化程式码(optimizedcode),并存在 <span class="file">.pyo</span> 档案里。这个最佳化程式码目前并没有太多功能,它只是简单的拿掉所有的 <tt class="keyword">assert</tt> 叙述以及 <code>SET_LINENO</code> 指令。当你使用 <b class="programopt">-O</b> 这个选项时, <i>所有的</i> 二元码(bytecode)都会被最佳化,所有的 <code>.pyc</code> 档都会被忽略,所有的 <code>.py</code> 档案都会被编译成最佳化的二元码。 <p> </p> </li> <li>如果你传入两个 <b class="programopt">-O</b> 选项给Python直译器的话 (<b class="programopt">-OO</b>) ,在有些很少见的情况下会使得编译器的最佳化过程使得程式无法正常执行。目前这个选项会使得 <code>__doc__</code> 字串从二元码中被拿掉,进而使得 <span class="file">.pyo</span> 档案可以更精简。但是有些程式会使用到这些字串,所以你应该只有在你很确定时才使用这个选项。 <p> </p> </li> <li>读 <span class="file">.pyc</span> 以及 <span class="file">.pyo</span> 档案并不会比读 <span class="file">.py</span> file; the only thing that'sfaster about <span class="file">.pyc</span> or <span class="file">.pyo</span> 档还要快,唯一的差距是在当被导入(load)时的速度有差别。 <p> </p> </li> <li>当你在命令列(command line)使用script的名称来执行它的话,并不会造成二元码被写到 <span class="file">.pyc</span> 或是 <span class="file">.pyo</span> 所以,你可以把这个script写成一个module,然后再用一个小的启动的script来import这个module。这样可以减少启动的时间。事实上,你也可以直接从命令列启动 <span class="file">.pyc</span> 或是 <span class="file">.pyo</span> 档案。 <p> </p> </li> <li>你也可以把 <span class="file">spam.pyc</span> (或是 <span class="file">spam.pyo</span> ,如果你用了 <b class="programopt">-O</b> 的话) 放在没有 <span class="file">spam.py</span> 的目录里。这样子,当你给别人你的程式库时,你可以给他们比较难用逆向工程(reverse engineer)破解的程式。 <p> </p> </li> <li>你可以用 <tt class="module">compileall</tt> 这个module来将某个目录里面的所有module都便成 <span class="file">.pyc</span> 档案(或者是 <span class="file">.pyo</span> 档案,如果你用了 <b class="programopt">-O</b> )。 <p> </p> </li> </ul> <p> </p> <h1> <br> 6.2 标准模组 </h1> <p> Python包含有一个 标准模组的程式库,这个程式库在另一个文件 <em class="citetitle"><a href="../lib/lib.html" title="Python Library Reference">Python Library Reference</a></em> (Python程式库参考手册)中有更多的描述。有些标准模组已经内建在直译器里面,这些模组让我们可以使用那些不在Python语言本身的一些功能,不管是为了效率或是要使用作业系统的资源(例如systemcall)。有些module是在设定时的选项,比如说, <tt class="module">amoeba</tt> 这个module就只有在你的系统里面有Amoeba相关的资源时才会出现。有一个module特别值得我们好好注意: <tt class="module">sys</tt> 。这个module在每一个Python直译器里面都有,其中有两个变数 <code>sys.ps1</code> 以及 <code>sys.ps2</code> 是用来设定primary prompt以及secondary prompt的: </p> <p> </p> <dl> <dd><pre class="verbatim">>>> import sys<br>>>> sys.ps1<br>'>>> '<br>>>> sys.ps2<br>'... '<br>>>> sys.ps1 = 'C> '<br>C> print 'Yuck!'<br>Yuck!<br>C><br></pre> </dd> </dl> <p> 这两个变数只有在当你在互动模式下启动直译器时才有定义。 </p> <p> <code>sys.path</code> 这个变数是一个许多目录路径组成的list,里面的目录路径就是直译器寻找module的路径。这个变数里面的路径都是从环境变数 <a class="envvar" name="l2h-16">$PYTHONPATH</a> 里面复制的,或者当 <a class="envvar" name="l2h-17">$PYTHONPATH</a> 没有设定时,就会使用预设值。你也可以用一般使用list的方法来修改之。例如: </p> <p> </p> <dl> <dd><pre class="verbatim">>>> import sys<br>>>> sys.path.append('/ufs/guido/lib/python')<br></pre> </dd> </dl> <p> </p> <h1> <br> 6.3 <tt class="function">dir()</tt> 函式 </h1> <p> 内建的 <tt class="function">dir()</tt> 函式主要是用来找出某个module里面所定义的所有名称。其传回值是一串经过排序了的字串list: </p> <p> </p> <dl> <dd><pre class="verbatim">>>> import fibo, sys<br>>>> dir(fibo)<br>['__name__', 'fib', 'fib2']<br>>>> dir(sys)<br>['__name__', 'argv', 'builtin_module_names', 'copyright', 'exit',<br>'maxint', 'modules', 'path', 'ps1', 'ps2', 'setprofile', 'settrace',<br>'stderr', 'stdin', 'stdout', 'version']<br></pre> </dd> </dl> <p> 如果没有传入参数的话, <tt class="function">dir()</tt> 会列出所有你目前已经定义的名称: </p> <p> </p> <dl> <dd><pre class="verbatim">>>> a = [1, 2, 3, 4, 5]<br>>>> import fibo, sys<br>>>> fib = fibo.fib<br>>>> dir()<br>['__name__', 'a', 'fib', 'fibo', 'sys']<br></pre> </dd> </dl> <p> 注意这里的名称是指所有类型的名称:包括变数,函式,以及module等等。 </p> <p> <tt class="function">dir()</tt> 并没有列出所有内建的函式及变数的名称。如果你真想要列出来的话,它们都定义在 <tt class="module">__builtin__</tt> 这个标准module里面: </p> <p> </p> <dl> <dd><pre class="verbatim">>>> import __builtin__<br>>>> dir(__builtin__)<br>['AccessError', 'AttributeError', 'ConflictError', 'EOFError', 'IOError',<br>'ImportError', 'IndexError', 'KeyError', 'KeyboardInterrupt',<br>'MemoryError', 'NameError', 'None', 'OverflowError', 'RuntimeError',<br>'SyntaxError', 'SystemError', 'SystemExit', 'TypeError', 'ValueError',<br>'ZeroDivisionError', '__name__', 'abs', 'apply', 'chr', 'cmp', 'coerce',<br>'compile', 'dir', 'divmod', 'eval', 'execfile', 'filter', 'float',<br>'getattr', 'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'len', 'long',<br>'map', 'max', 'min', 'oct', 'open', 'ord', 'pow', 'range', 'raw_input',<br>'reduce', 'reload', 'repr', 'round', 'setattr', 'str', 'type', 'xrange']<br></pre> </dd> </dl> <p> </p> <h1> <br> 6.4 Packages(包装) </h1> <p> Package是一种用点号表示模组名称(``dotted module names'')的组织Python模组(module)命名空间的方法。举例来说:如果module的名称是 <tt class="module">A.B</tt> 表示是在 "<tt class="samp">B</tt>" 这个package里面的一个名称为 "<tt class="samp">A</tt>" 的module。就如同使用module使得其他写module的不用担心别人的globalvariable命名的问题,使用这种带点号的module名称也使得写多个module的package的人不用担心所用的module名称会和别人有所重复。 </p> <p> 现在假设你要设计一组的module(就是设计一个package),这个package是用来标准化的处理声音档案以及声音的资料的。由于声音档的格式有很多(通常是由其延伸档名来辨别,例如 <span class="file">.wav</span>, <span class="file">.aiff</span>, <span class="file">.au</span>) 等格式),你也许需要一个随时会增加新module的package来处理新的声音档格式。由于你可能想对声音资料做各种不同的处理(例如混音、加回声、加入平衡方程式,加入人工音响效果等等),所以你还需要写一些module来专门做这些处理。底下这个架构可能是你的package所需要的(用档案阶层系统来表示): </p> <p> </p> <dl> <dd><pre class="verbatim">Sound/ Top-level package<br> __init__.py Initialize the sound package<br> Formats/ Subpackage for file format conversions<br> __init__.py<br> wavread.py<br> wavwrite.py<br> aiffread.py<br> aiffwrite.py<br> auread.py<br> auwrite.py<br> ...<br> Effects/ Subpackage for sound effects<br> __init__.py<br> echo.py<br> surround.py<br> reverse.py<br> ...<br> Filters/ Subpackage for filters<br> __init__.py<br> equalizer.py<br> vocoder.py<br> karaoke.py<br> ...<br></pre> </dd> </dl> <p> 为使Python能把这个目录架构当作是一个package,上面的 <span class="file">__init__.py</span> 这个档是必须要的。这是为了要避免有些档案目录的名字是很普通的名字(例如 "<tt class="samp">string</tt>" ),这会让直译器误认正确的module名称而找不到在搜寻路径中的module。在最简单的例子里, <span class="file">__init__.py</span> 可以是一个空的档案。但是你也可以让这个档来做一些package初始化的动作,或者设定 <code>__all__</code> 这个变数(稍后会再提)。 </p> <p> 使用package的人可以从package里使用(import)某一个module,例如: </p> <p> </p> <dl> <dd><pre class="verbatim">import Sound.Effects.echo<br></pre> </dd> </dl>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -