性少妇vide0seⅹfree_国产剧情视频在线观看_日日碰夜夜爽_九九这里只有精品视频_性free毛茸茸偷窥videos_国产v亚洲

中培偉業(yè)IT資訊頻道
您現(xiàn)在的位置:首頁 > IT資訊 > 軟件研發(fā) > 為什么要重構(gòu)?如何重組Python包?

為什么要重構(gòu)?如何重組Python包?

2020-10-19 16:52:15 | 來源:中培企業(yè)IT培訓(xùn)網(wǎng)

重構(gòu)一詞涵蓋了廣泛的動(dòng)作和定義。盡管該術(shù)語本身通常會(huì)導(dǎo)致一個(gè)共同的目標(biāo),即建立一個(gè)更干凈,更好的代碼庫,但仍有許多動(dòng)作可以視為“重構(gòu)”,即將依賴項(xiàng)升級(jí)到較新版本、重命名您的代碼功能,類,模塊等、重新組織代碼庫,將功能從文件移動(dòng)到另一個(gè)文件、改進(jìn)功能的實(shí)現(xiàn)以提高性能、重新格式化代碼以使其符合標(biāo)準(zhǔn)。

  重構(gòu)之前

盡管從一種編程語言到另一種編程語言有所區(qū)別,但重構(gòu)時(shí)通常仍要保留一些步驟和原則。

  第1步:了解代碼質(zhì)量。

運(yùn)行靜態(tài)分析工具。靜態(tài)分析工具為您提供了帶有定量統(tǒng)計(jì)信息的摘要報(bào)告,可以在不時(shí)重構(gòu)時(shí)進(jìn)行比較。

在Python中,我個(gè)人使用Prospector,一個(gè)靜態(tài)分析套件包含其他工具,例如pep8,Pylint等。我對Prospector的最喜歡的東西是它能夠檢測并適應(yīng)我使用的框架。

請注意,并非所有找到的消息都是有效的,因此有可能出現(xiàn)誤報(bào)。

  步驟2:準(zhǔn)備和驗(yàn)證測試用例

未經(jīng)測試的代碼在設(shè)計(jì)上是不好的代碼。您有測試用例嗎?如果是這樣,它們的完整性如何?這些測試用例是否最新?

為什么在重構(gòu)之前需要測試用例?您可以辯稱,即使進(jìn)行了簡單的更改,也不需要任何東西。好吧,相信我,您會(huì)被自己修飾的杰作所回應(yīng)的意外行為所吸引。

我不會(huì)說服您一般而言具有測試代碼的重要性。重構(gòu)之前測試代碼是為了確保重構(gòu)后系統(tǒng)的行為保持一致。

即使有測試用例,這為您提供了開綠燈,您仍然應(yīng)該驗(yàn)證測試代碼。讓我來告訴你為什么。

想象一下,在嘗試進(jìn)行重構(gòu)之前,您將運(yùn)行可用的任何測試,并且得到以下結(jié)果。

但是,當(dāng)您進(jìn)一步研究時(shí),您發(fā)現(xiàn)了這個(gè)測試用例。

“”“

軟件包:utils.tests

錯(cuò)誤的測試用例

”“”

導(dǎo)入單元測試

UtilsTestCase(unittest.TestCase)類:

def setUp(self):

通過

def test_is_empty(self):

從utils.common.helpers導(dǎo)入is_empty

#問題:沒有斷言

is_empty('')

is_empty(None)

is_empty('',object_type ='json')

is_empty('{}',object_type ='json')

def test_is_ok(self):

#問題:這是空的。

通過

def test_is_number(self):

#問題:這將通過。

如果不是is_empty(''):

print('Fail')

那么,您看到驗(yàn)證的重點(diǎn)了嗎?

此外,測試用例通常是軟件的最佳文檔。在代碼內(nèi)導(dǎo)航時(shí),它們也是您最好的GPS導(dǎo)航器。

  開始重構(gòu)—重組/重組

在本節(jié)中,我將config.py通過重組結(jié)構(gòu),合并重復(fù)的方法,分解和編寫測試代碼以確保向后兼容性,向您展示一個(gè)示例。

config.py 看起來像這樣:

“”“

軟件包:

重組

”“” 之前的utils.config

CONFIG_NAME = {

“ ENABLE_LOGGING”:“ enable_logging”,

“ LOGGING_LEVEL”:“ logging_level”,

}

