使用类作为函数和“全局”变量容器:糟糕的设计?

时间:2017-05-04 14:20:15

标签: python algorithm function class

我花了几个月的时间从头开始重写我的Python算法的新版本。我的目标之一是编写一个完整的文档代码,易于阅读和理解“任何人”。

在同一个项目文件夹中,我放了很多不同的模块,每个模块都包含一个类。我使用类作为函数和相关变量容器,这样一个类包含具有特定任务的所有函数,例如在Excel文件上写入算法的所有输出结果。

这是一个例子:

Algorithm.py

import os
import pandas as pd
import numpy as np
from Observer import Observer


def main(hdf_path):

    for hdf_file in os.listdir(hdf_path):

        filename = str(hdf_file.replace('.hdf', '.xlsx'))
        Observer.create_workbook(filename)

        dataframe = pd.read_hdf(hdf_file)
        years_array = dataframe.index.levels[0].values

        for year in years_array:
            year_mean = np.mean(dataframe.loc[year].values)
            Observer.mean_values = np.append(Observer.mean_values, dataframe_mean)

        Observer.export_result()

if __name__ == "main":

    hdf_path = 'bla/bla/bla/'
    main(hdf_path)

Observer.py

import numpy as np
import openpyxl


class Observer:

    workbook = None
    workbookname = None
    mean_values = np.array([])


    def create_workbook(filename):

        Observer.workbook = openpyxl.Workbook()
        Observer.workbookname = filename
        # do other things

    def save_workbook():

        Observer.workbook.save('results_path' + Observer.workbookname)

    def export_results():

        # print Observer.mean_values values in different workbook cells
        # export result on a specific sheet

我希望你能从这个简单的例子中理解我如何在我的项目中使用class。对于每个类,我定义了很多变量(例如工作簿),我从其他模块中调用它们就好像它们是全局变量一样。通过这种方式,我可以从任何地方轻松访问它们,我不需要将它们明确地传递给函数,因为我可以简单地编写Classname.varname。

我的问题是:设计不好吗?它会造成一些问题或性能下降吗?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

  

我的问题是:设计不好吗?

是。

  

我可以简单地编写Classname.varname。

当您强制执行调用Classname.varname时,您在类之间创建了非常强大的coupling。访问此变量的类现在与Classname强烈耦合。这可以防止您通过传递不同的参数来改变OOP方式的行为,并且会使类的测试复杂化 - 因为您将无法模拟Classname并使用其模拟而不是“真正的”类。

当您尝试在应用的两个部分中运行2个非常相似的代码时,这将导致代码重复,这些代码仅在这些参数中有所不同。您最终将创建两个几乎相同的类,一个使用Workbook,另一个使用Notepad类。

记住恶性循环:

Hard to test code -> Fear of refactor -> Sloppy code
   ^                                      |
   |                                      |
    ---------------------------------------

使用适当的对象,能够模拟它们(以及dependency injection)将保证您的代码易于测试,其余的将会跟随。