import 本地Python module或package


很基礎很重要的一課,雖然很簡單,但是防止以后忘了,還是記下來

這個筆記里說的都是import本地的,自己創建的,或者復制粘貼的別人的,總之“不是安裝到library”的module or package, 所以標題里有個大寫的LOCAL

module

  • what’s a module ?
    It’s just a python file

  • why do we need?
    Because we wanna re-use code, your own code or someone others’

  • dir() 用於在Python interpreter shell中展示當前的namespace,namespace這個詞真是好久不見

  • import LOCAL module

print name會打印這個.py文件的名字

➜ Desktop pwd
/Users/harry/Desktop
➜ Desktop more test_function.py
print __name__
a = 100
def some_func():
  print "hello"
  print "world"
  print a
➜ Desktop

這個例子是引入本地的某個module,module其實是一個.py文件,所以這個例子一定要在同一個目錄下做,我選了Desktop目錄

➜ Desktop python
Python 2.7.5 (default, Mar 9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import test_function  # 第一種方式,直接寫名字
test_function 
>>># 每次引入一個module,你當前的Python interpreter都會把這個module的代碼逐行執行,所以這里有一個test_function的輸出,因為源文件里有個 print __name__
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'test_function']
>>>
>>> test_function.some_func()
hello
world
100
>>> test_function.b = 77  # 注意這個地方,雖然原來的test_function.py里沒有這個叫b的變量,但是其實可以給它賦值
>>>
>>> test_function.b
77
>>>  
>>> from test_function import some_func
>>> 
>>> some_func()
hello
world
100
>>> dir() # 這次的namespace里就會多了這個some_func()
['__builtins__', '__doc__', '__name__', '__package__', 'some_func', 'test_function']  
>>>
  • as 關鍵詞,更名被你引入的module