def get_logging_level():

通過

ConfigHelper類:

def get(self,config_name,default = None):

通過

def set(self,config_name,value):

通過

def _get_settings_helper(self):

通過

def get_logging_level():

通過

def is_logging_enabled():

通過

類LOGGING_LEVEL:

VERBOSE =“詳細(xì)”

STANDARD =“標(biāo)準(zhǔn)”

步驟1:編寫向后兼容代碼

此步驟至關(guān)重要。在重構(gòu)我們的代碼之前,必須有測試用例。在這種情況下,我們編寫向后兼容的代碼,以確保對類/函數(shù)/常量的所有引用仍然有效。

在中__init__.py,我們將重新定義類/方法簽名:

“”“

在__init__.py

這是向后兼容的代碼的生命。

這是為了確保重構(gòu)的包支持

進(jìn)口的舊路。

這是不完整的,我們將在后面再講__init__.py

‘’”

CONFIG_NAME = {}

def get_logging_level(* args,** kwargs):

通過

ConfigHelper類:

def get(self,* args,** kwargs):

pass

def set(自我,* args,** kwargs):

通過

def _get_settings_helper(self):

通過

def get_logging_level(self):

通過

def is_logging_enabled(self):

通過

LOGGING_LEVEL類:

通過

目前__init__.py尚不完整。稍后我們將重新訪問該文件。

接下來,我們編寫一個(gè)測試用例,以確保我們?nèi)匀豢梢韵駥?dǎo)入舊包一樣導(dǎo)入該包。

tests.py中的“””

簡單的向后兼容性測試用例

“””

類ConfigHelperCompatibilityTestCase(unittest.TestCase):

def test_backward_compatibility(self):

試試:

從.config導(dǎo)入CONFIG_NAME,

從.config導(dǎo)入LOGGING_LEVEL

從.config導(dǎo)入get_logging_level 從.config導(dǎo)入ConfigHelper,

但I(xiàn)mportError除外,例如e:

self.fail(e.message)

這是一個(gè)簡單的測試用例,您可能會(huì)注意到在該測試用例中未捕獲到某些向后兼容性問題。

步驟2:重組套件結(jié)構(gòu)

本節(jié)為您提供有關(guān)如何重新組織Python軟件包的想法。讓我們回顧一下config.py我們擁有的:

“”“

軟件包:

重組

”“” 之前的utils.config

CONFIG_NAME = {

“ ENABLE_LOGGING”:“ enable_logging”,

“ LOGGING_LEVEL”:“ logging_level”,

}

def get_logging_level():

通過

ConfigHelper類:

def get(self,config_name,default = None):

通過

def set(self,config_name,value):

通過

def _get_settings_helper(self):

通過

def get_logging_level():

通過

def is_logging_enabled():

通過

類LOGGING_LEVEL:

VERBOSE =“詳細(xì)”

STANDARD =“標(biāo)準(zhǔn)”

你能發(fā)現(xiàn)這里有什么問題嗎?這很雜亂,在一個(gè)文件中有常量,助手,重復(fù)的代碼。當(dāng)代碼config.py變大時(shí),將難以導(dǎo)航。通過這種凌亂的結(jié)構(gòu),您可以為循環(huán)依賴,隱藏的耦合和優(yōu)化最美味的意大利面條代碼的配方提供一個(gè)地方。

您如何重組config.py?對我而言,關(guān)注的分離是我的腦海。以下結(jié)構(gòu)通常被認(rèn)為是構(gòu)建Python包的一種好習(xí)慣(在Django中也使用了該結(jié)構(gòu))。

config/

├── abstracts.py # All the abstract classes should live here

├── constants.py # All the constants should live here

├── exceptions.py # All custom exceptions should live here

├── helpers.py # All helpers should live here

├── __init__.py # All backward compatible code in here

├── mixins.py # All mixins goes to here

├── serializers.py # All common serializers goes to here

└── tests.py # All `config` related tests should live here

讓我們config.py在重構(gòu)之前重新訪問一下,并確定各個(gè)代碼段應(yīng)位于何處。

“”“

軟件包:

重組

”“” 之前的utils.config

#這看起來像屬于utils.config.constants

CONFIG_NAME = {

“” ENABLE_LOGGING“:” enable_logging“,

” LOGGING_LEVEL“:” logging_level“,

}

#看起來像一個(gè)輔助函數(shù),轉(zhuǎn)到utils.config.helpers

