利用Python内置库实现创建命令行应用程序

目录
  • 介绍
  • 解析参数
  • 创建帮助信息
  • 添加别名
  • 使用相互排斥的参数
  • 创建一个简单的搜索工具
  • 总结

介绍

当创建一个应用程序时,通常希望能够告诉你的应用程序如何做某事。有两种流行的方法来完成这项任务,你可以让应用程序接受命令行参数,或者创建一个图形化的用户接口。有些应用程序两者都支持。

当你需要在服务器上运行你的代码时,命令行接口很有帮助。大多数服务器没有图形化界面,特别当它们是Linux服务器时。在这种情况下,即使你想运行图形用户界面,你也可能无法运行。

Python 有一个叫做 argparse 的内置库,可以用它来创建一个命令行界面。在这篇文章中,你将了解到以下内容。

  • 解析实参
  • 创建有用的信息
  • 添加别名
  • 使用相互排斥的参数
  • 创建一个简单的搜索工具

argparse模块的内容比本文要介绍的多得多。如果你想知道更多关于它的信息,你可以查看文档。

现在是时候开始从命令行中解析参数了。

解析参数

在学习如何使用 argparse 之前,最好知道还有一种方法可以向 Python 脚本传递参数。你可以向 Python 脚本传递任何参数,并通过使用 sys 模块访问这些参数。

为了了解它是如何工作的,创建一个名为 sys_args.py 的文件,并在其中输入以下代码:

# sys_args.py
   import sys
   def main():
       print('You passed the following arguments:')
       print(sys.argv)
   if __name__ == '__main__':
       main()

这段代码导入sys并打印出sys.argv中的任何内容。argv属性包含了所有传递给脚本的东西的列表,其中第一项是脚本本身。

下面是一个例子,说明当你运行这段代码和几个参数的时候会发生什么。

$ python3 sys_args.py --s 45
   You passed the following arguments:
   ['sys_args.py', '--s', '45']

使用sys.argv的问题是,你无法控制可以传递给你的应用程序的参数。

  • 不能忽略参数
  • 不能创建默认参数
  • 无法判断什么是有效参数

这就是为什么使用 argparse 是使用 Python 标准库的方法。argparse 模块是非常强大和有用的。让我们想一想,一个命令行应用程序所遵循的常见过程。

  • pass:传入一个文件
  • do:在你的程序中对该文件做一些处理
  • output :输出结果

下面是一个关于如何工作的通用例子。继续创建file_parser.py并添加以下代码。

# file_parser.py
   import argparse
   def file_parser(input_file, output_file=''):
       print(f'Processing {input_file}')
       print('Finished processing')
       if output_file:
           print(f'Creating {output_file}')
   def main():
       parser = argparse.ArgumentParser('File parser')
       parser.add_argument('--infile', help='Input file')
       parser.add_argument('--out', help='Output file')
       args = parser.parse_args()
       if args.infile:
           file_parser(args.infile, args.out)
   if __name__ == '__main__':
       main()

file_parser()函数是进行解析的逻辑所在。在这个例子中,它只接收一个文件名,并将其打印出来。output_file参数的默认值是一个空字符串。

程序的重点在 main()中。在这里你创建了一个 argparse.ArgumentParser()的实例,并给你的解析器起了一个名字。然后你添加两个参数, --infile和 --out。为了使用这个解析器,你需要调用 parse_args(),它将返回传递给你的程序的任何有效参数。最后,你要检查用户是否使用了 --infile 标志。如果他们使用了,那么你就运行 file_parser()。

下面是你如何在你的终端中运行代码。

$ python file_parser.py --infile something.txt
   Processing something.txt
   Finished processing

在这里,你用 --infile标志和一个文件名来运行你的脚本。这将运行 main(),然后调用 file_parser()。

下一步是使用你在代码中声明的两个命令行参数尝试运行你的应用程序。

$ python file_parser.py --infile something.txt --out output.txt
   Processing something.txt
   Finished processing
   Creating output.txt

这一次,你得到了一个额外的输出行,提到了输出文件名。这代表你的代码逻辑中的一个分支。当你指定一个输出文件时,你可以让你的代码通过使用一个新的代码块或一个函数来生成该文件。如果你不指定一个输出文件,那么那个代码块就不会运行。

