1. 程式人生 > >python學習日記(模組匯入)

python學習日記(模組匯入)

什麼是模組?

 常見的場景:一個模組就是一個包含了python定義和宣告的檔案,檔名就是模組名字加上.py的字尾。

   但其實import載入的模組分為四個通用類別: 

  1 使用python編寫的程式碼(.py檔案)

  2 已被編譯為共享庫或DLL的C或C++擴充套件

  3 包好一組模組的包

  4 使用C編寫並連結到python直譯器的內建模組

為何要使用模組?

如果你退出python直譯器然後重新進入,那麼你之前定義的函式或者變數都將丟失,因此我們通常將程式寫到檔案中以便永久儲存下來,需要時就通過python test.py方式去執行,此時test.py被稱為指令碼script。

    隨著程式的發展,功能越來越多,為了方便管理,我們通常將程式分成一個個的檔案,這樣做程式的結構更清晰,方便管理。這時我們不僅僅可以把這些檔案當做指令碼去執行,還可以把他們當做模組來匯入到其他的模組中,實現了功能的重複利用。

如何使用模組?

import

示例檔案:自定義模組my_module.py,檔名my_module.py,模組名my_module

print('from my_module.py')

x = 100
def read1():
    print('my_module->read1->x',x)
def read2():
    
print('my_module->read2->x',x) read1() def change(): global x x = 0

重複匯入的問題

模組可以包含可執行的語句和函式的定義,這些語句的目的是初始化模組,它們只在模組名第一次遇到匯入import語句時才執行(import語句是可以在程式中的任意位置使用的,且針對同一個模組很import多次,為了防止你重複匯入,python的優化手段是:第一次匯入後就將模組名載入到記憶體了,後續的import語句僅是對已經載入大記憶體中的模組物件增加了一次引用,不會重新執行模組內的語句),如下 

import my_module
import my_module
import my_module

我們可以從sys.modules中找到當前已經載入的模組,sys.modules是一個字典,內部包含模組名與模組物件的對映,該字典決定了匯入模組時是否需要重新匯入。

import my_module
import sys
print(sys.modules)

模組與本地的變數衝突問題

每個模組都是一個獨立的名稱空間,定義在這個模組中的函式,把這個模組的名稱空間當做全域性名稱空間,這樣我們在編寫自己的模組時,就不用擔心我們定義在自己模組中全域性變數會在被匯入時,與使用者的全域性變數衝突啦

一、x與my_module.x不衝突

import my_module
x = 50
print(my_module.x)

二、read1與my_module.read1不衝突

import my_module
def read1():
    print('local_test_read1')
my_module.read1()

 三、執行my_module.change()操作的全域性變數x仍然是my_module中的

import my_module
x = 50
my_module.change()
print(x)
print(my_module.x)

總結

總結:首次匯入模組my_module時會做三件事:

1.為原始檔(my_module模組)建立新的名稱空間,在my_module中定義的函式和方法若是使用到了global時訪問的就是這個名稱空間。

2.在新建立的名稱空間中執行模組中包含的程式碼,見初始匯入import my_module

1 提示:匯入模組時到底執行了什麼?
2 
3 In fact function definitions are also ‘statements’ that are ‘executed’; the execution of a module-level function definition enters the function name in the module’s global symbol table.
4 事實上函式定義也是“被執行”的語句,模組級別函式定義的執行將函式名放入模組全域性名稱空間表,用globals()可以檢視
匯入模組時到底執行了什麼?

3.建立名字my_module來引用該名稱空間

1 這個名字和變數名沒什麼區別,都是‘第一類的’,且使用my_module.名字的方式可以訪問my_module.py檔案中定義的名字,my_module.名字與test.py中的名字來自兩個完全不同的地方。

模組別名

為模組起別名,相當於a = 1,b = a

import my_module as m
print(m.x)

示範用法一:

有兩中sql模組mysql和oracle,根據使用者的輸入,選擇不同的sql功能

#分別建立兩個資料庫模組
#mysql.py
def sqlparse():
    print('from mysql slparse')
#oracle.py
def sqlparse():
    print('from oracle sqlparse')
db_type = input('please input db_name:')
if db_type.strip().lower() == 'mysql':
    import mysql as db
elif db_type.strip().lower() == 'oracle':
    import oracle as sb

db.sqlparse()

示範用法二: 

為已經匯入的模組起別名的方式對編寫可擴充套件的程式碼很有用,假設有兩個模組xmlreader.py和csvreader.py,它們都定義了函式read_data(filename):用來從檔案中讀取一些資料,但採用不同的輸入格式。可以編寫程式碼來選擇性地挑選讀取模組,例如

if file_format == 'xml':
     import xmlreader as reader
elif file_format == 'csv':
     import csvreader as reader
data=reader.read_date(filename)

注意:模組在定義了別名之後,使用就只能用別名。

 一行匯入多個模組

import os,sys,re

from...import...

簡述

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

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

例如,要匯入模組 modname 的 name1 函式,使用如下語句:

from modname import name1

這個宣告不會把整個modname模組匯入到當前的名稱空間中,它只會將modname裡的name1函式引入進來。

#測試一:匯入的函式read1,執行時仍然回到my_module.py中尋找全域性變數 x
from my_module import read1
x = 0.1
read1()
print('分割線'.center(20,'-'))
#測試二:匯入的函式read2,執行時需要呼叫read1(),仍然回到my_module.py中找read1()
from my_module import read2
def read1():
    print('11111111')
read2()

覆蓋情況

匯入的函式read1,被當前位置定義的read1覆蓋掉了

from my_module import read1 def read1(): print('1111111111') read1()

注意:繫結關係

需要特別強調的一點是:python中的變數賦值不是一種儲存操作,而只是一種繫結關係,如下:

from my_module import x,read1
x = 0.1#將當前位置的名字x繫結到了100
print(x)#列印當前的名字
read1()#讀取my_module.py中的名字x,仍然為100

也可重新命名

from my_module import read1 as r
r()

也可匯入多行

from my_module import (x,
                       read1,
                       read2)

from … import *

簡述

from my_module import * 把my_module中所有的不是以下劃線(_)開頭的名字都匯入到當前位置,大部分情況下我們的python程式不應該使用這種匯入方式,因為*你不知道你匯入什麼名字,很有可能會覆蓋掉你之前已經定義的名字。而且可讀性極其的差,在互動式環境中匯入時沒有問題。

這種宣告不該被過多地使用。

from my_module import *
print(x)
print(read1)
print(read2)
print(change)

__all__

如果沒有這個變數,就會匯入模組中所有的名字

如果有這個變數,就只匯入__all__列表中的名字

__all__ = ['read1']#這樣在另外一個檔案中用from my_module import *就這能匯入列表中規定的一個名字

__name__

 一個模組被另一個程式第一次引入時,其主程式將執行。如果我們想在模組被引入時,模組中的某一程式塊不執行,我們可以用__name__屬性來使該程式塊僅在該模組自身執行時執行。

說明: 每個模組都有一個__name__屬性,當其值是'__main__'時,表明該模組自身在執行,否則是被引入。

說明:__name__ 與 __main__ 底下是雙下劃線, _ _ 是這樣去掉中間的那個空格。

import my_module as m
if m.__name__ == '__main__':
    print('程式自身在執行')
else:
    print('我來自另一個模組')
print('分割線'.center(15,'-'))
#自身
if __name__ == '__main__':
    print('程式自身在執行')
else:
    print('我來自另一個模組')

pass