python代碼佈局

閱讀本文需要15分鐘

前言

本人比較在意對代碼的管理,不僅是爲了以後的維護,更是基於對閱讀者的尊敬
具體類一般先實現功能後再優化,不要奢望一次就能寫出好的代碼
許多規範參照了《Clean Code》

涉及到的知識點

匿名函數(lambda函數) 點擊此處查看匿名函數知識點
裝飾器 點擊此處查看裝飾器知識點

栗子

對matplotlib.pyplot進行封裝,現有一個字典,key存屬性,value存值,基於這個字典畫出對應的圖片。

{
	"x":[1,2,3,4,5,6,7,8,9],
	"y":[1,2,3,4,5,6,7,8,9],
	"title":"Figure",
	.......
}

1.規劃

文件介紹
test.xml 是方便測試臨時寫的一個存儲所有畫圖有關的屬性和值,真正項目時這個xml是由前端生成的
demoCmd.py 因爲前端調用python我是通過命令行調用的,所以這個文件處理前端命令,是主函數
Demo.py 這個是所有畫圖功能,供其他文件調用
CONST.py 所有有關的常量、映射放在這裏,相當於是一個配置文件。這樣做的目的是當我們需要添加或刪除某些功能時,只需修改CONST.py裏面的對應關係,不需要再動其他文件的代碼

test.xml

<?xml version="1.0" encoding="UTF-8"?>
<Values>
    <x>
        <value type="list">[-6.283, -6.083, -5.883, -5.683, -5.483, -5.2829999999999995, -5.082999999999999, -4.882999999999999, -4.682999999999999, -4.482999999999999, -4.282999999999999, -4.082999999999998, -3.8829999999999982, -3.682999999999998, -3.482999999999998, -3.2829999999999977, -3.0829999999999975, -2.8829999999999973, -2.682999999999997, -2.482999999999997, -2.282999999999997, -2.0829999999999966, -1.8829999999999967, -1.6829999999999967, -1.4829999999999968, -1.2829999999999968, -1.0829999999999969, -0.8829999999999969, -0.6829999999999969, -0.48299999999999693, -0.2829999999999969, -0.08299999999999691, 0.1170000000000031, 0.3170000000000031, 0.5170000000000031, 0.7170000000000032, 0.9170000000000031, 1.117000000000003, 1.317000000000003, 1.517000000000003, 1.717000000000003, 1.917000000000003, 2.117000000000003, 2.3170000000000033, 2.5170000000000035, 2.7170000000000036, 2.917000000000004, 3.117000000000004, 3.317000000000004, 3.5170000000000043, 3.7170000000000045, 3.9170000000000047, 4.117000000000004, 4.317000000000005, 4.517000000000005, 4.717000000000005, 4.917000000000005, 5.117000000000005, 5.3170000000000055, 5.517000000000006, 5.717000000000006, 5.917000000000006, 6.117000000000006]</value>
    </x>
    <y>
        <value type="list">[0.00018530717852557836, 0.19885094075634005, 0.3895890148366298, 0.5647954043146128, 0.7174851833375362, 0.8415710922562171, 0.9321062174577968, 0.985481209200597, 0.9995681749983588, 0.9738055119787167, 0.9092202962174792, 0.8083873364566131, 0.675326524604979, 0.5153425753334286, 0.3348135438408722, 0.1409365529206157, -0.05855913361357452, -0.2557202522846237, -0.4426866114690056, -0.6120044524325037, -0.756923607169248, -0.8716666062987226, -0.9516590085381078, -0.9937117692407419, -0.9961483775425712, -0.9588716935597641, -0.8833678210493362, -0.7726468611420304, -0.6311229091091574, -0.4644380783136112, -0.2792375669548097, -0.08290473498661866, 0.11673324714446892, 0.31171744308496974, 0.4942744482509477, 0.6571262909383787, 0.793780582088022, 0.8987893463492944, 0.9679662156654169, 0.9985533265569903, 0.9893312674359778, 0.9406676926976436, 0.8545026655000147, 0.7342713135679936, 0.5847668814911388, 0.41194963918783684, 0.22270926475237623, 0.024590174730963994, -0.17450924795818812, -0.3666515376270242, -0.5441765875265056, -0.7000070341298301, -0.8279304092823339, -0.9228468117022411, -0.9809722239510984, -0.9999893692678891, -0.9791400940809049, -0.9192555931981585, -0.8227232726933746, -0.6933915715597261, -0.5364165365916276, -0.358056267069889, -0.1654214240919641]</value>
    </y>
    <style>
        <value type="string">g-</value>
    </style>
    <figure>
        <value type="list">[8,6]</value>
    </figure>
    <title>
        <value type="list">['sinX Figure', 14, 'b']</value>
    </title>
    <xlabel>
        <value type="list">["x axis",14,"b"]</value>
    </xlabel>
    <ylabel>
        <value type="list">["y axis",17,"r"]</value>
    </ylabel>
    <xlim>
        <value type="list">[-7,7]</value>
    </xlim>
    <ylim>
        <value type="list">[-2,2]</value>
    </ylim>
    <xticks>
        <value type="list">[10]</value>
    </xticks>
    <yticks>
        <value type="list">[-10]</value>
    </yticks>
    <xscale>
        <value type="string">linear</value>
    </xscale>
    <yscale>
        <value type="string">linear</value>
    </yscale>
    <axhline>
        <value type="list">[1,-1]</value>
    </axhline>
    <axvline>
        <value type="list">[2]</value>
    </axvline>
    <axis>
        <value type="string">on</value>
    </axis>
    <grid>
        <value type="boolean">True</value>
    </grid>
    <legend>
        <value type="string">best</value>
    </legend>
    <label>
        <value type="string">plotFigure</value>
    </label>
