通过 Python 开发关键软件:成功的故事

随着客户专家和行业合作伙伴的加入,Integrated Informatics Inc. 开发了“大地测量工具包”这一商品。通过此工具包,用户可以为地震测量及井眼测量加载、分析、审核和生成报表以及根据此类报表制图。工具箱中的这些工具采用根据自定义标准和行业标准(如 UKOOA、SEG-Y、SEGP1 等)进行格式化的文本和二进制数据,并将该数据加载到要素类和表的方案中。

Integrated Informatics Inc. 在下面讨论了选择 Python 作为开发和交付其商品的语言的原因。他们讨论了 Python 如何适应他们在软件开发环境方面的优势,并举例说明 Python 为何比单一脚本语言优越得多。最后,他们讨论了其在产品中使用的开源库。

解读各种测量

地震测量和井眼测量数据是所有石油和天然气公司数据库不可或缺的组成部分,可用于实现如可视化、资源探勘和清点存货等各种用途。石油和天然气行业有着悠久而丰富的计算机使用历史和数字数据存储历史。在这期间,出现了许多针对测量存储的不同标准,很多公司选择了最适合其需求的标准,有些公司甚至开发了自己的标准。结果是,测量文件大量增加,这些文件看起来相似,但在细微之处通常存在差异。

由于测量信息已经存在了很长时间,因此,出现大量用于处理数据的工具不足为奇。问题是这类工具通常不是大型软件解决方案的组成部分。构建这些工具的目的是进行查看和执行一些处理工作,但它们通常不能很好地处理企业级数据库的其余方面。这样就不是很理想,因为这些数据的全部优势只有在叠加和集成在一起以及同时进行分析时才能得以体现。如果大部分石油和天然气公司将 ESRI 堆栈用作其主要 GIS 软件,那么,引入可将各种格式的井眼和地震数据直接加载到 ArcGIS 中的功能将极具吸引力。

公司环境中的开发 - 为何采用 Python?

在开发“大地测量工具”时,我们可以选择使用基于 ArcObjects 的方法,但我们选择了 Python,原因主要有两个:1) 开发速度和 2) 易部署性。

开发速度

Python 和“地理处理框架”紧密集成在一起,Python 是实现脚本工具的推荐语言。选择 Python 意味着,作为开发人员,您可以花时间编写功能代码,而不是用户界面代码。这进而意味着,您向客户交付产品的速度要比预期更快,因为已经解决了项目的核心部分(用户界面)。例如,使用地理处理框架创建工具时,您所得到的工具的外观和功能与 ArcGIS 提供的核心工具相似。这意味着,默认的验证、用户界面控件和文档样式使得自定义工具能够与应用程序(如模型构建器)的其他部分实现无缝合并。

值得注意的是,初级程序员的开发时间也会因 Python 本身的特性而减少。Guido van Rossum 是 Python 的创始人,他创作的这种语言简单、直观、开源、像简明英语一样易懂,并且适合日常任务。对于您来说,GIS 分析人员变成了开发人员或业余爱好者,这意味着 Python 易于学习和阅读。您只需花少量时间来学习,而将更多时间用在创建解决方案和提高工作流上。

“大地测量工具箱”当前包含超多 40 种工具。这节省了大量的时间,因为我们无需为每个工具编写 UI 程序。我们可以将所节省的时间投入到测试工具、构建测试装置、提高性能和引入创新性和新功能上。

易部署性

Python 解决方案的优点之一是易于部署。无需注册 Dll、无需运行复杂的安装步骤,并且无需担心 COM 依赖性。通过“大地测量工具箱”,我们只需在办公室中压缩解决方案,然后在客户网络上的可访问位置将其解压缩。使用合适的代码,客户只需将工具箱添加到 ArcGIS Desktop 中,便可访问该功能。

在许多大型公司,软件安装由 IT 部门负责,向公司员工推出软件是他们的工作,通常也是令他们头痛的事情。作为解决方案提供者,让安装变得越简单,IT 部门就会对您越感激,而且您的客户可以更快地访问新功能。对于 Integrated Informatics,使用 Python 意味着我们不仅确保向客户提供尽可能最简单的安装过程、尽可能将要求的周转时间缩至最短,而且还确保令客户满意。

公司环境中的开发 - 自动测试

“大地测量工具箱”的 Python 代码包含的代码行远超过 5000(不包括开源数据包)。与所有商品一样,我们的客户定期向我们发送增强申请,我们也尽可能快地满足这些申请。申请范围从新参数到整个新工具集。因此,了解何时更改会对现有功能产生影响以及是否有更改导致工具无法运行对我们来说非常重要。在超过 40 种工具中,每个工具都包含多达几十个参数,手动测试各个工具完全无效。要在所需的周转时间内按要求达到预期的质量级别,自动测试绝对有必要。

