如何在Python模块中向主函数传递参数?

28

我最近开始学习更多关于Python包和模块的知识。我正在更新我的现有模块,以便可以将其作为脚本运行或导入到我的其他代码中作为模块使用。我不确定如何在我的模块内构建输入参数并将它们传递给模块内的 main() 函数。

我已经编写了我的 main() 函数,并在 if __name__ == '__main__' 下调用它,传递输入参数。目前,这些输入是硬编码的,以显示我想要实现的内容。如果您能提供帮助,告诉我如何正确构造用户将传递的输入参数,然后将其传递到主函数中,我将不胜感激。

正如我所说的,我正在尝试将以下内容用作脚本直接使用或作为模块导入到我的其他代码中并从那里运行。如果我将其作为模块导入,我是否需要在导入时调用 main() 函数?我编写的以下结构是否正确?任何建议都将不胜感激。

'''
Created on March 12, 2017

Create a new ArcHydro Schema

File Geodatabase and Rasters

Folder

@author: PeterW
'''
# import site-packages and modules
import re
from pathlib import Path
import arcpy

# set environment settings
arcpy.env.overwriteOutput = True


def archydro_rasters_folder(workspace):
    """Create rasters folder directory
    if it doens't already exist"""
    model_name = Path(workspace).name
    layers_name = re.sub(r"\D+", "Layers", model_name)
    layers_folder = Path(workspace, layers_name)
    if layers_folder.exists():
        arcpy.AddMessage("Rasters folder: {0} exists".format(layers_name))
    else:
        layers_folder.mkdir(parents=True)
        arcpy.AddMessage("Rasters folder {0} created".format(layers_name))


def archydro_fgdb_schema(workspace, schema, dem):
    """Create file geodatabase using XML
    schema and set coordinate system based
    on input DEM if it doesn't already exist"""
    model_name = Path(workspace).name
    fgdb = "{0}.gdb".format(model_name)
    if arcpy.Exists(str(Path(workspace, fgdb))):
        arcpy.AddMessage("{0} file geodatabase exists".format(fgdb))
    else:
        new_fgdb = arcpy.CreateFileGDB_management(str(workspace), fgdb)
        import_type = "SCHEMA_ONLY"
        config_keyword = "DEFAULTS"
        arcpy.AddMessage("New {0} file geodatabase created".format(fgdb))
        arcpy.ImportXMLWorkspaceDocument_management(new_fgdb, schema,
                                                    import_type,
                                                    config_keyword)
        arcpy.AddMessage("ArcHydro schema imported")
        projection = arcpy.Describe(dem).spatialReference
        projection_name = projection.PCSName
        feature_dataset = Path(workspace, fgdb, "Layers")
        arcpy.DefineProjection_management(str(feature_dataset),
                                          projection)
        arcpy.AddMessage("Changed projection to {0}".format(projection_name))


def main(workspace, dem, schema):
    """main function to create rasters folder
    and file geodatabase"""
    archydro_rasters_folder(workspace)
    archydro_fgdb_schema(schema, dem, workspace)

if __name__ == '__main__':
    main(workspace = r"E:\Projects\2016\01_Bertrand_Small_Projects\G113268\ArcHydro\Model04",
         dem = r"E:\Projects\2016\01_Bertrand_Small_Projects\G113268\ArcHydro\DEM2\raw",
         schema = r"E:\Python\Masters\Schema\ESRI_UC12\ModelBuilder\Schema\Model01.xml")

更新日期:17/03/13

下面是基于Jonathan的建议更新的Python模块:

'''
Created on March 12, 2017

Create a new ArcHydro Schema

File Geodatabase and Rasters

Folder

@author: PeterW
'''
# import site-packages and modules
import re
from pathlib import Path
import arcpy
import argparse

# set environment settings
arcpy.env.overwriteOutput = True