当你使用argparse创建你的命令行工具时,你可以很容易地添加信息,当你的用户不确定如何正确地与你的程序互动时,可以帮助他们。

现在是时候找出如何从你的应用程序中获得帮助了

创建帮助信息

argparse库将使用你在创建每个参数时提供的信息,自动为你的应用程序创建一个有用的信息。这里是代码:

# file_parser.py
   import argparse
   def file_parser(input_file, output_file=''):
       print(f'Processing {input_file}')
       print('Finished processing')
       if output_file:
           print(f'Creating {output_file}')
   def main():
       parser = argparse.ArgumentParser('File parser')
       parser.add_argument('--infile', help='Input file')
       parser.add_argument('--out', help='Output file')
       args = parser.parse_args()
       if args.infile:
           file_parser(args.infile, args.out)
   if __name__ == '__main__':
       main()

现在试着用 -h标志运行这段代码,你应该看到以下内容。

$ file_parser.py -h
   usage: File parser [-h] [--infile INFILE] [--out OUT]
   optional arguments:
     -h, --help       show this help message and exit
     --infile INFILE  Input file
     --out OUT        Output file

add_argument()的帮助参数被用来创建上面的帮助信息。argparse会自动添加 -h和 -help选项。你可以通过给它一个描述和后记来使你的帮助信息更丰富。

让我们用它们来改进你的帮助信息。首先,把上面的代码复制到一个新的文件中,命名为 file_parser_with_description.py,然后把它修改成下面的样子。

# file_parser_with_description.py
   import argparse
   def file_parser(input_file, output_file=''):
       print(f'Processing {input_file}')
       print('Finished processing')
       if output_file:
           print(f'Creating {output_file}')
   def main():
       parser = argparse.ArgumentParser(
               'File parser',
               description='PyParse - The File Processor',
               epilog='Thank you for choosing PyParse!',
               )
       parser.add_argument('--infile', help='Input file for conversion')
       parser.add_argument('--out', help='Converted output file')
       args = parser.parse_args()
       if args.infile:
           file_parser(args.infile, args.out)
   if __name__ == '__main__':
       main()

在这里,把description和epilog参数传递给ArgumentParser。还更新了 add_argument()的帮助参数,使其更具描述性。

在做了这些修改之后,当你用 -h或 --help运行这个脚本时,你会看到以下输出。

$ python file_parser_with_description.py -h
   usage: File parser [-h] [--infile INFILE] [--out OUT]
   PyParse - The File Processor
   optional arguments:
     -h, --help       show this help message and exit
     --infile INFILE  Input file for conversion
     --out OUT        Converted output file
   Thank you for choosing PyParse!

现在可以在你的帮助输出中看到新的description 和epilog。这给了你的命令行程序一些额外的修饰。

你也可以通过ArgumentParser的 add_help参数在你的应用程序中完全禁用帮助。如果你认为你的帮助文本过于冗长,你可以像这样禁用它。

# file_parser_no_help.py
   import argparse
   def file_parser(input_file, output_file=''):
       print(f'Processing {input_file}')
       print('Finished processing')
       if output_file:
           print(f'Creating {output_file}')
   def main():
       parser = argparse.ArgumentParser(
               'File parser',
               description='PyParse - The File Processor',
               epilog='Thank you for choosing PyParse!',
               add_help=False,
               )
       parser.add_argument('--infile', help='Input file for conversion')
       parser.add_argument('--out', help='Converted output file')
       args = parser.parse_args()
       if args.infile:
           file_parser(args.infile, args.out)
   if __name__ == '__main__':
       main()

通过将 add_help设置为 False,你将禁用 -h和 --help标志。

你可以看到下面的演示。

$ python file_parser_no_help.py --help
   usage: File parser [--infile INFILE] [--out OUT]
   File parser: error: unrecognized arguments: --help

在下一节中,你将学习如何为你的参数添加别名!

添加别名