正如他们所述,Python 是一个“遥控器”,因此对于测试来说,我们只需关注 Python 本身至少为解决方案的一部分。Python 具有一个极为出众的标准模块,名为 unittest,它是 Python 核心安装程序的一部分。我们为每个工具都提供了一个独立的测试脚本,用于测试参数和数据输入的各种不同排列。使用各个工具的各种测试套件,我们可以非常清楚地知道所测试的内容,并能充分有效地利用好工作日。

各工具的测试套件是很好的解决方案,但重要的是这些测试脚本会定期自动运行,而不只是在您让其运行时才运行。最近流行“持续集成”的概念,此概念是指在将各更改检入到代码库中后,触发器启动测试套件中的所有测试。对于某些类型的代码库和测试,这是一种极佳的选择,但对于执行大量处理操作的工具,如此高频率的测试并不总是很实用。定期触发测试这一想法更为重要。触发时间可以是每晚、每周,甚至每个月,具体取决于代码库的更新频率。通过自动运行测试套件,您始终可以实时了解您的代码,因此,在代码库中引入漏洞时,您可以很快知道出现了问题并对其进行更正。

代码重复使用:Python 的类

编程的基本原则之一是避免代码重复。有几种方法可以避免代码重复,并使代码库更为高效和有效。首先,您可以使用函数来添加需要重复使用的代码段。函数可以执行很多操作,并且是减少代码重复的第一步。对于大型代码库,函数的功能很有限(虽然也使用),而在许多情况下,恰当的方法是开始创建类。

尽管 Python 被视为 Esri 软件环境中的脚本语言(例如,注意名称“arcgisscripting”中使用的“scripting”),但它实际上是完全面向对象的 (OO) 编程语言。同样,程序员可以使用继承来创建类和完全类层级。在大型代码库中,精心编写的 OO 样式代码有助于在概念上提取复杂的概念、减少代码重复以及将代码分解成短小而简洁的块,使其更易于更改、管理和测试。

以下是一个十分简单的示例,旨在简要介绍 Python 类和小型类层级。

from os.path import basename

class AbstractReport(object):
    """
    Base parsing class
    """
    _table_fields = None

    def __init__(self, file_path, records):
        """
        initializes the class
        """
        self._file_path = file_path
        self._records = records

    def calc_coords(self):
        """
        calculates coordinates to be written to report table
        """
        raise NotImplementedError

    def write_table(self):
        """
        parses the records in the file
        """

        coords = self.calc_coords()
        print ('writes a table using fields %s '
               '\nand calculated coords %s to file %s' %
               (self._table_fields, coords, basename(self._file_path)))


class OrthoCheckReport(AbstractReport):
    """
    Orthongonal Check Report Class
    """
    _table_fields = ['FLD_A', 'FLD_B', 'FLD_C']

    def calc_coords(self):
        """
        calculates coordinates to be written to report table
        """
        print ('special Orthogonal Check report calculations using records %s' %
               self._records)
        return ['ortho', 'check', 'results']


class QAQCReport(AbstractReport):
    """
    QAQC Report class
    """
    _table_fields = ['FLD_X', 'FLD_Y', 'FLD_Z']

    def calc_coords(self):
        """
        calculates coordinates to be written to report table
        """
        print ('special QAQC report calculations using records %s' %
               self._records)
        return ['qaqc', 'report', 'results']


if __name__ == '__main__':
    input_file = r'c:\test\seismic_file.txt'
    records = ['reca', 'recb', 'recc']

    ocr = OrthoCheckReport(input_file, records)
    qqr = QAQCReport(input_file, records)

    ocr.write_table()
    qqr.write_table()

此代码在运行时会输出:

special Orthogonal Check report calculations using records ['reca', 'recb', 'recc']
writes a table using fields ['FLD_A', 'FLD_B', 'FLD_C']
and calculated coords ['ortho', 'check', 'results'] to file seismic_file.txt

special QAQC report calculations using records ['reca', 'recb', 'recc']
writes a table using fields ['FLD_X', 'FLD_Y', 'FLD_Z']
and calculated coords ['qaqc', 'report', 'results'] to file seismic_file.txt

在上述层级中,write_table 方法的代码仅显示在一个类中(AbstractReport 类),但其他类(OrthoCheckReportQAQCReport)的实例仍可调用此方法。这是因为 OrthoCheckReportQAQCReport 都是 AbtractReport“基类”和“继承”的“子类”。从基类继承的子类可以访问基类的所有方法和属性。这意味着不管以上创建了什么类,调用 write_report 都会采用相同的方法。

calc_coords 方法演示了当要求代码在子类中与在基类中不同时会发生什么情况。每种子类都会采用不同的方式来计算表的坐标,因此各子类具有唯一的代码。为了确保这一点,子类应从基类“重载”calc_coords 方法。如上面演示的那样,Python 中的“重载”与将同名方法添加到子类一样简单。这意味着尽管 write_table 方法对所有类都采用完全相同的代码,但当其调用 calc_coords 时,将沿着唯一路径通过各个子类。执行此操作后,将会排除代码中不必要的逻辑(如额外的“if”语句),从而使代码更简洁、更易于阅读。