def rasters_directory(workspace):
    """Create rasters folder directory
    if it doens't already exist"""
    model_name = Path(workspace).name
    layers_name = re.sub(r"\D+", "Layers", model_name)
    layers_folder = Path(workspace, layers_name)
    if layers_folder.exists():
        arcpy.AddMessage("Rasters folder: {0} exists".format(layers_name))
    else:
        layers_folder.mkdir(parents=True)
        arcpy.AddMessage("Rasters folder {0} created".format(layers_name))


def fgdb_schema(workspace, schema, dem):
    """Create file geodatabase using XML
    schema and set coordinate system based
    on input DEM if it doesn't already exist"""
    model_name = Path(workspace).name
    fgdb = "{0}.gdb".format(model_name)
    if arcpy.Exists(str(Path(workspace, fgdb))):
        arcpy.AddMessage("{0} file geodatabase exists".format(fgdb))
    else:
        new_fgdb = arcpy.CreateFileGDB_management(str(workspace), fgdb)
        import_type = "SCHEMA_ONLY"
        config_keyword = "DEFAULTS"
        arcpy.AddMessage("New {0} file geodatabase created".format(fgdb))
        arcpy.ImportXMLWorkspaceDocument_management(new_fgdb, schema,
                                                    import_type,
                                                    config_keyword)
        arcpy.AddMessage("ArcHydro schema imported")
        projection = arcpy.Describe(dem).spatialReference
        projection_name = projection.PCSName
        feature_dataset = Path(workspace, fgdb, "Layers")
        arcpy.DefineProjection_management(str(feature_dataset),
                                          projection)
        arcpy.AddMessage("Changed projection to {0}".format(projection_name))


def model_schema(workspace, schema, dem):
    """Create model schema: rasters folder
    and file geodatabase"""
    rasters_directory(workspace)
    fgdb_schema(schema, dem, workspace)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Create a ArcHydro schema')
    parser.add_argument('--workspace', metavar='path', required=True,
                        help='the path to workspace')
    parser.add_argument('--schema', metavar='path', required=True,
                        help='path to schema')
    parser.add_argument('--dem', metavar='path', required=True,
                        help='path to dem')
    args = parser.parse_args()
    model_schema(workspace=args.workspace, schema=args.schema, dem=args.dem)
1个回答

34

我认为这看起来是正确的,如果你想将其作为模块使用,那么你需要导入主要的main函数。不过,最好以更具描述性的方式命名它。

为了解释__main__和函数main()的工作原理。当你执行一个模块时,它将有一个名称,该名称存储在__name__中。如果你将模块作为脚本单独执行,它将具有名称__main__。如果你将其作为模块的一部分导入到另一个模块中,它将具有模块的名称。

main()函数可以以任何你喜欢的名称命名,并且不会影响你的程序。在小脚本中通常将其命名为main,但如果它是代码库的一部分,则不是特别好的名称。

为了让用户在作为脚本运行时输入参数,建议使用argparseclick

下面是argparse如何工作的示例:

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser(description='Create a ArcHydro schema')
    parser.add_argument('--workspace', metavar='path', required=True,
                        help='the path to workspace')
    parser.add_argument('--schema', metavar='path', required=True,
                        help='path to schema')
    parser.add_argument('--dem', metavar='path', required=True,
                        help='path to dem')
    args = parser.parse_args()
    main(workspace=args.workspace, schema=args.schema, dem=args.dem)

我已更新答案,包括如何使用argparse。 - Jonathan
将import放在函数内部而不是外部有什么好处? - Zypps987
@Zypps987 在这种情况下没有特定要求。在某些情况下,这可能很有用,因为您正在满足某些要求,除非满足这些要求,否则无法进行导入。 - Jonathan
@PeterWilson 如果Python文件有类似--config_file path_to_file的命令行参数,那么在直接调用主函数时如何传递它们? - Piyush Shandilya
@PiyushShandilya 它将被传递到你已经与命令行参数相关联的参数中。发表一个带有你代码示例的单独问题可能会有所帮助,以便进一步帮助你。 - Peter Wilson
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接