别名是一个花哨的词,指的是使用一个替代的标志来做同样的事情。例如,你知道你可以使用 -h和 --help来访问程序的帮助信息。-h是 --help的别名,反之亦然。

看看 main()里面的 parser.add_argument()方法有什么变化。

# file_parser_aliases.py
   import argparse
   def file_parser(input_file, output_file=''):
       print(f'Processing {input_file}')
       print('Finished processing')
       if output_file:
           print(f'Creating {output_file}')
   def main():
       parser = argparse.ArgumentParser(
               'File parser',
               description='PyParse - The File Processor',
               epilog='Thank you for choosing PyParse!',
               add_help=False,
               )
       parser.add_argument('-i', '--infile', help='Input file for conversion')
       parser.add_argument('-o', '--out', help='Converted output file')
       args = parser.parse_args()
       if args.infile:
           file_parser(args.infile, args.out)
   if __name__ == '__main__':
       main()

这里你改变了第一个 add_argument(),除了接受 -infile之外,还接受了 -i,你还在第二个 add_argument()中加入了 -o。这样就可以使用两个新的快捷标志来运行你的代码。

下面是一个例子。

$ python3 file_parser_aliases.py -i something.txt -o output.txt
   Processing something.txt
   Finished processing
   Creating output.txt

如果你去看argparse文档,你会发现也可以给子解析器添加别名。子解析器是一种在你的应用程序中创建子命令的方法,这样它就可以做其他事情。一个很好的例子是Docker,一个虚拟化或容器应用程序。它有一系列的命令,你可以在docker下运行,以及docker compose等等。这些命令中的每一个都有独立的子命令,你都可以使用。

下面是一个典型的docker命令,用于运行一个容器。

docker exec -it container_name bash

这将用docker启动一个容器。而如果你要使用docker compose,你将使用一组不同的命令。exec和compose是subparsers的例子。

使用相互排斥的参数

有时你需要让你的应用程序接受一些参数,但不接受其他参数。例如,你可能想限制你的应用程序,使它只能创建或删除文件,而不是同时创建和删除。

argparse模块提供了 add_mutually_exclusive_group()方法,它就是这样做的。

将你的两个参数添加到一个组对象中,使其相互排斥,如下面的例子。

# file_parser_exclusive.py
   import argparse
   def file_parser(input_file, output_file=''):
       print(f'Processing {input_file}')
       print('Finished processing')
       if output_file:
           print(f'Creating {output_file}')
   def main():
       parser = argparse.ArgumentParser(
               'File parser',
               description='PyParse - The File Processor',
               epilog='Thank you for choosing PyParse!',
               add_help=False,
               )
       group = parser.add_mutually_exclusive_group()
       group.add_argument('-i', '--infile', help='Input file for conversion')
       group.add_argument('-o', '--out', help='Converted output file')
       args = parser.parse_args()
       if args.infile:
           file_parser(args.infile, args.out)
   if __name__ == '__main__':
       main()

首先,你创建了一个相互排斥的组。然后,你把 -i和 -o参数添加到组中,而不是添加到解析器对象中。现在这两个参数是互斥的。

下面是当你试图用这两个参数运行你的代码时发生的情况。

$ python3 file_parser_exclusive.py -i something.txt -o output.txt
   usage: File parser [-i INFILE | -o OUT]
   File parser: error: argument -o/--out: not allowed with argument -i/--infile

用这两个参数运行你的代码,会使你的解析器向用户显示一条错误信息,解释他们做错了什么。

在涵盖了所有这些与使用argparse有关的信息之后,你已经准备好应用你的新技能来创建一个简单的搜索工具了

创建一个简单的搜索工具

在开始创建一个应用程序之前,弄清楚你要完成的任务总是好的。你在本节中想要建立的应用程序应该能够搜索特定文件类型的文件。为了使它更有趣,你可以添加一个额外的参数,让你也能选择性地搜索特定的文件大小。

你可以使用 Python 的 glob 模块来搜索文件类型。你可以在这里阅读关于这个模块的所有信息。

还有一个 fnmatch 模块,glob 自己也使用它。你现在应该使用 glob,因为它更容易使用,但是如果你有兴趣写一些更专业的东西,那么 fnmatch 可能是你正在寻找的。

