最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python解決循環(huán)依賴(lài)的問(wèn)題分析

 更新時(shí)間:2022年12月02日 09:30:31   作者:Bruce小鬼  
在使用python開(kāi)發(fā)過(guò)程中在引入其他模塊時(shí)可能都經(jīng)歷過(guò)一個(gè)異常就是循環(huán)引用most likely due to a circular import,它的意思就是A引用了B,反過(guò)來(lái)B又引用了A,導(dǎo)致出現(xiàn)了循環(huán)引用異常,下面來(lái)介紹如何避免循環(huán)引用異常,感興趣的朋友跟隨小編一起看看吧

python解決循環(huán)依賴(lài)

1.概述

在使用python開(kāi)發(fā)過(guò)程中在引入其他模塊時(shí)可能都經(jīng)歷過(guò)一個(gè)異常就是循環(huán)引用most likely due to a circular import,它的意思就是A引用了B,反過(guò)來(lái)B又引用了A,導(dǎo)致出現(xiàn)了循環(huán)引用異常。下面來(lái)介紹如何避免循環(huán)引用異常。

2.循環(huán)引用介紹

2.1.python引入模塊原理

下面通過(guò)一個(gè)循環(huán)引用示例,來(lái)介紹python引入模塊的原理。示例中創(chuàng)建了三個(gè)模塊,它的引用關(guān)系如下

  • dialog.py模塊引入了app模塊的prefs類(lèi)的get方法
  • app模塊引入了dialog模塊的show方法

創(chuàng)建一個(gè)python文件,命名為dialog.py

import app

class Dialog:
    def __init__(self, save_dir):
        self.save_dir = save_dir

save_dialog = Dialog(app.prefs.get('save_dir'))

def show():
    print('Showing the dialog!')

創(chuàng)建一個(gè)python文件,命名為app.py

import dialog

class Prefs:
    def get(self, name):
        pass

prefs = Prefs()
dialog.show()

創(chuàng)建一個(gè)python文件,命名為main.py

import app

運(yùn)行上面循環(huán)引用代碼,拋出了異常

AttributeError: partially initialized module 'app' has no attribute 'prefs' (most likely due to a circular import)

要明白上面為什么會(huì)拋出循環(huán)引用異常,首先要明白python是如何引入模塊的。在引入模塊的時(shí)候,python系統(tǒng)會(huì)按照深度優(yōu)先的順序,對(duì)模塊執(zhí)行以下五步:

  • 1.在sys.path里尋找模塊的位置
  • 2.把模塊的代碼加載進(jìn)來(lái),并確認(rèn)這些代碼能編譯
  • 3.創(chuàng)建響應(yīng)的空白模塊對(duì)象表示該模塊
  • 4.把這個(gè)模塊插入sys.modules字典
  • 5.運(yùn)行模塊對(duì)象之中的代碼定義該模塊的內(nèi)容

循環(huán)依賴(lài)之所以會(huì)出錯(cuò),原因在于,執(zhí)行完第4步驟之后,這個(gè)模塊已經(jīng)位于sys.modules之中了,然而它的內(nèi)容還沒(méi)有得到定義,要等到執(zhí)行完第5步驟,才能齊備。

可是python在執(zhí)行import語(yǔ)句的時(shí)候,如果發(fā)現(xiàn)要引用的模塊已經(jīng)出現(xiàn)在了sys.modules之中,(也就是執(zhí)行完第4個(gè)步驟),那么就會(huì)繼續(xù)執(zhí)行importd 下一條語(yǔ)句,而不會(huì)顧及模塊之中的內(nèi)容是否的得到了定義。

