1. 程式人生 > 實用技巧 >Python學習第四天----模組兒匯入

Python學習第四天----模組兒匯入

1.名稱空間

  模組兒的名字加上檔案的名字,就是名稱空間。   python如何區分一個普通的資料夾和一個包的?     在一個資料夾下有一個特定的檔案__init__.py,此時這個資料夾就是一個包。(前後各兩個下劃線)。其中,這個檔案本身也是一個模組兒。這個模組兒的名字就是他的直屬資料夾的名字。

2.模組兒的引入:

  第一種:

  我們不能直接匯入模組兒下的變數的。   修改引入模組兒的名字:
import t.c7 as m 
print(m.a)

  第二種:

from t.c7 import a 
print(a) //或者 # from t import c7
#print(c7.a)
  引入所有的變數:
from t.c7 import * 
print(a) 
print(c) 
print(d)
  其中t.c7中的變數定義為:
a = 2
c = 3
d = 4
  在t.c7中可以指定通過*號匯出變數或者函式,如下值匯出a,c變數:   t.c7.py:
__all__ = ['a', 'c']   
  
a = 2     
c = 3     
d = 4
  此時執行c8.py檔案:
from t.c7 import *

print(a)
print(c)
print(d) 
//2
//3
//Traceback (most recent call last):
// File ".\c8.py", line 9, in <module> // print(d) //NameError: name 'd' is not defined
  其中__all__稱為模組兒的內建變數。

第三種:

from c9 import a,b,c

'''
    from c9 import a
    from c9 import b
    from c9 import c
'''
python建議: 一行字元的個數最好不要超過80個 此時涉及到換行而不改變程式碼本意:
from c9 import a,b,\
c  
上邊示例並不建議,顯得很突兀,所以建議使用括號來進行:
from
c9 import (a,b, c)

3.__init__.py檔案的作用:

單個匯入:

  匯入包的時候, 該檔案會自動執行。   c11檔案中:
import t
  此時執行c11.py:
#This is __init__.py file t中的__init__.py檔案自動執行。
  當然,只引用t中的c7檔案,__init__.py依舊可以執行。   在 __init__.py檔案中寫入:
__all__ = ['c7']
  在t資料夾下加入c8.py檔案,c8.py檔案中寫入:
e = 2 
f = 3  
g = 4
  c11檔案中寫入,並執行c11
from t import * 
print(c7.a) 
#2 
print(c8.e) 
#error: NameError: name 'c8' is not defined

  批量匯入:

    關於專案目錄:     在t資料夾下的 __init__.py中批量匯入模組兒:
import sys
import datetime 
import io
  在c13檔案下引用:
import t
print(t.sys.path)
#['F:\\pythonlearn\\my-pythonFirst\\six', 'E:\\py3\\python38.zip', 'E:\\py3\\DLLs', 'E:\\py3\\lib', 'E:\\py3', 'C:\\Users\\Administrator\\AppData\\Roaming\\Python\\Python38\\site-packages', 'E:\\py3\\lib\\site-packages']

包與模組兒:

    1.包與模組兒是不會被重複匯入的:     2.避免迴圈匯入     什麼是迴圈匯入呢?     例如,新建P資料夾,在p資料夾下有p1和p2兩個檔案:     p1中:
from p2 import p2 
p1 = 2 
print(p2)
  p2中:
from p1 import p1 
p2 = 2
  此時執行p1就會報錯。
Traceback (most recent call last):
  File ".\p1.py", line 1, in <module>
    from p2 import p2
  File "F:\pythonlearn\my-pythonFirst\six\p\p2.py", line 1, in <module>
    from p1 import p1
  File "F:\pythonlearn\my-pythonFirst\six\p\p1.py", line 1, in <module>
    from p2 import p2
ImportError: cannot import name 'p2' from partially initialized module 'p2' (most likely due to a circular import) (F:\pythonlearn\my-pythonFirst\six\p\p2.py)
  import 匯入的同時,就會執行被匯入模組兒的程式碼。

模組兒的內建變數:

a = 2
c = 3

infos = dir();
print(infos)
# ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'c']
  列印內建變數裡的具體資訊:先看結構   1.在c9.py中:
'''

    This is a c9 doc

'''


print("name:"+__name__)
print("package:"+__package__)
print("doc:"+__doc__)
print("file:"+__file__)
  2.在c15中引入:
import t.t1.c9
    此時的列印結果:
name:t.t1.c9
package:t.t1
doc:

    This is a c9 doc

  如果c9中沒有上邊的註釋,則會報錯:
TypeError: can only concatenate str (not "NoneType") to str

入口檔案和普通模組內建變數的區別:

  修改c15.py
import t.t1.c9

print("name:"+__name__)
print("package:"+__package__)
print("doc:"+__doc__)
print("file:"+__file__)
  列印結果:
name:t.t1.c9
package:t.t1
doc:

    This is a c9 doc