然而,由于你希望能够通过文件大小来选择性地过滤返回的文件,你可以使用 pathlib,它包括一个类似 glob 的接口。glob 模块本身并不提供文件大小的信息。

你可以先创建一个名为 pysearch.py 的文件并输入以下代码。

# pysearch.py
   import argparse
   import pathlib
   def search_folder(path, extension, file_size=None):
       """
       Search folder for files
       """
       folder = pathlib.Path(path)
       files = list(folder.rglob(f'*.{extension}'))
       if not files:
           print(f'No files found with {extension=}')
           return
       if file_size is not None:
           files = [
                   f
                   for f in files
                   if f.stat().st_size >= file_size
                   ]
       print(f'{len(files)} *.{extension} files found:')
       for file_path in files:
           print(file_path)

在上面的代码片段中,首先导入了argparse和pathlib。接下来,创建了search_folder()函数,它接收了三个参数。

  • path - 要搜索的文件夹
  • extension - 要寻找的文件扩展名
  • file_size - 要过滤的文件大小,以字节为单位。

把路径变成pathlib.Path对象,然后使用其rglob()方法在文件夹中搜索用户传入的扩展名。如果没有找到文件,就向用户打印一个有意义的信息,然后退出。

如果找到了任何文件,就检查是否已经设置了filesize。如果它被设置了,就用一个list comprehension来过滤出小于指定的filesize的文件。

接下来,打印出找到的文件的数量,最后在这些文件上循环,打印出它们的名字。

为了使这一切正常工作,需要创建一个命令行界面。你可以通过添加一个包含argparse代码的main()函数来做到这一点,像这样。

def main():
       parser = argparse.ArgumentParser(
               'PySearch',
               description='PySearch - The Python Powered File Searcher',
               )
       parser.add_argument('-p', '--path',
                           help='The path to search for files',
                           required=True,
                           dest='path')
       parser.add_argument('-e', '--ext',
                           help='The extension to search for',
                           required=True,
                           dest='extension')
       parser.add_argument('-s', '--size',
                           help='The file size to filter on in bytes',
                           type=int,
                           dest='size',
                           default=None)
       args = parser.parse_args()
       search_folder(args.path, args.extension, args.size)
   if __name__ == '__main__':
       main()

这个ArgumentParser()有三个参数,与你传递给search_folder()的参数相对应。让--path和--ext参数成为必需的,而让--size参数成为可选的。注意,--size参数被设置为type=int,这意味着你不能把它传成字符串。

add_argument()函数有一个新的参数。它是dest参数,可以用它来告诉你的参数分析器在哪里保存传递给它们的参数。

下面是一个脚本运行的例子。

$ python3 pysearch.py -p /Users/michael/Dropbox/python101code/chapter32_argparse -e py -s 650
   6 *.py files found:
   /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_aliases2.py
   /Users/michael/Dropbox/python101code/chapter32_argparse/pysearch.py
   /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_aliases.py
   /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_with_description.py
   /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_exclusive.py
   /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_no_help.py

现在试试用-s和一个字符串来运行它。

$ python3 pysearch.py -p /Users/michael/Dropbox/python101code/chapter32_argparse -e py -s python
   usage: PySearch [-h] -p PATH -e EXTENSION [-s SIZE]
   PySearch: error: argument -s/--size: invalid int value: 'python'

这次我们收到了一个错误,因为-s和-size只接受整数。在你自己的机器上运行一下这段代码,看看当你使用-s和整数时,它是否按你想要的方式工作。

这里有一些想法,你可以用来改进你的代码版本。

更好地处理扩展文件。现在,它将接受 *.py,这不会像你期望的那样工作。

更新代码,以便你可以一次搜索多个扩展名

更新代码,以便对文件大小的范围进行过滤(例如,1MB-5MB)。

还有很多其他的功能和改进,你可以添加到这个代码中,比如添加错误处理或单元测试。

总结

argparse模块功能齐全,可以用来创建庞大、灵活的命令行应用程序。在本章中,你了解了以下内容。

  • 解析参数
  • 创建有用的信息
  • 添加别名
  • 使用相互排斥的参数
  • 创建一个简单的搜索工具

