入门
最简单的示例¶
最简单的Typer文件可能如下所示
import typer
def main():
print("Hello World")
if __name__ == "__main__":
typer.run(main)
将其复制到文件main.py
中。
测试它
$ python main.py
Hello World
// It just prints "Hello World".
// Now check the --help
$ python main.py --help
<b> </b><font color="#F4BF75"><b>Usage: </b></font><b>main.py [OPTIONS] </b>
<b> </b>
<font color="#A5A5A1">╭─ Options ─────────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--help</b></font> Show this message │
<font color="#A5A5A1">│ and exit. │</font>
<font color="#A5A5A1">╰───────────────────────────────────────────────────╯</font>
...但此程序仍然不太有用。让我们扩展它。
什么是CLI 参数¶
此处我们将使用术语CLI 参数来指按特定顺序传递给 CLI 应用程序的CLI 参数。默认情况下,它们是必需的。
如果你转到你的终端并键入
$ ls ./myproject
first-steps.md intro.md
ls
将显示目录 ./myproject
的内容。
ls
是程序(或“命令”、“CLI 应用程序”)。./myproject
是一个CLI 参数,在此处它指一个目录的路径。
它们与你稍后在下面看到的CLI 选项略有不同。
添加一个 CLI 参数¶
使用参数 name
更新上一个示例
import typer
def main(name: str):
print(f"Hello {name}")
if __name__ == "__main__":
typer.run(main)
$ python main.py
// If you run it without the argument, it shows a nice error
<font color="#F4BF75">Usage: </font>main.py [OPTIONS] NAME
<font color="#A5A5A1">Try </font><font color="#44919F">'main.py </font><font color="#44919F"><b>--help</b></font><font color="#44919F">'</font><font color="#A5A5A1"> for help.</font>
<font color="#F92672">╭─ Error ───────────────────────────────────────────╮</font>
<font color="#F92672">│</font> Missing argument 'NAME'. <font color="#F92672">│</font>
<font color="#F92672">╰───────────────────────────────────────────────────╯</font>
// Now pass that NAME CLI argument
$ python main.py Camila
Hello Camila
// Here "Camila" is the CLI argument
// To pass a name with spaces for the same CLI argument, use quotes
$ python main.py "Camila Gutiérrez"
Hello Camila Gutiérrez
提示
如果你需要将包含空格的单个值传递给CLI 参数,请在其周围使用引号 ("
)。
两个 CLI 参数¶
现在假设我们想要将名字和姓氏分开。
因此,将其扩展为具有 2 个参数,name
和 lastname
import typer
def main(name: str, lastname: str):
print(f"Hello {name} {lastname}")
if __name__ == "__main__":
typer.run(main)
// Check the main --help
$ python main.py --help
<font color="#F4BF75">Usage: </font>main.py [OPTIONS] NAME
<font color="#A5A5A1">Try </font><font color="#44919F">'main.py </font><font color="#44919F"><b>--help</b></font><font color="#44919F">'</font><font color="#A5A5A1"> for help.</font>
<font color="#F92672">╭─ Error ───────────────────────────────────────────╮</font>
<font color="#F92672">│</font> Missing argument 'NAME'. <font color="#F92672">│</font>
<font color="#F92672">╰───────────────────────────────────────────────────╯</font>
<font color="#A1EFE4"><b>typer</b></font> on <font color="#AE81FF"><b> richify</b></font> <font color="#F92672"><b>[»!?] </b></font>via <font color="#F4BF75"><b>🐍 v3.7.5 (env3.7)</b></font>
<font color="#F92672"><b>❯</b></font> <font color="#A6E22E">python</font> <u style="text-decoration-style:single">main.py</u>
<font color="#F4BF75">Usage: </font>main.py [OPTIONS] NAME LASTNAME
<font color="#A5A5A1">Try </font><font color="#44919F">'main.py </font><font color="#44919F"><b>--help</b></font><font color="#44919F">'</font><font color="#A5A5A1"> for help.</font>
<font color="#F92672">╭─ Error ───────────────────────────────────────────╮</font>
<font color="#F92672">│</font> Missing argument 'NAME'. <font color="#F92672">│</font>
<font color="#F92672">╰───────────────────────────────────────────────────╯</font>
// There are now 2 CLI arguments, name and lastname
// Now pass a single name argument
$ python main.py Camila
<font color="#F4BF75">Usage: </font>main.py [OPTIONS] NAME LASTNAME
<font color="#A5A5A1">Try </font><font color="#44919F">'main.py </font><font color="#44919F"><b>--help</b></font><font color="#44919F">'</font><font color="#A5A5A1"> for help.</font>
<font color="#F92672">╭─ Error ───────────────────────────────────────────╮</font>
<font color="#F92672">│</font> Missing argument 'LASTNAME'. <font color="#F92672">│</font>
<font color="#F92672">╰───────────────────────────────────────────────────╯</font>
// These 2 arguments are required, so, pass both:
$ python main.py Camila Gutiérrez
Hello Camila Gutiérrez
提示
请注意,顺序很重要。姓氏必须放在名字之后。
如果你使用以下命令调用它
$ python main.py Gutiérrez Camila
你的应用程序将无法知道哪个是 name
,哪个是 lastname
。它期望第一个CLI 参数是 name
,第二个CLI 参数是 lastname
。
什么是CLI 选项¶
此处我们将使用术语CLI 选项来指使用特定名称传递给 CLI 应用程序的CLI 参数。例如,如果你转到你的终端并键入
$ ls ./myproject --size
12 first-steps.md 4 intro.md
ls
将显示目录 ./myproject
的内容及其大小
。
ls
是程序(或“命令”、“CLI 应用程序”)。./myproject
是一个CLI 参数。--size
是一个可选的CLI 选项。
该程序知道它必须显示大小,因为它看到了 --size
,而不是因为顺序。
像 --size
这样的CLI 选项不依赖于像CLI 参数那样的顺序。
因此,如果你将 --size
放在CLI 参数之前,它仍然有效(事实上,这是最常见的方法)
$ ls --size ./myproject
12 first-steps.md 4 intro.md
CLI 选项和CLI 参数之间的主要视觉差异在于CLI 选项在名称前加有--
,如“--size
”。
CLI 选项不依赖于顺序,因为它有一个预定义的名称(此处为--size
)。这是因为 CLI 应用程序专门查找带有该特定“名称”(此处特定名称为“--size
”)的文字--size
参数(也称为“标志”或“开关”)。CLI 应用程序将检查您是否键入了它,即使您没有键入它,它也会主动查找--size
(以检查它是否存在)。
相比之下,CLI 应用程序不会主动查找带有“./myproject
”文本的CLI 参数,它无法知道您会键入./myproject
还是./my-super-awesome-project
或其他任何内容。它只是等待获取您给它的任何东西。知道您指的是特定CLI 参数的唯一方法是通过顺序。它知道第一个CLI 参数是name
,第二个是lastname
,但如果您混淆了顺序,它将无法处理它。
相反,使用CLI 选项,顺序无关紧要。
此外,默认情况下,CLI 选项是可选的(不是必需的)。
所以,默认情况下
- CLI 参数是必需的
- CLI 选项是可选的
但必需的和可选的默认值可以更改。
所以,主要且最重要的区别是
- CLI 选项以
--
开头且不依赖于顺序 - CLI 参数依赖于顺序顺序
提示
在上面的示例中,CLI 选项--size
只是一个“标志”或“开关”,它将包含布尔值True
或False
,具体取决于它是否已添加到命令中。
这个不接收任何值。但CLI 选项也可以接收值,如CLI 参数。稍后您将看到。
添加一个CLI 选项¶
现在添加一个--formal
CLI 选项
import typer
def main(name: str, lastname: str, formal: bool = False):
if formal:
print(f"Good day Ms. {name} {lastname}.")
else:
print(f"Hello {name} {lastname}")
if __name__ == "__main__":
typer.run(main)
此处formal
是一个默认值为False
的bool
。
// Get the help
$ python main.py --help
<b> </b><font color="#F4BF75"><b>Usage: </b></font><b>main.py [OPTIONS] NAME LASTNAME </b>
<b> </b>
<font color="#A5A5A1">╭─ Arguments ─────────────────────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#F92672">*</font> name <font color="#F4BF75"><b>TEXT</b></font> [default: None] <font color="#A6194C">[required]</font> │
<font color="#A5A5A1">│ </font><font color="#F92672">*</font> lastname <font color="#F4BF75"><b>TEXT</b></font> [default: None] <font color="#A6194C">[required]</font> │
<font color="#A5A5A1">╰─────────────────────────────────────────────────────────────────╯</font>
<font color="#A5A5A1">╭─ Options ───────────────────────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--formal</b></font> <font color="#AE81FF"><b>--no-formal</b></font> [default: no-formal] │
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--help</b></font> Show this message and │
<font color="#A5A5A1">│ exit. │</font>
<font color="#A5A5A1">╰─────────────────────────────────────────────────────────────────╯</font>
提示
请注意,它会自动创建一个--formal
和一个--no-formal
,因为它检测到formal
是一个bool
。
现在正常调用它
$ python main.py Camila Gutiérrez
Hello Camila Gutiérrez
// But if you pass --formal
$ python main.py Camila Gutiérrez --formal
Good day Ms. Camila Gutiérrez.
// And as --formal is a CLI option you can put it anywhere in this command
$ python main.py Camila --formal Gutiérrez
Good day Ms. Camila Gutiérrez.
$ python main.py --formal Camila Gutiérrez
Good day Ms. Camila Gutiérrez.
带值的CLI 选项¶
要将lastname
从CLI 参数转换为CLI 选项,请为其指定默认值""
import typer
def main(name: str, lastname: str = "", formal: bool = False):
if formal:
print(f"Good day Ms. {name} {lastname}.")
else:
print(f"Hello {name} {lastname}")
if __name__ == "__main__":
typer.run(main)
由于lastname
现在具有默认值""
(空字符串),因此函数中不再需要它,并且Typer现在默认将其设为可选CLI 选项。
$ python main.py --help
<b> </b><font color="#F4BF75"><b>Usage: </b></font><b>main.py [OPTIONS] NAME </b>
<b> </b>
<font color="#A5A5A1">╭─ Arguments ───────────────────────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#F92672">*</font> name <font color="#F4BF75"><b>TEXT</b></font> [default: None] <font color="#A6194C">[required]</font> │
<font color="#A5A5A1">╰───────────────────────────────────────────────────────────────────╯</font>
<font color="#A5A5A1">╭─ Options ─────────────────────────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--lastname</b></font> <font color="#F4BF75"><b>TEXT</b></font> │
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--formal</b></font> <font color="#AE81FF"><b>--no-formal</b></font> <font color="#F4BF75"><b> </b></font> [default: no-formal] │
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--help</b></font> <font color="#F4BF75"><b> </b></font> Show this message │
<font color="#A5A5A1">│ and exit. │</font>
<font color="#A5A5A1">╰───────────────────────────────────────────────────────────────────╯</font>
提示
注意--lastname
,并注意它采用文本值。
一个值类似于 --lastname
的CLI 选项(与没有值的CLI 选项相反,一个 bool
标志,如 --formal
或 --size
)将其值作为CLI 选项右侧的任何内容。
// Call it without a --lastname
$ python main.py Camila
Hello Camila
// Pass the --lastname
$ python main.py Camila --lastname Gutiérrez
Hello Camila Gutiérrez
提示
请注意,“Gutiérrez
”位于 --lastname
的右侧。一个有值的CLI 选项将其值作为右侧的任何内容。
并且由于 --lastname
现在是一个不依赖于顺序的CLI 选项,因此可以在名称之前传递它
$ python main.py --lastname Gutiérrez Camila
// and it will still work normally
Hello Camila Gutiérrez
记录你的 CLI 应用程序¶
如果你向你的函数添加一个文档字符串,它将用于帮助文本中
import typer
def main(name: str, lastname: str = "", formal: bool = False):
"""
Say hi to NAME, optionally with a --lastname.
If --formal is used, say hi very formally.
"""
if formal:
print(f"Good day Ms. {name} {lastname}.")
else:
print(f"Hello {name} {lastname}")
if __name__ == "__main__":
typer.run(main)
现在使用 --help
选项查看它
$ python main.py --help
<b> </b><font color="#F4BF75"><b>Usage: </b></font><b>main.py [OPTIONS] NAME </b>
<b> </b>
Say hi to NAME, optionally with a <font color="#A1EFE4"><b>--lastname</b></font>.
If <font color="#6B9F98"><b>--formal</b></font><font color="#A5A5A1"> is used, say hi very formally. </font>
<font color="#A5A5A1">╭─ Arguments ───────────────────────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#F92672">*</font> name <font color="#F4BF75"><b>TEXT</b></font> [default: None] <font color="#A6194C">[required]</font> │
<font color="#A5A5A1">╰───────────────────────────────────────────────────────────────────╯</font>
<font color="#A5A5A1">╭─ Options ─────────────────────────────────────────────────────────╮</font>
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--lastname</b></font> <font color="#F4BF75"><b>TEXT</b></font> │
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--formal</b></font> <font color="#AE81FF"><b>--no-formal</b></font> <font color="#F4BF75"><b> </b></font> [default: no-formal] │
<font color="#A5A5A1">│ </font><font color="#A1EFE4"><b>--help</b></font> <font color="#F4BF75"><b> </b></font> Show this message │
<font color="#A5A5A1">│ and exit. │</font>
<font color="#A5A5A1">╰───────────────────────────────────────────────────────────────────╯</font>
提示
还有另一个地方可以记录特定的CLI 选项和CLI 参数,这些选项和参数将在帮助文本中显示在它们旁边,如 --install-completion
或 --help
,你将在本教程的后面部分了解到这一点。
参数、选项、参数、可选、必需¶
请注意,这些术语根据上下文指代多个事物,遗憾的是,这些“上下文”经常混合,因此很容易混淆。
在 Python 中¶
在 Python 中,函数中变量的名称,如 name
和 lastname
def main(name: str, lastname: str = ""):
pass
被称为“Python 函数参数”或“Python 函数参数”。
技术细节
实际上,Python 中的“参数”和“参数”之间有一个非常小的区别。
这非常技术化……而且有点迂腐。
参数指函数声明中的变量名称。如
def bring_person(name: str, lastname: str = ""):
pass
参数指调用函数时传递的值。如
person = bring_person("Camila", lastname="Gutiérrez")
... 但你可能会看到它们在大多数地方(包括这里)互换使用。
Python 默认值¶
在 Python 中,在函数中,一个具有默认值的参数(如 lastname
)
def main(name: str, lastname: str = ""):
pass
被视为“可选参数”(或“可选参数”)。
默认值可以是任何值,如 ""
或 None
。
而一个没有默认值的参数(如 name
)则被视为必需的。
在 CLI 中¶
在讨论命令行界面应用程序时,单词“参数”和“参数”通常用于指传递给 CLI 应用程序的数据,这些参数。
但这些单词并不暗示有关数据是必需的、需要按特定顺序传递或具有 --lastname
之类的标志的任何信息。
带有 --lastname
(以及可选值)名称的参数通常是可选的,不是必需的。因此,在讨论 CLI 时,通常将它们称为可选参数或可选参数。有时,这些以 --
开头的可选参数也称为标志或开关。
实际上,需要按顺序的参数也可以设为可选。而带有标志(如 --lastname
)的参数也可以设为必需。
在Typer 中¶
为了让它更容易一点,我们通常会使用单词“参数”或“参数”来指 Python 函数。
我们将使用CLI 参数来指那些取决于特定顺序的CLI 参数。默认情况下必需。
我们将使用CLI 选项来指那些取决于以 --
开头的名称的CLI 参数(如 --lastname
)。默认情况下可选。
我们将使用CLI 参数来指两者,CLI 参数和CLI 选项。
typer
命令¶
当你安装 typer
时,默认情况下它会向你的 shell 添加一个 typer
命令。
此 typer
命令允许你在终端中使用 ✨ 自动完成 ✨ 运行脚本。
作为使用 Python 运行的替代方案
$ python main.py
Hello World
你可以使用 typer
命令运行
$ typer main.py run
Hello World
...当您按 TAB 键时,它将在您的终端中为您提供自动完成,适用于您的所有代码。
因此,当您继续学习本教程时,您可以使用它为自己的脚本提供自动完成。
提示
一旦您创建了一个 Python 包,使用 Typer 构建的 CLI 应用程序将不再需要 typer
命令来进行自动完成。
但在创建 Python 包之前,对于短脚本和学习来说,它可能很有用。