➜ Desktop python
Python 2.7.5 (default, Mar 9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import test_function as ppp
test_function  # 但是這里的 __name__ 不會變
>>> dir()  # 這里的會變
['__builtins__', '__doc__', '__name__', '__package__', 'ppp']
>>> 
>>> 
>>> ppp.some_func()
hello
world
100
>>>
  • what does python do when you import a module

每次引入一個module,你當前的Python interpreter都會把這個module的代碼逐行執行,所以這里有一個testfunction的輸出,因為源文件里有個 print _name , 但是你在同一個interpreter shell里引入兩次,它就不會執行兩次

  • module creates its own namespace
➜ Desktop python
Python 2.7.5 (default, Mar 9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import test_function
test_function
>>> 
>>> 
>>> test_function.some_func()
hello
world
100
>>> 
>>> a = 11
>>> test_function.a
100
>>> 
>>> a
11
>>>
  • 一個有意思的現象,單獨執行那個.py,輸出的name 就是main

這樣也就有了以后的

if name == ‘main‘:
main()

➜ Desktop python test_function.py
__main__
➜ Desktop

所以在別的interpreter shell或者Python文件中引用它時,這個地方name == ‘main‘: 不成立,所以就不會執行if下面的內容,這就提供了一種很好的機制,可以讓我們可以單獨執行源文件里的東西

➜ Desktop cat test_function.py
print __name__
a = 100
def some_func():
print "hello"
print "world"
print a

if __name__ == '__main__':
print "this is excuted by itself"
➜ Desktop 
➜ Desktop 
➜ Desktop python test_function.py
__main__
this is excuted by itself   # 這樣這句話就出來了
➜ Desktop

package/path

  • 先說sys.path, 我的理解是,這些path都是可以直接import的,也就是已經install的module和package所在的地方

pprint.pprint(sys.path)是個好辦法,因為直接輸出sys.path看着太混亂了

  • 注意下面pprint出來的第一行內容,是個空的string,這就代表了Python會查看本地目錄,也就是一個Python文件自己所在的目錄,也就解釋了之前在同一個目錄Desktop為什么可以直接引用
➜ Desktop python 
Python 2.7.5 (default, Mar 9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import pprint
>>> 
>>> pprint.pprint(sys.path)
['',
 '/Library/Python/2.7/site-packages/trigger-1.5.2b2-py2.7.egg',
 '/Library/Python/2.7/site-packages/redis-2.10.3-py2.7.egg',
 '/Library/Python/2.7/site-packages/SimpleParse-2.1.1-py2.7-macosx-10.9-intel.egg',
 '/Library/Python/2.7/site-packages/pyparsing-1.5.7-py2.7.egg',
 '/Library/Python/2.7/site-packages/pycrypto-2.6.1-py2.7-macosx-10.9-intel.egg',
 '/Library/Python/2.7/site-packages/pyasn1-0.1.8-py2.7.egg',
 '/Library/Python/2.7/site-packages/IPy-0.83-py2.7.egg',
 '/Library/Python/2.7/site-packages/pip-1.5.6-py2.7.egg',
 '/Library/Python/2.7/site-packages/pyPluribus-0.3.0-py2.7.egg',
 '/Library/Python/2.7/site-packages',
 '/Library/Python/2.7/site-packages/napalm-1.0.0-py2.7.egg',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC',
 '/Library/Python/2.7/site-packages']
>>>
  • 如何修改sys.path

使用 export命令修改,這個命令也是通用的

為了演示這個過程,我創建了一個文件夾在Desktop, 叫package1

這涉及到了Linux Mac OS X等系統的環境變量的設置,命令是 env ,可以展示當前所有的環境變量,Python的那個值的key是PYTHONPATH

➜ Desktop env | grep PYT #看到目前是沒有設置任何PYTHONPATH變量的
➜ Desktop

下面我去創建一個package1,然后盡管這個folder里什么都還沒有,它還是能被加到PYTHONPATH中

➜ Desktop mkdir package1
➜ Desktop cd package1 
➜ package1 
➜ package1 
➜ package1 pwd
/Users/harry/Desktop/package1
➜ package1 export PYTHONPATH = /Users/harry/Desktop/package1
zsh: bad assignment
➜ package1 export PYTHONPATH=/Users/harry/Desktop/package1 
➜ package1 env | grep PYT
PYTHONPATH=/Users/harry/Desktop/package1
➜ package1

進入Python查看一下

➜ package1 python
Python 2.7.5 (default, Mar 9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import pprint
>>> pprint.pprint(sys.path)
['',
 '/Library/Python/2.7/site-packages/trigger-1.5.2b2-py2.7.egg',
 '/Library/Python/2.7/site-packages/redis-2.10.3-py2.7.egg',
 '/Library/Python/2.7/site-packages/SimpleParse-2.1.1-py2.7-macosx-10.9-intel.egg',
 '/Library/Python/2.7/site-packages/pyparsing-1.5.7-py2.7.egg',
 '/Library/Python/2.7/site-packages/pycrypto-2.6.1-py2.7-macosx-10.9-intel.egg',
 '/Library/Python/2.7/site-packages/pyasn1-0.1.8-py2.7.egg',
 '/Library/Python/2.7/site-packages/IPy-0.83-py2.7.egg',
 '/Library/Python/2.7/site-packages/pip-1.5.6-py2.7.egg',
 '/Library/Python/2.7/site-packages/pyPluribus-0.3.0-py2.7.egg',
 '/Library/Python/2.7/site-packages',
 '/Library/Python/2.7/site-packages/napalm-1.0.0-py2.7.egg',
 '/Users/harry/Desktop/package1',  # <<<<<<<<<<<<<<<<<-------------------------check it out!!!!!!!!
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC',
 '/Library/Python/2.7/site-packages']
>>>
  • 往這個package1里加點東西,加init.py才算一個package,這個方法3.3版本前適用,后面再說這個文件干啥用的
➜ package1 pwd
/Users/harry/Desktop/package1
➜ package1 touch __init__.py
➜ package1 ls -al
total 0
drwxr-xr-x 3 harry staff 102 Aug 8 12:14 .
drwxr-xr-x+ 26 harry staff 884 Aug 8 12:01 ..
-rw-r--r-- 1 harry staff 0 Aug 8 12:14 __init__.py
➜ package1

其實這個時候,它才能被稱為是一個package

這個時候我遇到了一個issue,提示ImportError: No module named package1,但是其實pprint都已經顯示了,原因是permission issue,chmod 755 package1/ 就好了

  • 往package里價格module,也就是py文件,添加一個p_test.py
➜ Desktop cd package1 
➜ package1 vi p_test.py
➜ package1 python p_test.py 
hello world, this is excuted by myself
➜ package1 
➜ package1 
➜ package1 cat p_test.py 
def some_func():
print "from some_func"

def another_func():
print "from another func"

if __name__ == '__main__':
print "hello world, this is excuted by myself"
➜ package1

在Python interpreter shell中引用這個p_test.py,引用的格式是 import some_package.some_module

➜ Desktop python
Python 2.7.5 (default, Mar 9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import package1.p_test
>>>
>>> package1.p_test.some_func()
from some_func
>>>
  • package1下面還可以創建多個子目錄,依然不用修改sys.path,多個子目錄里就可以放自己想要的module

  • 編輯 init.py ,這里體現了這貨有啥用

先往里隨便加點print

➜ package1 cat __init__.py
print "In __init__.py"

當你再次引用時, 會看到一旦引用,Python會執行init里的print,其實Python會逐條執行這個init,雖然里面可以什么都沒有

現在dir()展開一下namespace會發現沒有p_test存在,如果想用p_test,必須單獨import,init這個文件就是為了解決這個問題的

➜ Desktop python
Python 2.7.5 (default, Mar 9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import package1
In __init__.py
>>> 
>>> dir()  
['__builtins__', '__doc__', '__name__', '__package__', 'package1']
>>> dir(package1)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
>>>

發現沒有p_test存在,如果想用p_test,必須單獨import

>>> package1.p_test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'p_test'
>>> 
>>> 
>>> import package1.p_test
>>> 
>>> package1.p_test
<module 'package1.p_test' from 'package1/p_test.pyc'>
>>> 
>>> package1.p_test.some_func()
from some_func
>>>

> - 再次編輯 __init__.py “連接”你想要的file

```sh
➜ package1 vi __init__.py
➜ package1
➜ package1 cat __init__.py
print "In __init__.py"

from . import p_test # from . 的意思是從當前目錄import

這樣ptest就被_init 引用了

再次回到Python,再引用一次package1

namespace都在了

➜ Desktop python           
Python 2.7.5 (default, Mar 9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import package1
In __init__.py
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'package1']
>>> dir(package1)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'p_test']
>>> dir(package1.p_test)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'another_func', 'some_func']
>>>

p_test這個module也可以用了

>>> 
>>> package1.p_test.some_func()  # 可以直接這么用
from some_func
>>>
  • 關於import現成的module or package

1) 以pprint為例

locate pprint可以找到pprint.py在哪里,一般是在下面這個,看到這個pprint.py就可以認為這是一個 module

 /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pprint.py

打開看一下他其實就是一個py文件,里面是源碼,有作者的info comment等等

2) 以paramiko為例

locate paramiko找到一個叫paramiko的文件夾,在/Library/Python/2.7/site-packages/paramiko 這個路徑
進去看一下會發現,這是一個 package

你可以看到它的 init.py 這個文件,其實你import paramiko的時候,就是它在連接它的各個py文件

➜ paramiko pwd        
/Library/Python/2.7/site-packages/paramiko
➜ paramiko ls *.py
__init__.py common.py kex_group14.py resource.py sftp_si.py
_version.py compress.py kex_gss.py rsakey.py ssh_exception.py
_winapi.py config.py message.py server.py ssh_gss.py
agent.py dsskey.py packet.py sftp.py transport.py
auth_handler.py ecdsakey.py pipe.py sftp_attr.py util.py
ber.py file.py pkey.py sftp_client.py win_pageant.py
buffered_pipe.py hostkeys.py primes.py sftp_file.py
channel.py kex_gex.py proxy.py sftp_handle.py
client.py kex_group1.py py3compat.py sftp_server.py
➜ paramiko

一共有42個py文件

➜ paramiko ls *.py | wc -l
  42
➜ paramiko

從其他地方看到的關於import的內容

http://stackoverflow.com/questions/6757192/importing-a-function-from-a-class-in-another-file
以上似乎是直接引用,不需要安裝

Head First 上40 - 41頁上講的是如何安裝然后/Library/Python/2.7/site-packages就有了相應的module,在程序里直接 import那個名字即可

卸載
http://stackoverflow.com/questions/1550226/python-setup-py-uninstall

思考:

Head First 上講的是引用一個print多層數組的方法,引用的是一個含有一個方法的.py文件,如果是類的話,用install的話,應該和Head First上的方法是一樣的,如果想直接從文件引用的話,就參考第一個stackoverflow的鏈接,似乎需要在源文件里 always run着一個instance


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com