</Values>

CONST.py

FigureFeature = {
    "plot":['title','xlabel', 'ylabel', 'xlim', 'ylim', 'xticks', 'yticks', 'xscale', 'yscale', 'axhline', 'axvline', 'axis', 'grid', 'legend'],
    "scatter":['title','xlabel', 'ylabel', 'xlim', 'ylim', 'xticks', 'yticks', 'xscale', 'yscale', 'axhline', 'axvline', 'axis', 'grid','legend'],
    }
###利用字典存lambda函數
map_function = {  
        "title":lambda title:plt.title(title[0],fontsize=title[1],color=title[2]),
        "xlabel":lambda xlabel:plt.xlabel(xlabel[0],fontsize=xlabel[1],color=xlabel[2]),
        "ylabel":lambda ylabel:plt.ylabel(ylabel[0],fontsize=ylabel[1],color=ylabel[2]),
        "xlim":lambda xlim:plt.xlim(xlim[0],xlim[1]),
        "ylim":lambda ylim:plt.ylim(ylim[0],ylim[1]),
        "xticks":lambda xticks:plt.xticks(xticks),
        "yticks":lambda yticks:plt.yticks(yticks),
        "xscale":lambda xscale:plt.xscale(xscale),
        "yscale":lambda yscale:plt.yscale(yscale),
        "axhline":lambda axhline:plt.axhline(axhline[0]),
        "axvline":lambda axvline:plt.axvline(axvline[0]),
        "axis":lambda axis:plt.axis(axis),
        "grid":lambda grid:plt.grid(grid),
        "legend":lambda legend:plt.legend(loc=legend)
     }

fun_default = lambda x:x

proper_plot = []

前端調用的cmd命令爲,(也就是文件不是通過點擊F5運行的,而是輸入這條命令啓動的)

python demoCmd.py label=plot path_xml_args=./test.xml path_xml_return=./return.xml path_picture=./test.png

demoCmd.py

import parsexml
from Demo import Demo