def get_logging_level():

#看起來像是重復(fù)的方法

傳遞

#這看起來像一個(gè)幫助程序類,轉(zhuǎn)到utils.config.helpers

類ConfigHelper:

def get((自我,config_name,默認(rèn)=無):

通過

def set(self,config_name,value):

通過

def _get_settings_helper(self):

通過

def get_logging_level():

#這看起來像是重復(fù)的方法

傳遞

def is_logging_enabled():

通過

#這看起來像另一個(gè)常量,轉(zhuǎn)到utils.config.constants

類LOGGING_LEVEL:

VERBOSE =“詳細(xì)”

STANDARD =“標(biāo)準(zhǔn)”

在重構(gòu)之后,config.py應(yīng)該成為一個(gè)Python包c(diǎn)onfig用__init__.py它。

實(shí)用程序/

├──config.py # To be removed

└──config/

├── constants.py

├── helpers.py

├── __init__.py

└── tests.py

在utils.config.constants :

“”“

軟件包:

重組

”“” 之后的utils.config.constants

#不一致的編程構(gòu)造

CONFIG_NAME = {

“” ENABLE_LOGGING“:” enable_logging“,

” LOGGING_LEVEL“:” logging_level“,

}

#不一致的編程構(gòu)造

類LOGGING_LEVEL:

VERBOSE =“詳細(xì)”

STANDARD =“標(biāo)準(zhǔn)”

在utils.config.helpers :

“”“

軟件包:

重組

”“” 之后的utils.config.constants

def get_logging_level():

#這是重復(fù)的,刪除了此

通行證

ConfigHelper類:

def get(self,config_name,default = None):

通過

def set(self,config_name,value):

通過

def _get_settings_helper(self):

通過

def get_logging_level():

通過

def is_logging_enabled():

通過

  步驟3:消除和合并重復(fù)項(xiàng)

在中utils.config.helpers ,有2個(gè)相似的方法/功能get_logging_level()和ConfigHelper()._get_logging_level() 。假設(shè)兩個(gè)實(shí)現(xiàn)都相同,則意味著我們必須找到一個(gè)最佳的位置來托管該功能。

在這種情況下,我將刪除獨(dú)立服務(wù)器get_logging_level()并將其保留在中ConfigHelper。

“”“

軟件包:

刪除重復(fù)項(xiàng)后的utils.config.constants

”“”

ConfigHelper類:

def get(self,config_name,default = None):

通過

def set(self,config_name,value):

通過

def _get_settings_helper(self):

通過

def get_logging_level():

通過

def is_logging_enabled():

通過

  步驟4:分解

我個(gè)人是分解愛好者。除了擁有一個(gè)類之外ConfigHelper,我們還可以進(jìn)一步分解ConfigHelper為類和mixin的層次結(jié)構(gòu)。

我們托管AbstractBaseConfigHelper在abstracts.py:

“”“

在abstracts.py

‘’”

從ABC進(jìn)口ABCMeta

class AbstractBaseConfigHelper:

__metaclass__ = ABCMeta

def get(self,config_name):

通過

def set(self,config_name,value):

通過

def _get_settings_helper(self):

通過

在mixins.py :

“”“

在mixins.py

‘’”

類LoggingConfigMixin:

def is_logging_enabled():

通過

def get_logging_level():

通過

在helpers.py :

“”

在helpers.py中的

“””

類ConfigHelper(

AbstractBaseConfigHelper,

LoggingConfigMixin

):

通過

ConfigHelper 現(xiàn)在分解為多個(gè)類和混合。

  步驟5:填寫我們的向后兼容代碼

在步驟1中,我們在中添加了一些代碼。__init__.py. 但是,它基本上是不完整的。讓我們重新訪問該文件:

“”“

在__init__.py

這是向后兼容的代碼的生命。

這是為了確保重構(gòu)的包支持

進(jìn)口的舊路。

這是不完整的,我們將在后面再講__init__.py

‘’”

CONFIG_NAME = {}

def get_logging_level(* args,** kwargs):

通過

ConfigHelper類:

def get(self,* args,** kwargs):

pass

def set(自我,* args,** kwargs):

通過

def _get_settings_helper(self):

通過

def get_logging_level(self):

通過

def is_logging_enabled(self):

通過

LOGGING_LEVEL類:

通過

請注意,上面的代碼與我們新組織的config軟件包之間的橋梁仍然缺失。要建立橋梁,我們將其編輯__init__.py為:

__init__.py中的““”

這是向后兼容代碼所在的地方。

這是為了確保重構(gòu)的程序包支持

舊的導(dǎo)入方式。

“ 。”

從.constants導(dǎo)入CONFIG_NAME,

從.helpers導(dǎo)入LOGGING_LEVEL 從ConfigHelper導(dǎo)入為_ConfigHelper

def get_logging_level(* args,** kwargs):

返回_ConfigHelper()。get_logging_level()

類ConfigHelper(_ConfigHelper):

通過

  步驟6:通知開發(fā)人員

直到第5步,我們config的重構(gòu)都正確了。但是,我們需要及時(shí)通知開發(fā)人員有關(guān)更改的信息。有什么簡單的方法嗎?是。每當(dāng)開發(fā)人員嘗試導(dǎo)入過時(shí)的函數(shù)/類/方法時(shí),我們都可以發(fā)出警告消息。例如,我們用裝飾器注釋舊的函數(shù)/類/方法:

“”“

decorators.py

”“”

def refactored_class(消息):

def cls_wrapper(cls):

類包裝(cls,對象):

def __init __(self,* args,** kwargs):

warnings.warn(message,F(xiàn)utureWarning)

super(Wrapped,self).__ init __( * args,** kwargs)

return包裝的

return cls_wrapper

def重構(gòu)(消息):

def裝飾器(func):

def glow_warning(* args,** kwargs):

warnings.warn(消息,F(xiàn)utureWarning)

返回func(* args,** kwargs)

返回return_warning

返回裝飾器

在我們的中__init__.py ,我們添加裝飾器,如下所示:

__init__.py中的““”

這是向后兼容代碼所在的地方。

這是為了確保重構(gòu)的程序包支持

舊的導(dǎo)入方式。

“ 。”

從.constants導(dǎo)入CONFIG_NAME,

從.helpers導(dǎo)入LOGGING_LEVEL 從ConfigHelper導(dǎo)入為_ConfigHelper

@refactored('get_logging_level()被重構(gòu)和棄用。')

def get_logging_level(* args,** kwargs):

返回_ConfigHelper()。get_logging_level()

@refactored_class( 'config.ConfigHelper被重構(gòu)和棄用請使用config.helpers.ConfigHelper。')

類ConfigHelper(_ConfigHelper):

通過

  重組后

重組我們的Python包之后,我們運(yùn)行測試用例并確保已通過所有測試。

  結(jié)論

到現(xiàn)在為止,您應(yīng)該能夠了解代碼庫的質(zhì)量,了解重構(gòu)的概念,確定重構(gòu)的需求,并了解如何重構(gòu)/重組Python包。想了解更多關(guān)于Python的信息,請繼續(xù)關(guān)注中培偉業(yè)。

標(biāo)簽: Python 軟件研發(fā)
主站蜘蛛池模板: 亚洲国产精品一区二区美利坚 | 久久久久久久电影一区 | 亚洲美免无码中文字幕 | 人妻丝袜无码专区视频网站 | 一级黄色录像免费观看 | 色婷婷97| 日韩一区欧美一区 | 黑人粗黑大躁护士 | 久久三级无码网站 | 懂色一区二区三区在线播放 | 国产美女视频91 | 一个人看www在线高清免费看 | 性生活视频一级片 | 久久久SS麻豆欧美国产日韩 | 黄色网址av | 午夜免费视频一区二区三区 | 中文字幕亚洲成人 | 成人软件在线观看 | 九七97影院理论片手机在线观看 | 91美女厕所偷拍 | 人成免费视频 | 91久久久久久白丝白浆欲热蜜臀 | 国产愉拍精品手机 | 少妇啪啪免费观看欧美三p poronoⅵdeos中国少妇 | 操av在线| gogogo免费视频韩国大牛 | 欧洲一区二区三区四区 | 久久免费视频1 | 日韩加勒比一本无码精品 | 一级做人爰全过程 | 亚洲一区国产二区 | 国产高潮国语对白精品视频网站 | 制服丝袜电影在线观看 | 久久99久久精品视频 | 久久成人免费 | 浪漫樱花动漫观看免费视频 | 日日摸人人看夜夜爱 | 日日夜av| 国产又粗又大又硬点视频 | 日本一区二区小视频 | 青草视频网 |