file:F:\pythonlearn\my-pythonFirst\six\t\t1\c9.py
name:__main__
Traceback (most recent call last):
  File ".\c15.py", line 9, in <module>
    print("package:"+__package__)
TypeError: can only concatenate str (not "NoneType") to str
  繼續修改:
'''
描述
'''
import t.t1.c9

print('~~~~~~~~~~~~~~~~~~~~c15~~~~~~~~~~~~~~~~~~~~~~~~~')
print("name:" + __name__)
print("package:" + (__package__ or '當前模組不屬於任何包'))
print("doc:" + __doc__)
print("file:" + __file__)
  列印結果:
name:t.t1.c9
package:t.t1
doc:

    This is a c9 doc


file:F:\pythonlearn\my-pythonFirst\six\t\t1\c9.py
~~~~~~~~~~~~~~~~~~~~c15~~~~~~~~~~~~~~~~~~~~~~~~~
name:__main__
package:當前模組不屬於任何包
doc:
描述

file:.\c15.py

  總結: 因為執行的是c15.py檔案,因此它是一個入口檔案,所以不屬於任何包。而c9從t下的t1引入,所以c9屬於t.t1包。   此外,file結果根執行時環境有關:   對於dir()函式的補充:   函式不帶引數時,返回當前範圍內的變數、方法和定義的型別列表;帶引數時,返回引數的屬性、方法列表。如果引數包含方法__dir__(),該方法將被呼叫。如果引數不包含__dir__(),該方法將最大限度地收集引數資訊。 對於一句程式碼的解讀:
if __name__ == "__main__":    
     pass
  可以用Make a script both importable and executable來概括:   讓你的指令碼既可以提供一個指令碼,供其他程式去呼叫,也可以自己作為一個可執行檔案。   當一個模組兒處於兩種不同的情景的時候,在這兩種情境中程式碼的邏輯是不同的,這個時候就需要用到這段程式。   例如,在c17.py中寫入:
if __name__ == "__main__":
    print('This is app')

print('This is a module')
  此時如果是直接執行該檔案,可得到:   
  This is app
  This is a module
  如果是被呼叫:
This is a module
  這是因為,作為入口檔案時,它的內建變數__name__的值就是__main__   我們也可以通過命令來作為模組兒呼叫檔案:
python -m six.c17
  此時,c17是six資料夾下的py檔案,命令列是在six的同級目錄下進行(要讓他稱為一個模組,他就必須是一個包下的檔案,否則會報錯):
PS F:\pythonlearn\my-pythonFirst> python -m six.c17 
This is app
This is a module
  對於以上程式碼注意:     ① 如果six下沒有__init__.py,則找不到c17這個檔案     ② 如果是在six目錄下執行:
PS F:\pythonlearn\my-pythonFirst\six> python -m c17
This is app
This is a module

//-m 後邊如果是檔案,則會報錯
PS F:\pythonlearn\my-pythonFirst\six> python -m .\c17.py
E:\py3\python.exe: Relative module names not supported
  對於根目錄下的c15執行命令:( python -m six.c15)
'''
描述
'''
import t.t1.c9

print('~~~~~~~~~~~~~~~~~~~~c15~~~~~~~~~~~~~~~~~~~~~~~~~')
print("name:" + __name__)
print("package:" + (__package__ or '當前模組不屬於任何包'))
print("doc:" + __doc__)
print("file:" + __file__)
  會報錯,報錯內容是找不到檔案t,此時需要在t檔案前加six.
'''
描述
'''
import six.t.t1.c9

print('~~~~~~~~~~~~~~~~~~~~c15~~~~~~~~~~~~~~~~~~~~~~~~~')
print("name:" + __name__)
print("package:" + (__package__ or '當前模組不屬於任何包'))
print("doc:" + __doc__)
print("file:" + __file__)
  打印出來的name和package是:
name:six.t.t1.c9 
package:six.t.t1
  此處涉及到了相對匯入和絕對匯入的問題。此時,-m 後邊跟的是名稱空間。

  相對匯入與絕對匯入:

  絕對匯入:

  1.入口檔案的位置決定著__package__。   m2檔案:
print(__package__);
  執行main.py
Module2.Module4
  將main.py移動到Module2中,並修改main中的引入為Module4.m2,執行main.py
Module4
  說明入口檔案決定著這個名稱空間。   絕對路徑: 從頂級包開始向下找。

  相對路徑:

    一個點表示當前目錄,兩個點表示上一層目錄,三個點表示上上層目錄,通過n個點表示上n-1層目錄     但是import不能使用相對路徑,但是可以使用from。main引用不能使用相對路徑,原因是作為入口檔案,被python執行後,它的name指的是__main__。而__main__是不存在的,所以在入口檔案是不能使用相對路徑的。但是可以通過使用-m來使得入口檔案作為模組。   包內檔案不能使用相對路徑引用頂層檔案。如下圖:   原因是m5的頂層包是Module2,mian.py是一個入口檔案,它的同級別目錄下是沒有__main__這個包的。