你可以用argparse模块做更多的事情,不完全包括本章所讲的。请务必查看文档以了解全部细节。

到此这篇关于利用Python内置库实现创建命令行应用程序的文章就介绍到这了,更多相关Python命令行应用程序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python 中使用 argparse 解析命令行参数

    目录 1.Python 中的参数解析 2.类型 3.子命令 4.程序架构 使用 argparse 模块为应用程序设置命令行选项. 有一些第三方库用于命令行解析,但标准库 argparse 与之相比也毫不逊色. 无需添加很多依赖,你就可以编写带有实用参数解析功能的漂亮命令行工具. 1.Python 中的参数解析 使用 argparse 解析命令行参数时,第一步是配置一个 ArgumentParser 对象.这通常在全局模块内完成,因为单单_配置_一个解析器没有副作用. import argpars

  • Python命令行解析器argparse详解

    目录 第1章 argparse简介 1.1 解析 1.2 argparse定义三步骤 1.3  代码示例 第2章 参数详解 2.1 创建一个命令行解析器对象:ArgumentParser() 2.2 为命令行添加参数: add_argument() 方法 2.3 解析命令行的参数:parse_args() 2.4 命令行参数的输入 2.5 命令行参数的使用 总结 第1章 argparse简介 1.1 解析 argparse 模块是 Python 内置的一个用于命令项选项与参数解析的模块,argp

  • python命令行模式的用法及流程

    1.使用cmd打开命令行窗口. 2.在输入python时,进入python交互模式. 3.输入exit(),退出交互模式,在命令行模式下运行.py程序. 实例 C:\Users\86178>python Python 3.8.3 (default, Jul 2 2020, 17:30:36) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32 Type "help", "copyright", &quo

  • IPython 8.0 Python 命令行交互工具

    目录 1.追溯改进 2.自动建议 3.使用“?”和"??"查看对象信息 4.历史范围全局功能 前言: IPython 是 Python 的原生交互式 shell 的增强版,可以完成许多不同寻常的任务,比如帮助实现并行化计算:主要使用它提供的交互性帮助,比如代码着色.改进了的命令行回调.制表符完成.宏功能以及改进了的交互式帮助. IPython 8.0 酝酿了许久,主要对现有代码库和几个新功能进行了改进.新功能包括在 CLI 中使用 Black 重新格式化代码.ghost 建议以及突出错

  • 实现 Python 脚本生成命令行

    目录 Fire 使用方法 方法支持 类支持 重新改写 有时候我们会有这样的一个需求: 我们定义了一个 Python 的方法,方法接收一些参数,但是调用的时候想将这些参数用命令行暴露出来. 比如说这里有个爬取方法: import requests def scrape(url, timeout=10): response = requests.get(url, timeout=timeout) print(response.text) 这里定义了一个 scrape 方法,第一个参数接收 url,即

  • 利用Python内置库实现创建命令行应用程序

    目录 介绍 解析参数 创建帮助信息 添加别名 使用相互排斥的参数 创建一个简单的搜索工具 总结 介绍 当创建一个应用程序时,通常希望能够告诉你的应用程序如何做某事.有两种流行的方法来完成这项任务,你可以让应用程序接受命令行参数,或者创建一个图形化的用户接口.有些应用程序两者都支持. 当你需要在服务器上运行你的代码时,命令行接口很有帮助.大多数服务器没有图形化界面,特别当它们是Linux服务器时.在这种情况下,即使你想运行图形用户界面,你也可能无法运行. Python 有一个叫做 argparse

  • python 内置库wsgiref的使用(WSGI基础入门)

    WSGI基本原理 1. WSGI处理过程 浏览器到WSGI Server:浏览器发送的请求会先到WSGI Server. environ:WSGI Server会将HTTP请求中的参数等信息封装到environ(一个字典)中. WSGI Server到WSGI App:App就是我们自己编写的后台程序,每个URL会映射到对应的入口处理函数(或其他可调用对象),WSGI Server调用后台App时,会将environ和WSGI Server中自己的一个start_response函数注入到后台A

  • 关于Python 内置库 itertools

    目录 1.itertools库 2.使用itertools 3.itertools.accumulate 4.itertools.chain 5.itertools.combinations_with_replacement 6.itertools.compress 7.itertools.count 8.itertools.cycle 9.itertools.dropwhile 10.itertools.filterfalse 11.itertools.groupby 12.itertools

  • 详解python算法常用技巧与内置库

    近些年随着python的越来越火,python也渐渐成为了很多程序员的喜爱.许多程序员已经开始使用python作为第一语言来刷题. 最近我在用python刷题的时候想去找点python的刷题常用库api和刷题技巧来看看.类似于C++的STL库文档一样,但是很可惜并没有找到,于是决定结合自己的刷题经验和上网搜索做一份文档出来,供自己和大家观看查阅. 1.输入输出: 1.1 第一行给定两个值n,m,用空格分割,第一个n决定接下来有n行的输入,m决定每一行有多少个数字,m个数字均用空格分隔. 解决办法

  • python使用prettytable内置库美化输出表格

    目录 前言: 安装 案例 从csv文件添加数据,并打印出表格 从HTML导入数据 前言: 大多数时候,需要输出的信息能够比较整齐的输出来,在使用mysql的时候,我们使用命令符之后,会输出特别好看的表格,python的prettytable库就是这么一个工具,可以帮助我们打印出好看的表格,并且对中文支持特别友好 安装 prettytable是pyhton内置库,通过命令直接可以安装 pip install prettytable 案例 from prettytable import Pretty

  • Python基于内置库pytesseract实现图片验证码识别功能

    这篇文章主要介绍了Python基于内置库pytesseract实现图片验证码识别功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 环境准备: 1.安装Tesseract模块 git文档地址:https://digi.bib.uni-mannheim.de/tesseract/ 下载后就是一个exe安装包,直接右击安装即可,安装完成之后,配置一下环境变量,编辑 系统变量里面 path,添加下面的安装路径: 2.如果您想使用其他语言,请下载相应的

  • Python如何使用内置库matplotlib绘制折线图

    这篇文章主要介绍了Python如何使用内置库matplotlib绘制折线图,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 环境准备: 需要安装matplotlib,安装方式: pip install matplotlib 直接贴代码喽: #引入模块 from matplotlib import pyplot,font_manager #设置支持中文字体的显示 font=font_manager.FontProperties(fname="C:\

  • Python enumerate内置库用法解析

    这篇文章主要介绍了Python enumerate内置库用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 使用enumerate,可以自动进行索引下标的赋值,本例代码中使用enumerate,进行excel单元格的赋值操作. 代码如果重复被调用,可将该代码封装成类进行使用 import openpyxl #加载excel文件 wb = openpyxl.load_workbook('test_datas/test_cases.xlsx')

  • python中内置库os与sys模块的详细介绍

    目录 os包 sys模块 os包 想要使用os包一样要先导入:import os os包下可以直接调用的函数 下面介绍一下os包中可以直接调用的函数: 例子: 例子: 例子: 注意:os.path.exists()参数可以传绝对路径,也可以传相对路径: 已知一个文件的路径,可以用spilt切割出这个文件名: sys模块 sys模块常用于操作当前的操作系统/环境 sys中常用的函数: 例子: 关于argv我们知道,他可以从程序外部获取参数,我们让他从终端传入参数给程序. 举一个详细的例子介绍: 可

  • Python内置方法实现字符串的秘钥加解密(推荐)

    在实际编程开发中,我们会使用到各类的加密算法来对数据和信息进行加密.比如密码中比较常见的MD5加密,以及AES加密等等. 对于密码认证来说,MD5加密是比较适合的,因为其不需要接触到明文的数据,只需要比对MD5加密后的哈希值就能判断数据是否一致:而对于一些在加密后进行解密的数据而言,AES则更加的常用. 在Python中实现AES算法需要借助的第三方库Crypto,其在各个操作系统上的安装方法有些许复杂,所以对于简单的使用有点杀鸡用牛刀的意思.在Mrdoc的开发过程中,我们就遇到了这样的问题.一

随机推荐