if __name__ == "__main__":
    Error = False
    args = parsexml.parse()  ##解析cmd參數爲字典
	"""Example
	>>> python demoCmd.py label=plot path_xml_args=./test.xml path_xml_return=./return.xml path_picture=./test.png
	{
	    "label":"plot"
	    "path_xml_args":"./test.xml"
	    "path_xml_return":"./temp/return.xml"
	    "path_picture":"./temp/test.png"
	}
	"""
    if args == False:
        Error = True
        parsexml.save({"status":0}, path_xml_return)   ##寫出錯誤結果到xml文件
        #print("解析錯誤,注意等號左右不要有空格")
    label = args.get("label",False)
    path_xml_args = args.get("path_xml_args",False)
    path_xml_return = args.get("path_xml_return",False)
    path_picture = args.get("path_picture",False)
    
    args_xml = parsexml.read(path_xml_args) ##解析xml爲字典,數據太多就不展示了,

    draw = Demo()
    if label == "plot":
        result = draw.plot(args_xml, filePath_png=path_picture)
    elif label == "scatter":
        result = draw.scatter(args_xml, filePath_png=path_picture)
    elif label == "hist":
        result = draw.hist(args_xml, filePath_png=path_picture)
    elif label == "bar":
        result = draw.bar(args_xml, filePath_png=path_picture)
    elif label == "barh":
        result = draw.barh(args_xml, filePath_png=path_picture)
    elif label == "pie":
        result = draw.pie(args_xml, filePath_png=path_picture)
    else:
        pass

    parsexml.save({"status":0}, path_xml_return) if Error else parsexml.save({"status":1}, path_xml_return)   ##寫到xml文件


Demo.py

import numpy as np
import matplotlib.pyplot as plt
from CONST import FigureFeature
from CONST import map_function
from CONST import fun_default

"""定義一個畫圖函數裝飾器"""
def addDecorate(type_):
    def outer(func):
        def inner(*args, **kwargs):
            try:
                items,filePath_png = func(*args, **kwargs)
                feature = tuple(set(FigureFeature.get(type_)) & set(items.keys()))
                for i in feature:
                    map_function.get(i,fun_default) (items.get(i,"nothing"))
                plt.savefig(filePath_png)
                plt.show()
            except Exception as e:
                print(e)
                return False
            return True
        return inner
    return outer


class Demo(MatPlotDrawFigure):
    def __init__(self):
        pass

    @addDecorate(type_='plot')
    def plot(self,items,filePath_png):
        plt.figure(figsize = items.get("figure",[0,0]))
        plt.plot(items.get("x",[]), items.get("y",[]), items.get("style",""), label = items.get("label","plot"))
        return items,filePath_png
    
    @addDecorate(type_='scatter')
    def scatter(self,items,filePath_png):
        plt.figure(figsize = items.get("figure",[0,0]))
        plt.scatter(items.get("x",[]), items.get("y",[]), label=items.get("label",""))
        return items,filePath_png
    
    @addDecorate(type_='hist')
    def hist(self,items,filePath_png):
        plt.figure(figsize = items.get("figure",[0,0]))
        plt.hist(items.get("values",[]), items.get("bins",[]))
        return items,filePath_png
    
    @addDecorate(type_='bar')
    def bar(self,items,filePath_png):
        plt.figure(figsize = items.get("figure",[0,0]))
        plt.bar(items.get("xlabel",[]), items.get("values",[]))
        return items,filePath_png
    
    @addDecorate(type_='barh')
    def barh(self,items,filePath_png):
        plt.figure(figsize = items.get("figure",[0,0]))
        plt.barh(items.get("values",[]), items.get("ylabel",[]), label=items.get("label",""))
        return items,filePath_png
    
    @addDecorate(type_='pie')
    def pie(self,items,filePath_png):
        plt.figure(figsize = items.get("figure",[0,0]))
        plt.pie(items.get("proportion",[]), labels=items.get("labels",[]), explode=items.get("explode",[]), autopct=items.get("autopct",'%1.1f%%'), shadow=items.get("shadow",True))
        return items,filePath_png

這裏簡單畫出兩種類型的圖(不太好看,只是說明了程序是沒有問題的)

plot
在這裏插入圖片描述

scatter
在這裏插入圖片描述

未完!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章