{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `argparse`\n",
    "\n",
    "{mod}`argparse`：命令行选项、参数和子命令解析器\n",
    "\n",
    "## 基础\n",
    "\n",
    "我们编写最简单的例子：\n",
    "\n",
    "```{literalinclude} examples/argparse/simple.py\n",
    ":language: python\n",
    "```\n",
    "\n",
    "在没有任何选项的情况下运行脚本不会在标准输出显示任何内容。这没有什么用处："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "!python examples/argparse/simple.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "{option}`--help` 选项，也可缩写为 {option}`-h`，是唯一一个可以直接使用的选项（即不需要指定该选项的内容）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "usage: simple.py [-h]\n",
      "\n",
      "optional arguments:\n",
      "  -h, --help  show this help message and exit\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/simple.py --help"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "指定其他任何内容都会导致错误。即便如此，我们也能直接得到一条有用的用法信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "usage: simple.py [-h]\n",
      "simple.py: error: unrecognized arguments: --verbose\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/simple.py --verbose"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "usage: simple.py [-h]\n",
      "simple.py: error: unrecognized arguments: foo\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/simple.py foo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 位置参数\n",
    "\n",
    "举个例子：\n",
    "\n",
    "```{literalinclude} examples/argparse/echos.py\n",
    ":language: python\n",
    "```\n",
    "\n",
    "运行此程序："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "usage: echos.py [-h] echo\n",
      "echos.py: error: the following arguments are required: echo\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/echos.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "增加了 {meth}`add_argument` 方法，该方法用于指定程序能够接受哪些命令行选项。在这个例子中，我将选项命名为 `echo`，与其功能一致。\n",
    "\n",
    "现在调用我们的程序必须要指定一个选项："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "foo\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/echos.py foo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "查看帮助信息："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "usage: echos.py [-h] echo\n",
      "\n",
      "positional arguments:\n",
      "  echo\n",
      "\n",
      "optional arguments:\n",
      "  -h, --help  show this help message and exit\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/echos.py -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以给位置参数一些辅助信息：\n",
    "\n",
    "```{literalinclude} examples/argparse/echos_help.py\n",
    ":language: python\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "usage: echos_help.py [-h] echo\n",
      "\n",
      "positional arguments:\n",
      "  echo        echo the string you use here\n",
      "\n",
      "optional arguments:\n",
      "  -h, --help  show this help message and exit\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/echos_help.py -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "传入的位置参数选项的值默认是作为字符串传递的，可以修改其为其他类型：\n",
    "\n",
    "```{literalinclude} examples/argparse/square.py\n",
    ":language: python\n",
    "```\n",
    "\n",
    "以下是该代码的运行结果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "16\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/square.py 4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "输错类型，会触发异常："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "usage: square.py [-h] square\n",
      "square.py: error: argument square: invalid int value: \"'4'\"\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/square.py '4'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当程序在收到错误的无效的输入时，它甚至能在执行计算之前先退出，还能显示很有帮助的错误信息。\n",
    "\n",
    "### 可选参数\n",
    "\n",
    "下面看看如何添加可选参数：\n",
    "\n",
    "```{literalinclude} examples/argparse/option.py\n",
    ":language: python\n",
    "```\n",
    "\n",
    "这一程序被设计为当指定 {command}`--verbosity` 选项时显示某些东西，否则不显示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "verbosity turned on\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/option.py --verbosity 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "!python examples/argparse/option.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```{hint}\n",
    "如果一个可选参数没有被使用时，相关变量被赋值为 `None`。\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "usage: option.py [-h] [--verbosity VERBOSITY]\n",
      "\n",
      "optional arguments:\n",
      "  -h, --help            show this help message and exit\n",
      "  --verbosity VERBOSITY\n",
      "                        increase output verbosity\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/option.py --help"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上述例子接受任何整数值作为 {command}`--verbosity` 的参数，但对于简单程序而言，只有两个值有实际意义：`True` 或者 `False`。据此修改代码：\n",
    "\n",
    "```{literalinclude} examples/argparse/option_action.py\n",
    ":language: python\n",
    "```\n",
    "\n",
    "现在，这一选项多了一个旗标，而非需要接受一个值的什么东西。我们甚至改变了选项的名字来符合这一思路。注意我们现在指定了一个新的关键词 `action`，并赋值为 `\"store_true\"`。这意味着，当这一选项存在时，为 `args.verbose` 赋值为 `True`。没有指定时则隐含地赋值为 `False`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "verbosity turned on\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/option_action.py --verbose"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "usage: option_action.py [-h] [--verbose]\n",
      "option_action.py: error: unrecognized arguments: 1\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/option_action.py --verbose 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "usage: option_action.py [-h] [--verbose]\n",
      "\n",
      "optional arguments:\n",
      "  -h, --help  show this help message and exit\n",
      "  --verbose   increase output verbosity\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/option_action.py -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 短选项\n",
    "\n",
    "例如：\n",
    "\n",
    "\n",
    "```{literalinclude} examples/argparse/short.py\n",
    ":language: python\n",
    "```\n",
    "\n",
    "\n",
    "效果就像这样："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "usage: short.py [-h] [-v]\n",
      "\n",
      "optional arguments:\n",
      "  -h, --help     show this help message and exit\n",
      "  -v, --verbose  increase output verbosity\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/short.py -h"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "verbosity turned on\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/short.py -v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结合位置参数和可选参数\n",
    "\n",
    "```{literalinclude} examples/argparse/complex1.py\n",
    ":language: python\n",
    "```\n",
    "\n",
    "接着是输出："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "usage: complex1.py [-h] [-v] square\n",
      "complex1.py: error: the following arguments are required: square\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex1.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "16\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex1.py 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the square of 4 equals 16\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex1.py 4 --verbose"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "顺序无关紧要："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the square of 4 equals 16\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex1.py --verbose 4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给程序加上接受多个 `verbosity` 的值，然后实际使用：\n",
    "\n",
    "```{literalinclude} examples/argparse/complex2.py\n",
    ":language: python\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "16\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex2.py 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "usage: complex2.py [-h] [-v VERBOSITY] square\n",
      "complex2.py: error: argument -v/--verbosity: expected one argument\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex2.py 4 -v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4^2 == 16\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex2.py 4 -v 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the square of 4 equals 16\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex2.py 4 -v 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "16\n"
     ]
    }
   ],
   "source": [
    "!python examples/argparse/complex2.py 4 -v 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 作为模块使用\n",
    "\n",
    "```python\n",
    "# train.py\n",
    "import argparse\n",
    "\n",
    "\n",
    "def parse_opt(known=False):\n",
    "    parser = argparse.ArgumentParser()\n",
    "    opt = parser.parse_known_args()[0] if known else parser.parse_args()\n",
    "    return opt\n",
    "\n",
    "\n",
    "def main(opt):\n",
    "    ...\n",
    "\n",
    "\n",
    "def run(**kwargs):\n",
    "    '''用法（来源于 yolo 代码）\n",
    "    import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt')\n",
    "    '''\n",
    "    opt = parse_opt(True)\n",
    "    for k, v in kwargs.items():\n",
    "        setattr(opt, k, v)\n",
    "    main(opt)\n",
    "\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    opt = parse_opt()\n",
    "    main(opt)\n",
    "\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "410d97fcec9c8f0bfe82a84a3d6982ea954e4374bc1aa0a0d36cc0ce0e02db7f"
  },
  "kernelspec": {
   "display_name": "Python 3.10.0 64-bit ('xin': conda)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.0"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