例如上面的例子,app模塊在執(zhí)行自己第5步驟時(shí),首先遇到的就是引入dialog模塊的這條語(yǔ)句,而此刻他還沒(méi)有把自己的內(nèi)容定義出來(lái),他只不過(guò)執(zhí)行完了前4步驟,讓自己出現(xiàn)在了sys.dodules字典里面而已。
等到dialog模塊反過(guò)來(lái)要引入app的時(shí)候,由于app模塊已經(jīng)出現(xiàn)在了sys.modules字典中,python就會(huì)認(rèn)為這個(gè)模塊已近引入,于是繼續(xù)執(zhí)行dialog模塊其他代碼,而不會(huì)考慮app里面的內(nèi)容到底有沒(méi)有定義。
這樣的話(huà),執(zhí)行到save_dialog = Dialog(app.prefs.get('save_dir')) 這一句的時(shí)候,就會(huì)因?yàn)閍pp里面找不到prefs屬性而出錯(cuò)。(這個(gè)屬性必須等app執(zhí)行完第5步驟才能夠得到定義)

3.解決循環(huán)引用方法

如果要解決上面的循環(huán)引用異常,有四種解決辦法。

3.1.重構(gòu)引入關(guān)系

例如把prefs內(nèi)容提取到一個(gè)單獨(dú)的工具模塊中,把它放在依賴(lài)體系最底層,這樣app與dialog分別引入這個(gè)模塊。他們的關(guān)系如下

  • app 引入 prefs
  • dialog 引入 prefs

有時(shí)候這種重構(gòu)引入關(guān)系需要拆分代碼,對(duì)于大型的項(xiàng)目可能不太好拆分,還可以通過(guò)其他的方式解決

3.2.調(diào)整import語(yǔ)句

調(diào)整import位置,例如我們可以讓app模塊不要那么早就引入dialog模塊,而是等到prefs等其他內(nèi)容都創(chuàng)建出來(lái)之后,在引入dailog,這樣的話(huà),等待dialog返回來(lái)使用app中的屬性時(shí),就不會(huì)因?yàn)樵搶傩赃€沒(méi)有定義出來(lái)而發(fā)生AttributeError

class Prefs:
    def get(self, name):
        pass

prefs = Prefs()

import dialog  # Moved
dialog.show()

這種寫(xiě)法雖然可行,但是它違背了PEP8規(guī)范,依照建議,所有的import語(yǔ)句都應(yīng)該出現(xiàn)在文件開(kāi)頭。這種方式有個(gè)弊端,在執(zhí)行了一半,才發(fā)現(xiàn)自己要使用的那個(gè)模塊還沒(méi)有加載進(jìn)來(lái),因此不建議使用這種方法。

3.3.把模塊分成引入-配置-運(yùn)行三個(gè)環(huán)節(jié)

循環(huán)引入可以通過(guò)勁量縮減引用時(shí)所要執(zhí)行的操作。我們可以讓模塊只把函數(shù)、類(lèi)、與常量定義出來(lái),而不真正去執(zhí)行,這樣python在引入本模塊的時(shí)候,就不會(huì)由于操作其他模塊而出錯(cuò)了。
我們可以把本模塊里,需要用到其他模塊的那種操作放在configure函數(shù)中,等到模塊徹底引入完畢后,再去調(diào)用。

dialog.py模塊把調(diào)用的操作放在configure函數(shù)中

import app

class Dialog:
    def __init__(self):
        pass

save_dialog = Dialog()

def show():
    print('Showing the dialog!')

def configure():
    save_dialog.save_dir = app.prefs.get('save_dir')

app.py模塊把調(diào)用的操作放在configure函數(shù)中

import dialog

class Prefs:
    def get(self, name):
        pass

prefs = Prefs()

def configure():
    pass

main.py模塊按照引入-配置-運(yùn)行的順序先把那兩個(gè)模塊引入進(jìn)來(lái),然后調(diào)用各自的configure函數(shù),最后運(yùn)行dialog模塊的show函數(shù)

import app
import dialog

app.configure()
dialog.configure()

dialog.show()

