Python 模組引用和編譯

來源:互聯網
上載者:User

標籤:linux   init   情況下   解決   程式設計語言   匯入   不用   上層   .so   

Python 編譯

以下是常見Python檔案

  • py 源檔案
  • pyc 源檔案編譯後的檔案
  • pyo 源檔案最佳化編譯後的檔案
  • pyd 其他語言寫的python庫

python並非完全是解釋性語言,它是有編譯的,先把py檔案編譯成pyc或者pyo,然後由python的執行,相對於py檔案來說,編譯成pyc和pyo本質上和py沒有太大區別,只是對於這個模組的載入速度提高了,並沒有提高代碼的執行速度,通常情況下不用主動去編譯pyc檔案,文檔上說只要調用了import 那麼model.py就會先編譯成pyc然後載入

  • 如果需要特殊的單獨編譯,則只需要使用py_complie這個模組就行了,如下
import py_compilepy_compile.compile(r‘H:\\test.py‘)compile原型:compile(file[, cfile[, dfile[, doraise]]])
  • file 表示需要編譯的py檔案的路徑
  • cfile 表示編譯後的pyc檔案名稱和路徑,預設為直接在file檔案名稱後加c 或者 o,o表示最佳化的位元組碼
  • dfile 錯誤訊息儲存的路徑
  • doraise 可以是兩個值,True或者False,如果為True,則會引發一個PyCompileError,否則如果編譯檔案出錯,則會有一個錯誤,預設顯示sys.stderr中,而不會引發異常

  • 如果要把一個檔案夾下的所有py檔案都進行編譯,則用下面的命令

import compileallcompileall.compile_dir(dirpath)

dirpath是我們要編譯的的絕對路徑

  • 如果要編譯pyo檔案則

編譯成 pyo 就是在執行 python -O -m py_compile file.py
其中file.py就是我們要編譯的源檔案

模組引入

模組間相互獨立相互引用是任何一種程式設計語言的基礎能力。對於“模組”這個詞在各種程式設計語言中或許是不同的,但我們可以簡單認為一個程式檔案是一個模組,檔案裡包含了類或者方法的定義。對於編譯型的語言,比如C#中的一個.cs檔案,Java中的一個.java或者編譯後的.class檔案可以認為是一個模組(但常常不表述為模組);對於解釋型的語言會更加直觀些,比如PHP的.php檔案,在Python中就是.py檔案可以認為是一個模組。在“模組”之上有“包”,主要是為了方便組織和管理模組。比如C#中編譯後的.dll檔案(但常常不表述為包Package,而是庫Library),Java將.class打包後的.jar檔案,PHP的.phar檔案(模仿Java包),在Python中一個特殊定義的檔案夾是一個包,可以打包為egg檔案。但對於解釋型語言“包”並沒有編譯成低級語言而後打包的意思,只是更加方便模組化和管理模組間的依賴。每種程式設計語言對於模組和包管理都有一定的約定,不瞭解這些約定,那會給學習這種語言的帶來障礙。下面我想來梳理一下Python的這些約定。

其中Java在有模組相互引用時通常需要到最上層目錄對檔案進行編譯,Python 解譯器命令有一些選項是用於模組引用,下面順帶提提解譯器常用的選項

選項 作用
-d 提供調試輸出
-O 產生最佳化的位元組碼(產生.pyo檔案)
-S 不匯入site模組,以在啟動時自動尋找Python路徑
-v 冗餘輸出
-m mod 將一個模組以指令碼的方式運行
-Q opt 除塵選項
-c cmd 運行系統命令,一般是shell內部命令
import 語句模組的引入

模組定義好後,我們可以使用 import 語句來引入模組,文法如下:

