python動(dòng)態(tài)加載技術(shù)解析
前言
提到python動(dòng)態(tài)加載技術(shù),我們需要聊上幾個(gè)話題:
1)反射技術(shù)
2)模塊動(dòng)態(tài)加載importlib
3) callback(函數(shù)名傳遞)--不完全算是吧動(dòng)態(tài)
反射技術(shù)
先說(shuō)反射技術(shù),所謂反射技術(shù)就是指的是在程序的運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類(lèi),都可以知道這個(gè)類(lèi)的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用他的任意方法和屬性,增加刪除方法和屬性。這種動(dòng)態(tài)獲取程序信息以及動(dòng)態(tài)調(diào)用對(duì)象的功能稱(chēng)為反射機(jī)制。
步驟:
class Animal:
def __init__(self, name, legs) -> None:
self.name = name
self.legs = legs
def get_legs(self):
return self.legs
def get_name(self):
return self.name
animal = Animal('dog', 4)
print(dir(animal))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_legs', 'get_name', 'legs', 'name']具體一個(gè)應(yīng)用場(chǎng)景,比如我們的testcase來(lái)自一個(gè)文本的創(chuàng)建的一個(gè)測(cè)試計(jì)劃,其中是一個(gè)所要執(zhí)行的測(cè)試用例的list
['test_test1', 'test_test2',...]
我們要執(zhí)行它,比如我的測(cè)試實(shí)例是test_obj
class T1:
def test_test11(self):
print('test11')
def test_test22(self):
print('test22')
class Test(T1):
def test_test1(self):
print('test1')
def test_test2(self):
print('test2')
test_obj = Test()
for test in [ 'test_test1', 'test_test2', 'test_test11', 'test_test22']:
method = getattr(test_obj, test) # 如果該函數(shù)不存在會(huì)raise exception
method()
# 可以修改如下
test_obj = Test()
for test in [ 'test_test1', 'test_test2', 'test_test11', 'test_test22']:
method = getattr(test_obj, test, lambda :'donothing') # 如果不存在就運(yùn)行一個(gè)匿名函數(shù),實(shí)際就是一個(gè)默認(rèn)值
method()反射中的setattr等不在本次討論的范疇。
模塊動(dòng)態(tài)加載importlib
動(dòng)態(tài)加載模塊,可以用于,當(dāng)我們已經(jīng)知道我們的模塊名稱(chēng),在我們的目的是動(dòng)態(tài)加載這些module用于運(yùn)行;動(dòng)態(tài)加載指在程序運(yùn)行中,動(dòng)態(tài)的加載模塊,而不是在運(yùn)行之前利用import 或from ... import 的方式加載模塊的方式。
應(yīng)用場(chǎng)景:
(1) 程序在運(yùn)行期間才能確定加載的模塊。
(2) 在某種條件下,需要通過(guò)模塊名字符串進(jìn)行加載的模塊。
#mymodule/mytest.py
def helloworld():
print('hello world')
class MyModule:
def print_hello(self):
print(f'hello from {self.__class__}')
# test.py
import importlib
def import_method1():
"""From module"""
module = importlib.import_module('mymodule.mytest')
module.helloworld()
my_module_obj = module.MyModule()
my_module_obj.print_hello()
def import_method2():
"""From file path"""
file = 'mymodule/mytest.py'
module_name = 'mytest'
# loading module
spec = importlib.util.spec_from_file_location(module_name, file)
module = importlib.util.module_from_spec(spec)
#execute module
spec.loader.exec_module(module)
# invoke methods
module.helloworld()
my_module = module.MyModule()
my_module.print_hello()另外一個(gè)例子,我們的module中有很多個(gè)類(lèi),相同的方法,這樣我們可以批處理進(jìn)行調(diào)用
# mytest/myfile.py
import sys
class Test1:
def setup(self):
print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}")
def teardown(self):
print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}")
def run(self):
print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}")
class Test2:
def setup(self):
print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}")
def teardown(self):
print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}")
def run(self):
print(f" {self.__module__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}")
# test.py
import importlib
libs = 'mytest.myfile'
class_names = ['Test1', 'Test2']
methods = ['setup', 'run', 'teardown', 'hello'] # hello不存在的
my_import = importlib.import_module(libs)
for cls_ in class_names:
Clss = getattr(my_import, cls_) # 獲取模塊下的類(lèi)
my_class = Clss() # 實(shí)例化
for m in methods:
method = getattr(my_class, m, lambda: "DoNothing") # 獲取類(lèi)方法, 默認(rèn)lambda為了防止函數(shù)不存在
method() # 執(zhí)行方法
# output
mytest.myfile.Test1.setup
mytest.myfile.Test1.run
mytest.myfile.Test1.teardown
mytest.myfile.Test2.setup
mytest.myfile.Test2.run
mytest.myfile.Test2.teardown另外一種方式:
通過(guò)__import__加載
函數(shù)原型:__import__(name, globals={}, locals={}, fromlist=[], level=-1)
參數(shù):name:模塊名,包含路徑
globals:全局變量,一般默認(rèn),如果設(shè)置,可設(shè)置globals()
locals:局部變量,一般默認(rèn),如果設(shè)置,可設(shè)置locals()
fromlist:導(dǎo)入的模塊,及name下的模塊名、函數(shù)名、類(lèi)名或者全局變量名。
返回值:module對(duì)象,通過(guò)取module得屬性獲取模塊得函數(shù)、類(lèi)或者全局變量等。
# 如上代碼,我們下面的方式
d1 = __import__(libs)
for cls_ in class_names:
Clss = getattr(my_import, cls_) # 獲取模塊下的類(lèi)
my_class = Clss() # 實(shí)例化
for m in methods:
method = getattr(my_class, m, lambda: "DoNothing") # 獲取類(lèi)方法
method() # 執(zhí)行方法另外一種方式:通過(guò)exec進(jìn)行,但是不建議用邪惡的exec
import_string = "import mytest.myfile as myfile" exec(import_string ) t1 = myfile.Test1() t1.setup()
callback方式(回調(diào))
說(shuō)到回調(diào)不得不提python的函數(shù)其實(shí)也是一種類(lèi)型
比如你可以將一個(gè)函數(shù)名給一個(gè)變量
比如最常見(jiàn)的匿名函數(shù)
squre = lambda x: x*x squre(5) 25
那么回調(diào)就是我們?cè)趫?zhí)行一個(gè)函數(shù)時(shí)候,另外一個(gè)函數(shù)作為一個(gè)變量傳入,以便對(duì)在該函數(shù)中由系統(tǒng)在符合你設(shè)定的條件時(shí)自動(dòng)調(diào)用
def my_function(a, b, callback_func): ??????? .... ??????? if xxx: ??????????????? callback_func(**kwargs)
這里不給贅述了,僅僅該一個(gè)例子,比如我們?cè)趯?shí)時(shí)讀取文件的時(shí)候進(jìn)行查找默寫(xiě)匹配的
import time
import re
def follow_file_with_timeout(tailed_file,callback_func, timeout=10):
with open(tailed_file) as file_:
file_.seek(0,2) # Go to the end of file
start_time = time.time()
while time.time() - start_time < timeout:
curr_position = file_.tell()
line = file_.readline()
if not line:
file_.seek(curr_position)
time.sleep(1)
else:
callback_func(line)
def my_search(line):
if line:
matched = re.search('Yourpatternhear', line)
if matched:
print(line)
follow_file_with_timeout('test.txt', my_search)到此這篇關(guān)于淺談一下python動(dòng)態(tài)加載技術(shù)的文章就介紹到這了,更多相關(guān)python動(dòng)態(tài)加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python程序運(yùn)行添加命令行參數(shù)argparse模塊具體用法詳解
這篇文章主要給大家介紹了關(guān)于python程序運(yùn)行添加命令行參數(shù)argparse模塊具體用法的相關(guān)資料,argparse是Python內(nèi)置的一個(gè)用于命令項(xiàng)選項(xiàng)與參數(shù)解析的模塊,通過(guò)在程序中定義好我們需要的參數(shù),需要的朋友可以參考下2024-01-01
numba CUDA報(bào)錯(cuò)的問(wèn)題解決
本文主要介紹了numba CUDA報(bào)錯(cuò)的問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
Python3爬蟲(chóng)發(fā)送請(qǐng)求的知識(shí)點(diǎn)實(shí)例
在本篇文章里小編給大家分享的是一篇關(guān)于Python3爬蟲(chóng)發(fā)送請(qǐng)求的知識(shí)點(diǎn)實(shí)例,需要的朋友們可以學(xué)習(xí)下。2020-07-07
pytorch教程實(shí)現(xiàn)mnist手寫(xiě)數(shù)字識(shí)別代碼示例
這篇文章主要講解了pytorch教程中如何實(shí)現(xiàn)mnist手寫(xiě)數(shù)字識(shí)別,文中附有詳細(xì)的代碼示例,test準(zhǔn)確率98%,有需要的朋友可以借鑒參考下2021-09-09
python保存字典數(shù)據(jù)到csv文件的完整代碼
在實(shí)際數(shù)據(jù)分析過(guò)程中,我們分析用Python來(lái)處理數(shù)據(jù)(海量的數(shù)據(jù)),我們都是把這個(gè)數(shù)據(jù)轉(zhuǎn)換為Python的對(duì)象的,比如最為常見(jiàn)的字典,下面這篇文章主要給大家介紹了關(guān)于python保存字典數(shù)據(jù)到csv的相關(guān)資料,需要的朋友可以參考下2022-06-06
python 判斷l(xiāng)inux進(jìn)程,并殺死進(jìn)程的實(shí)現(xiàn)方法
今天小編就為大家分享一篇python 判斷l(xiāng)inux進(jìn)程,并殺死進(jìn)程的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07
通過(guò)數(shù)據(jù)庫(kù)對(duì)Django進(jìn)行刪除字段和刪除模型的操作
這篇文章主要介紹了通過(guò)數(shù)據(jù)庫(kù)對(duì)Django進(jìn)行刪除字段和刪除模型的操作,這里假設(shè)我們已經(jīng)建立了一個(gè)名為book的數(shù)據(jù)模型,需要的朋友可以參考下2015-07-07
python TinyDB輕量級(jí)文檔導(dǎo)向數(shù)據(jù)庫(kù)輕松存儲(chǔ)訪問(wèn)
這篇文章主要為大家介紹了python TinyDB輕量級(jí)文檔導(dǎo)向數(shù)據(jù)庫(kù)輕松存儲(chǔ)訪問(wèn)數(shù)據(jù)使用探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
淺談pytorch中的nn.Sequential(*net[3: 5])是啥意思
這篇文章主要介紹了pytorch中的nn.Sequential(*net[3: 5])是啥意思,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