這種寫(xiě)法能適應(yīng)許多種情況,而且便于我們運(yùn)用依賴(lài)注入模式來(lái)替換受依賴(lài)模塊之中的內(nèi)容。
但是有時(shí)候不太容易從代碼中抽離出這樣一個(gè)configure配置環(huán)節(jié),因?yàn)樗言撃K定義的對(duì)象與這些對(duì)象的配置邏輯分別寫(xiě)到了兩個(gè)環(huán)節(jié)里面。

3.4.動(dòng)態(tài)引入

動(dòng)態(tài)引入比前幾個(gè)方法要簡(jiǎn)單,也就是把import語(yǔ)句從模塊級(jí)別下移到函數(shù)或方法里面,這樣就解決了循環(huán)依賴(lài)關(guān)系了。
這種import并不會(huì)在程序啟動(dòng)并初始化本模塊時(shí)執(zhí)行,而是等到相關(guān)函數(shù)真正運(yùn)行的時(shí)候才得以觸發(fā),因此又叫做動(dòng)態(tài)引入

下面我們用動(dòng)態(tài)引入辦法修改dialog模塊,他只會(huì)在dialog.show函數(shù)真正運(yùn)行的時(shí)候去引入import模塊,而不像原來(lái)那樣,模塊剛初始化,就要引入app

class Dialog:
    def __init__(self):
        pass

# Using this instead will break things
# save_dialog = Dialog(app.prefs.get('save_dir'))
save_dialog = Dialog()

def show():
    import app  # Dynamic import
    save_dialog.save_dir = app.prefs.get('save_dir')
    print('Showing the dialog!')

app模塊修改

import dialog

class Prefs:
    def get(self, name):
        pass

prefs = Prefs()
dialog.show()

main模塊

import 

這樣寫(xiě),實(shí)際上與剛才那種先引入,再配置,然后運(yùn)行的辦法是類(lèi)似的。區(qū)別僅僅在于,這次不調(diào)整代碼的結(jié)構(gòu),也不修改模塊的定義與引入方式,只是把形成循環(huán)依賴(lài)的那條import語(yǔ)句推遲到真正需要使用另外一個(gè)模塊的那一刻。

一般來(lái)說(shuō)還是勁量避免動(dòng)態(tài)引入,因?yàn)閕mport語(yǔ)句畢竟是有開(kāi)銷(xiāo)的,如果它出現(xiàn)在需要頻繁執(zhí)行的循環(huán)體里面,那么這種開(kāi)銷(xiāo)會(huì)更大。另外,由于動(dòng)態(tài)引入會(huì)推遲代碼的執(zhí)行時(shí)機(jī),有可能你代碼啟動(dòng)很久之后,如果因?yàn)閯?dòng)態(tài)引入其他模塊發(fā)生異常而奔潰。

