標籤: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]]])
import compileallcompileall.compile_dir(dirpath)
dirpath是我們要編譯的的絕對路徑
編譯成 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搜尋路徑
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']
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 模組引用和編譯