python之8核心知識點

8.1 python工程組織結構之包、模塊等的概念

  • 模塊
    新建python file,生成帶有.py後綴的文件稱爲模塊

  • 包和目錄差不多,唯一的區別在於包下面有一個_init_.py的文件

8.2 命名空間

  • 命名空間是變量到對象的映射集合。一般都是通過字典來實現的。主要可以分爲三類:
    1、每個函數都有着自已的命名空間,叫做局部命名空間,它記錄了函數的變量,包括函數的參
    數和局部定義的變量。
    2、每個模塊擁有它自已的命名空間,叫做全局命名空間,它記錄了模塊的變量,包括函數、類、其它導入的模塊、模塊級的變量和常量。
    3、還有就是內置命名空間,任何模塊均可訪問它,它存放着內置的函數和異常。通俗點講:命名空間就是爲了確定全局唯一,當模塊A中有變量c,模塊B中也有一個變量c,此時,通過A.c來確定引用A中變量c.123

  • 命名空間的查找順序
    當一行代碼要使用變量 x 的值時,Python 會到所有可用的名字空間去查找變量,按照如下順序:
    1、局部命名空間:特指當前函數或類的方法。如果函數定義了一個局部變量 x,或一個參數
    x,Python 將使用它,然後停止搜索。
    2、全局命名空間:特指當前的模塊。如果模塊定義了一個名爲 x 的變量,函數或類,Python
    將使用它然後停止搜索。
    3、內置命名空間:對每個模塊都是全局的。作爲最後的嘗試,Python 將假設 x 是內置函數或
    變量。
    4、如果 Python 在這些名字空間找不到 x,它將放棄查找並引發一個 NameError 異常,如,
    NameError: name ‘xxx’ is not defined。

  • 當函數嵌套時的查找規則
    1、先在當前 (嵌套的或 lambda) 函數的命名空間中搜索
    2、然後是在父函數的命名空間中搜索
    3、接着是模塊命名空間中搜索
    4、最後在內置命名空間中搜索

msg = "msg"
def my_func():
    name = " wiggin "
    def func_son():
         name = "xdclass " # 此處的name變量,覆蓋了父函數的name變量
        print(name)
        # 調用內部函數
    func_son()
    print(name)
my_func()
  • 命名空間的生命週期
    1、內置命名空間在 Python 解釋器啓動時創建,會一直保留,不被刪除。
    2、模塊的全局命名空間在模塊定義被讀入時創建,通常模塊命名空間也會一直保存到解釋器退出。
    3、當函數被調用時創建一個局部命名空間,當函數返回結果 或 拋出異常時,被刪除。每一個遞歸調用的函數都擁有自己的命名空間。
a = 1
def my_func(str):
    if a == 1:
        print(str)
       a = 24
my_func("file")

上面的程序會在報錯,UnboundLocalError: local variable ‘a’ referenced before assignment
在python的函數中和全局同名的變量,如果你有修改變量的值就會變成局部變量,在修改之前對
該變量的引用自然就會出現沒定義這樣的錯誤了,如果確定要引用全局變量,並且要對它修改,
必須加上global關鍵字。

修改如下:

a = 1
def my_func(str):
    global a
    if a == 1:
        print(str)
        a = 24
my_func("file")
print(a)
  • 命名空間的訪問
    1、局部命名空間的訪問

    局部命名空間可以 locals() 來訪問。
    locals 返回一個名字/值對的 dictionary。這個 dictionary 的鍵是字符串形式的變量名字,dictionary 的值是變量的實際值

def my_func():
  a = 1
  b = 2
  print(locals())
my_func()

輸出:
{‘a’: 1, ‘b’: 2}

2、全局命名空間的訪問
全局 (模塊級別)命名空間可以通過 globals() 來訪問。

a = 1
b = 2
print(globals())

輸出:
{
name’: ‘main’,
doc’: None,
package’: None,
loader’: <_frozen_importlib_external.SourceFileLoader object at
0x00000255B062F548>,
spec’: None,
annotations’: {},
builtins’: <module ‘builtins’ (built-in)>,
file’: ‘C:/Users/wiggin/Desktop/xdclass/chapter12/class2.py’,
cached’: None,
‘a’: 1, ‘b’: 2
}

3、locals 與 globals 之間的區別
locals 是隻讀的,但globals是可讀寫的

def my_func():
    x = 123
    print(locals())
    locals()["x"] = 456
    print("x=", x)
y = 123
my_func()
globals()["y"] = 111
print("y=", y)

輸出:
x=123
y=111

8.3 導入模塊
import module_name

import class2
print(class2.a)

import module_name as alias

# 導入模塊並重命名爲xd
import xdclass_python_chapter12_class3 as xd
print(xd.name)

import導入時,

  1. 查找一個模塊,如果有必要還會加載並初始化模塊。
  2. 在局部命名空間中爲 import 語句發生位置所處的作用域定義一個或多個名稱。