到此這篇關(guān)于python解決循環(huán)依賴(lài)的文章就介紹到這了,更多相關(guān)python循環(huán)依賴(lài)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python連接Postgres/Mysql/Mongo數(shù)據(jù)庫(kù)基本操作大全

    Python連接Postgres/Mysql/Mongo數(shù)據(jù)庫(kù)基本操作大全

    在后端應(yīng)用開(kāi)發(fā)中,經(jīng)常會(huì)用到Postgres/Mysql/Mongo這三種數(shù)據(jù)庫(kù)的基本操作,今天小編就給大家詳細(xì)介紹Python連接Postgres/Mysql/Mongo數(shù)據(jù)庫(kù)基本操作,感興趣的朋友一起看看吧
    2021-06-06
  • CentOS中升級(jí)Python版本的方法詳解

    CentOS中升級(jí)Python版本的方法詳解

    本文給大家分享的是再centos系統(tǒng)中將Python版本從2.6升級(jí)到2.7的方法和升級(jí)過(guò)程中遇到的問(wèn)題的處理,非常詳細(xì),有需要的小伙伴可以參考下
    2017-07-07
  • Python中的pprint模塊

    Python中的pprint模塊

    本文介紹了 Python中的pprint模塊,pprint模塊包含一個(gè)“美觀打印機(jī)”,用于生成數(shù)據(jù)結(jié)構(gòu)的一個(gè)美觀的視圖。格式化工具會(huì)生成數(shù)據(jù)結(jié)構(gòu)的一些表示,不僅能夠由解釋器正確地解析,還便于人閱讀。輸出會(huì)盡可能放在一行上,分解為多行時(shí)會(huì)縮進(jìn),想了解具體內(nèi)容請(qǐng)參考下文
    2021-11-11
  • pandas DataFrame 數(shù)據(jù)選取,修改,切片的實(shí)現(xiàn)

    pandas DataFrame 數(shù)據(jù)選取,修改,切片的實(shí)現(xiàn)

    這篇文章主要介紹了pandas DataFrame 數(shù)據(jù)選取,修改,切片的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • Python爬蟲(chóng)框架Scrapy實(shí)例代碼

    Python爬蟲(chóng)框架Scrapy實(shí)例代碼

    這篇文章主要介紹了Python爬蟲(chóng)框架Scrapy實(shí)例代碼,需要的朋友可以參考下
    2018-03-03
  • 詳解DBSCAN算法原理及其Python實(shí)現(xiàn)

    詳解DBSCAN算法原理及其Python實(shí)現(xiàn)

    DBSCAN,即Density-Based Spatial Clustering of Applications with Noise,基于密度的噪聲應(yīng)用空間聚類(lèi),本文將詳細(xì)介紹DBSCAN算法的原理及其Python實(shí)現(xiàn),需要的可以參考下
    2023-12-12
  • Python實(shí)戰(zhàn)之天氣預(yù)報(bào)系統(tǒng)的實(shí)現(xiàn)

    Python實(shí)戰(zhàn)之天氣預(yù)報(bào)系統(tǒng)的實(shí)現(xiàn)

    本文主要和大家介紹了如何用代碼寫(xiě)一款Python版天氣預(yù)報(bào)系統(tǒng),是Tkinter界面化的,還會(huì)制作溫度折線(xiàn)圖跟氣溫餅圖哦!感興趣的小伙伴可以嘗試一下
    2022-12-12
  • Python測(cè)試WebService接口的實(shí)現(xiàn)示例

    Python測(cè)試WebService接口的實(shí)現(xiàn)示例

    webService接口是走soap協(xié)議通過(guò)http傳輸,請(qǐng)求報(bào)文和返回報(bào)文都是xml格式的,本文主要介紹了Python測(cè)試WebService接口,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • 總結(jié)的幾個(gè)Python函數(shù)方法設(shè)計(jì)原則

    總結(jié)的幾個(gè)Python函數(shù)方法設(shè)計(jì)原則

    這篇文章主要介紹了總結(jié)的幾個(gè)Python函數(shù)方法設(shè)計(jì)原則,本文講解了每個(gè)函數(shù)只做一件事、保持簡(jiǎn)單、保持簡(jiǎn)短、輸入使用參數(shù)、輸出使用return語(yǔ)句等內(nèi)容,需要的朋友可以參考下
    2015-06-06
  • Python利用pynput實(shí)現(xiàn)劃詞復(fù)制功能

    Python利用pynput實(shí)現(xiàn)劃詞復(fù)制功能

    這篇文章主要為大家想詳細(xì)介紹了Python如何利用pynput實(shí)現(xiàn)劃詞復(fù)制功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-05-05

最新評(píng)論

成都市| 盐边县| 高碑店市| 崇义县| 根河市| 喜德县| 涡阳县| 栾城县| 泽州县| 项城市| 伊宁市| 枣阳市| 柳州市| 连州市| 若尔盖县| 岱山县| 柯坪县| 寿阳县| 保德县| 胶州市| 玉林市| 雅江县| 张家界市| 丰县| 县级市| 饶阳县| 麻江县| 将乐县| 正定县| 东乡族自治县| 石屏县| 清丰县| 永城市| 鄂温| 丘北县| 江北区| 龙井市| 乃东县| 鄂伦春自治旗| 河池市| 丰都县|