要使类继承自其他类,只需在类声明中包括所需基类的名称:

class OrthoCheckReport(AbstractReport):

执行此操作时,请确保子类的初始化 (__init__) 与基类的初始化相同。如果不同,还需要为子类编写 __init__。有关示例,可参阅文档和帮助。

开源数据包的使用和交付

为什么开源?

Python 已成为最受欢迎的开源编程语言之一。同样,Python 的用户已经创建了差不多成千上万个开源数据包,其中许多数据包可直接用于在应用程序中执行的各种操作。在“大地测量工具箱”中,我们使用许多开源数据包来实现我们的客户目标。

举例来说,假如一个普通客户请求:根据 ArcGIS 中执行的分析来创建 pdf 报表。事实证明,有一种易于使用的跨平台开源数据包,名为“ReportLab 工具包”,可用于创建 pdf 文档。此数据包中含有综合而强大的 pdf 操控功能、良好的文档以及帮助用户入门的教程。使用此数据包,我们可以在极短的总开发时间内相对轻松地将报表和数据写入 pdf 文档。这样,下次在获得申请时,可以在直接投入开发前先自问“其他人是否已经执行过此操作”,并搜索 Internet。

所有重要许可

找到了所需的数据包后,需要做的第一件事就是阅读许可。“开源”许可以各种不同的形式出现,编写的许多许可是用来防止软件变为“关闭源”。仔细阅读许可并确保使用的数据包正确无误极其重要。对于 ReportLab 工具包来说,许可是一种“Berkeley 软件分发许可”(通常称为“BSD”许可)形式。此许可十分随意,允许软件在其他专用软件中使用和分发(少数情况下)。其他许可并没有这么随意,它们旨在确保采用其他开源软件的软件也是开源(例如 GPL)。花些时间来了解最常用的许可,以便知道开源数据包可以使用哪些许可以及如何使用。

以下网站提供了一个很有用的许可表:http://en.wikipedia.org/wiki/Comparison_of_free_software_licenses。另一个非常有用的网站是 www.opensource.org,其中包含了关于所有开源许可的信息。

交付开源软件包

对于“大地测量工具箱”,我们已将“ReportLab 工具包”作为一个子软件包合并到了我们的软件包中,这意味着我们实际上是将此代码与我们自己的代码一起交付。虽然在代码中参考开源软件包看似很简单,但真正合并此软件包非常重要。这使您可以控制正在使用的软件包的版本,并确保软件包在客户端计算机上可用。应该避免要求客户自己安装软件包,因为这对客户来说十分困难。此外,在交付包含您自己代码的开源软件包时,必须阅读许可并履行许可中所述的义务。

结论

为了在“大地测量工具箱”中提供该功能,我们选择 Python 作为开发语言。Python 和“地理处理框架”使得我们能够快速提供此功能,并使其外观与其余 ArcGIS 产品十分类似。通过使用作为任何 Python 安装程序组成部分的模块,我们创建了一套 unittest,用来确保我们的产品在多次代码交付和新功能请求方面的质量。我们使用 Python 的功能作为面向对象的编程语言,这减少了我们代码库中的代码重复,从而使代码更易于维护。最后,由于 Python 拥有如此大的开源社区,因此我们可以找到缩短开发时间并且有助于我们满足客户需求的开源软件包。

关于 Integrated Informatics

Integrated Informatics Inc. 是一家在“地理信息系统”实现和开发方面具有领先地位的咨询公司。Integrated 成立于 2002 年,主要为办事处分布在卡尔加里市、阿尔伯达省、圣约翰斯市、纽芬兰省以及德克萨斯州休斯敦市的北美客户提供空间数据管理和自动制图解决方案。

Integrated 与其客户保持长期合作关系,这些客户包括大型和超大型的独立综合能源公司、省政府、州政府,以及工程和环境咨询公司。我们在开发和实施支持业务目标和提供企业价值的战略、系统和技术方面拥有经过证明的成绩记录。

我们的实力来源于我们的员工。我们的团队由在地理信息系统领域、空间数据管理领域、项目数据管理领域和应用程序开发领域具有丰富经验的专业人才以及学科特级专家组成。我们拥有管道工程学科、环境学科和地球科学分析学科的在职专家。我们的工作环境提供专业的开发、连续的培训、行业参与和内部基金资助的研究及开发,因而促成了各种想法、创新和实施。

Integrated 是 Silver Tier International Esri 业务合作伙伴,积极参与了对 Esri 整体测试的 beta 计划,并且加入了南阿尔伯达技术学院 (SAIT) 的 GIS 教学计划的咨询委员会。有关我们的独特解决方案的详细信息,请访问我们的网站 www.integrated-informatics.com 或发送邮件至 gis@integrated-informatics.com