當一個模塊首次被導入時,Python 會搜索該模塊,如果找到就創建一個 module 對象並初始化它。 如果指定名稱的模塊未找到,則會引發 ModuleNotFoundError。 當發起調用導入機制時,Python 會實現多種策略來搜索指定名稱的模塊。
特別注意:當模塊首次被導入時,會執行模塊裏面的代碼

使用importlib模塊進行模塊的導入,基本語法如下
import importlib
importlib.import_module(“module_name”)

import importlib
module = importlib.import_module("xdclass_python_chapter12_class3")

如果想導入另一個包中的模塊,可以使用如下語法:
from package import module

如果想導入多層包中的模塊,可以使用如下語法:
from package.son import module

8.4 導入變量
from module import variable

from class2 import a
print(a)

別注意:當模塊首次被導入時,會執行模塊裏面的代碼
如class2中的內容爲:

a = 1111
print("hello world")

運行結果會先輸出hello world,在打印a值

如果要導入多個變量,可用逗號隔開
如果要導入大量變量,可使用*號導入

from class2 import a, b
from class2 import *

8.5 導包機制
python 導入機制:
導入期間,會在 sys.modules 查找模塊名稱,如存在則其關聯的值就是需要導入的模塊,導入過程完成。 然而,如果值爲 None ,則會引發ModuleNotFoundError。 如果找不到指定模塊名稱,Python 將繼續搜索該模塊。
如果指定名稱的模塊在 sys.modules找不到,則將發起調用 Python 的導入協議以查找和加載該模塊。 此協議由兩個概念性模塊構成,即 查找器和 加載器。查找器的任務是確定是否能使用其所知的策略找到該名稱的模塊。 同時實現這兩種接口的對象稱爲 導入器—— 它們在確定能加載所需的模塊時會返回其自身。

例如
from class5_import import a

  • 在sys.modules中查找符號"class5_import"
  • 如果符號存在,則獲得符號class5_import對應的module對象
    從的dict中獲得符號"a"對應的對象,如果"a"不存在,則拋出異常
  • 如果符號class5_import不存在,則創建一個新的module對象,注意,這時,module對象的dict爲空
  • 執行class5_import.py中的表達式,填充的dict
  • 從的dict中獲得"a"對應的對象,如果"a"不存在,則拋出異常

模塊 class5.py

from class2 import a
b = 11
print(a)

模塊 class5_import.py

from class5 import b
a = 1

執行過程如下:
1、執行class5.py中的from class5_import import a,由於是執行的python class5.py,所以在sys.modules中並沒有存在,首先爲B.py創建一個module對象(),注意,這時創建的這個module對象是空的,裏邊啥也沒有,在Python內部創建了這個module對象之後,就會解析執行class5_import.py,其目的是填充這個dict。
2、執行class5_import.py中的 from class5 import b,在執行class5_import.py的過程中,會碰到這一句,首先檢查sys.modules這個module緩存中是否已經存在了,由於這時緩存還沒有緩存,所以類似的,Python內部會爲class5.py創建一個module對象(),然後,同樣地,執行class5.py中的語句
3、再次執行class5.py中的from class5_import import a,這時,由於在第1步時,創建的對象已經緩存在了sys.modules中,所以直接就得到了,但是,注意,從整個過程來看,我們知道,這時還是一個空的對象,裏面啥也沒有,所以從這個module中獲得符號"a"的操作就會拋出異常。如果這裏只是import class5_import,由於"class5_import"這個符號在sys.modules中已經存在,所以是不會拋出異常的。

8.6 說說_init_.py的作用及用法
說說_init_.py的作用:

  • 標誌所在目錄是一個模塊包
  • 本身也是一個模塊
  • 可用於定義模糊導入時要導入的內容

我們使用from package import * 會報錯誤,如果想使用該語法不報錯,可以在__init__.py中定義要導入的模塊
我們可以在__init__.py文件中,使用__all__ = [‘module_name1’,‘module_name2’]定義號匹配時要導入的模塊,之後再導入的時候,就可以使用通配符進行模糊導入

  • 導入一個包的時候,包下的__init__.py中的代碼會自動執行
  • 用於批量導入模塊

當我們的許多模塊中,都需要導入某些公共的模塊,此時,可以在__init__.py中進行導入,之後直接導入該包即可

8.7 _all_和_name_的作用及用法
__all__的作用及其用法:
__all__是list的結構

  • 在普通模塊中使用時,表示一個模塊中允許哪些屬性可以被導入到別的模塊中
  • 在包下的__init__.py中,可用於標識模糊導入時的模塊

__name__的作用及其用法:

  • __name__這個系統變量顯示了當前模塊執行過程中的名稱,如果當前程序運行在這個模塊中,name 的名稱就是__main__如果不是,則爲這個模塊的名稱。
  • __main__一般作爲函數的入口,類似於C語言,尤其在大型工程中,常常有if name == “main”:來表明整個工程開始運行的入口。
def my_fun():
	if __name__ == "__main__":
	print("this is main")
my_fun()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章