import module1[, module2[,... moduleN]

比如要引用模組 math,就可以在檔案最開始的地方用 import math 來引入。在調用 math 模組中的函數時,必須這樣引用:

模組名.函數名

當解譯器遇到 import 語句,如果模組在當前的搜尋路徑就會被匯入。

搜尋路徑是一個解譯器會先進行搜尋的所有目錄的列表。如想要匯入模組 support.py,需要把命令放在指令碼的頂端:

support.py:

def print_func( par ):   print "Hello : ", par   return

引用檔案:

#!/usr/bin/python# -*- coding: UTF-8 -*- # 匯入模組import support # 現在可以調用模組裡包含的函數了support.print_func("Runoob")

以上執行個體輸出結果:

Hello : Runoob

一個模組只會被匯入一次,不管你執行了多少次import。這樣可以防止匯入模組被一遍又一遍地執行。

From…import

Python 的 from 語句讓你從模組中匯入一個指定的部分到當前命名空間中。文法如下:

from modname import name1[, name2[, ... nameN]]

例如,要匯入模組 fib 的 fibonacci 函數,使用如下語句:

from fib import fibonacci

這個聲明不會把整個 fib 模組匯入到當前的命名空間中,它只會將 fib 裡的 fibonacci 單個引入到執行這個聲明的模組的全域符號表。

From…import*

把一個模組的所有內容全都匯入到當前的命名空間也是可行的,只需使用如下聲明:

from modname import *

這提供了一個簡單的方法來匯入一個模組中的所有項目。然而這種聲明不該被過多地使用。

例如我們想一次性引入 math 模組中所有的東西,語句如下:

from math import *
搜尋路徑

當你匯入一個模組,Python 解析器對模組位置的搜尋順序是:

  • 目前的目錄
  • 如果不在目前的目錄,Python 則搜尋在 shell 變數 PYTHONPATH 下的每個目錄。
  • 如果都找不到,Python會察看預設路徑。UNIX下,預設路徑一般為/usr/local/lib/python/。

模組搜尋路徑儲存在 system 模組的 sys.path 變數中。變數裡包含目前的目錄,PYTHONPATH和由安裝過程決定的預設目錄。可以列印看看Python搜尋路徑

  • Windows
In [1]: import sys                                                                                                                In [2]: sys.path                                                 Out[2]:                                                          ['',                                                              'D:\\Dev\\Anaconda3\\Scripts',                                   'D:\\Dev\\Anaconda3\\python36.zip',                              'D:\\Dev\\Anaconda3\\DLLs',                                      'D:\\Dev\\Anaconda3\\lib',                                       'D:\\Dev\\Anaconda3',                                            'D:\\Dev\\Anaconda3\\lib\\site-packages',                        'D:\\Dev\\Anaconda3\\lib\\site-packages\\Babel-2.5.0-py3.6.egg', 'D:\\Dev\\Anaconda3\\lib\\site-packages\\win32',                 'D:\\Dev\\Anaconda3\\lib\\site-packages\\win32\\lib',            'D:\\Dev\\Anaconda3\\lib\\site-packages\\Pythonwin',             'D:\\Dev\\Anaconda3\\lib\\site-packages\\IPython\\extensions',   'C:\\Users\\oneTO\\.ipython']                                   
  • Linux
In [1]: import sysIn [2]: sys.pathOut[2]: ['', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/bin', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python36.zip', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python3.6', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python3.6/lib-dynload', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python3.6/site-packages', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python3.6/site-packages/IPython/extensions', '/home/whoami/.ipython']

也可以通過sys模組的append方法在Python環境中增加搜尋路徑

In [3]: sys.path.append('/home/whoami/DjangoEnv/')In [4]: sys.pathOut[4]: ['', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/bin', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python36.zip', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python3.6', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python3.6/lib-dynload', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python3.6/site-packages', '/home/whoami/.pyenv/versions/anaconda3/envs/my-r-env/lib/python3.6/site-packages/IPython/extensions', '/home/whoami/.ipython', '/home/whoami/DjangoEnv/']
PYTHONPATH 變數

作為環境變數,PYTHONPATH 由裝在一個列表裡的許多目錄組成。PYTHONPATH 的文法和 shell 變數 PATH 的一樣。

在 Windows 系統,典型的 PYTHONPATH 如下:

set PYTHONPATH=c:\python27\lib;

在 UNIX 系統,典型的 PYTHONPATH 如下:

set PYTHONPATH=/usr/local/lib/python
Python中的包

包是一個分層次的檔案目錄結構,它定義了一個由模組及子包,和子包下的子包等組成的 Python 的應用環境。

簡單來說,包就是檔案夾,但該檔案夾下必須存在 __init__.py 檔案, 該檔案的內容可以為空白。__int__.py用於標識當前檔案夾是一個包。

pkg0├── __init__.py├── main.py├── pkg1│   ├── A.py│   └── __init__.py└── pkg2    ├── B.py    └── __init__.py
引用子目錄的包

main.py中引用package2/B的方法

# main.pyfrom pkg2 import BB.someMethod()

這個寫法很糟糕,但能解決目前問題。糟糕的地方在於隱晦的引入pkg2。更好的方式是相對參照。

from .pkg2 import BB.someMethod()

但如果用 python pkg0/main.py 執行會報錯,此處原因請參考這。原因是相對參照預設作為包的方式才能運行。

正確執行方法(linux shell下): python -m pkg0.main

這個寫法也不夠好!B 在具體的程式碼,看不出其出處。更好的方式是

from . import t2pkg2.B.someMethod()

但運行時會報錯!

AttributeError: ‘module‘ object has no attribute ‘B‘

大致意思是, 模組對象沒有B屬性!這點從java/.net轉過來的也許有一點不習慣!

python引入一個模組(import m) <==> 引入m/__init__.py檔案,所以可以在m/__init__.py引入本地模組

import B-or-from . import B

這樣就能解決在運行上層檔案main.py時引用下層模組不會報錯了。

跨目錄引用

pkg1.__init__.py 中 import 本地模組

from . import A

然後在模組 pkg2.B 中可以這樣引用模組 pkg1.A

from .. import pkg1pkg1.A.someMethod()

其中 ... 有點類似於Linux檔案路徑的意思。

Python 模組引用和編譯

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.