ホームページ >バックエンド開発 >Python チュートリアル >クリックを使用して完璧な Python コマンド ライン プログラムを作成します

クリックを使用して完璧な Python コマンド ライン プログラムを作成します

WBOY
WBOY転載
2023-04-18 14:55:031246ブラウズ

クリックを使用して完璧な Python コマンド ライン プログラムを作成します


Python プログラマーの主な仕事は、コマンド ライン プログラム、つまりターミナルで直接実行されるスクリプトを作成することです。プロジェクトのサイズが大きくなるにつれて、毎回ソース コードを変更するのではなく、さまざまなパラメーターを提供することでさまざまな問題を解決できる効果的なコマンド ライン インターフェイスを作成したいと考えています。

この目標を達成するために、4 つの原則をまとめました。皆様のお役に立てれば幸いです。

  • コマンド ライン パラメーターはデフォルト値を提供する必要があります
  • あらゆる可能性を処理します。パラメータの欠落、間違ったデータ型、ファイルが見つからないなどのパラメータ エラーに対処します。
  • パラメータの意味とその設定方法を説明する包括的なドキュメントを作成します。
  • 長時間実行タスクを表示する進行状況バー

簡単な例

これらのルールを具体的なケース、つまりシーザー暗号を使用してメッセージの暗号化と復号化を行うスクリプトに適用してみましょう。

以下に示すように暗号化関数を作成するとします。次に、メッセージを暗号化および復号化するスクリプトを作成しましょう。

このスクリプトを使用すると、ユーザーはモード (暗号化または復号化)、キーを選択できます。前者のデフォルト値は暗号化であり、後者のデフォルト値は 1 です。これはすべてコマンド ライン パラメーターを通じて実現されます。

def encrypt(plaintext, key):
cyphertext = ''
for character in plaintext:
if character.isalpha():
number = ord(character)
number += key
if character.isupper():
if number > ord('Z'):
number -= 26
elif number < ord('A'):
number += 26
elif character.islower():
if number > ord('z'):
number -= 26
elif number < ord('a'):
number += 26
character = chr(number)
cyphertext += character
return cyphertext

初心者向けの方法: sys.argv

スクリプトは最初にコマンド ライン パラメーターの値を取得する必要があります。最初に最も単純な sys.argv を使用して実装しましょう。 。

sys.argv は、スクリプトの実行時にユーザーが入力したすべてのパラメーター (スクリプト名自体を含む) を含むリストです。

ターミナルで次のコマンドを入力します:

> python caesar_script.py --key 23 --decrypt my secret message
pb vhfuhw phvvdjh

sys.argv リストには次のものが含まれます:

['caesar_script.py', '--key', '23', '--decrypt', 'my', 'secret', 'message']

次のコマンドを取得します。パラメータ値を取得するには、引数リストをループして、キー値を取得するために '--key' (または '-k' ) を探し、モードを取得するために '--decrypt' を探す必要があります。

import sys
from caesar_encryption import encryp
def caesar():
key = 1
is_error = False
for index, arg in enumerate(sys.argv):
if arg in ['--key', '-k'] and len(sys.argv) > index + 1:
key = int(sys.argv[index + 1])
del sys.argv[index]
del sys.argv[index]
break
for index, arg in enumerate(sys.argv):
if arg in ['--encrypt', '-e']:
del sys.argv[index]
break
if arg in ['--decrypt', '-d']:
key = -key
del sys.argv[index]
break
if len(sys.argv) == 1:
is_error = True
else:
for arg in sys.argv:
if arg.startswith('-'):
is_error = True
if is_error:
print(f'Usage: python {sys.argv[0]} [ --key <key> ] [ --encrypt|decrypt ] <text>')
else:
print(encrypt(' '.join(sys.argv[1:]), key))
if __name__ == '__main__':
caesar()

コードは、最初に提案した原則に従っています:

デフォルトのキー値とデフォルトのモードを持つ

基本的なエラーを処理します(入力テキストや不明なパラメータは提供されません) )

パラメータが間違っている場合、またはスクリプトがパラメータなしで呼び出された場合に簡潔なプロンプト メッセージを出力します

#

> python caesar_script_using_sys_argv.py
Usage: python caesar.py [ --key <key> ] [ --encrypt|decrypt ] <text>

ただし、このバージョンのスクリプトは非常に長いです (39 行、暗号化関数は含まれていません)、コードは非常に醜いです。

コマンドライン引数を解析するより良い方法はありますか?

Enter argparse

argparse は、コマンド ライン引数を解析するために使用される Python 標準ライブラリ モジュールです。

argparse を使用してコマンド ライン引数を解析するようにスクリプトを変更します。

import argparse
from caesar_encryption import encrypt
def caesar():
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('-e', '--encrypt', action='store_true')
group.add_argument('-d', '--decrypt', action='store_true')
parser.add_argument('text', nargs='*')
parser.add_argument('-k', '--key', type=int, default=1)
args = parser.parse_args()
text_string = ' '.join(args.text)
key = args.key
if args.decrypt:
key = -key
cyphertext = encrypt(text_string, key)
print(cyphertext)
if __name__ == '__main__':
caesar()

コードは、私たちが提案した原則に準拠しており、より正確なドキュメントとより対話的なエラー処理を提供します。 。

> python caesar_script_using_argparse.py --encode My message
usage: caesar_script_using_argparse.py [-h] [-e | -d] [-k KEY] [text [text ...]]
caesar_script_using_argparse.py: error: unrecognized arguments: --encode
> python caesar_script_using_argparse.py --help
usage: caesar_script_using_argparse.py [-h] [-e | -d] [-k KEY] [text [text ...]]positional arguments:
text
optional arguments:
-h, --help show this help message and exit
-e, --encrypt
-d, --decrypt
-k KEY, --key KEY

スクリプトの 7 行目から 13 行目はコマンド ライン引数を定義していますが、あまり洗練されていません。冗長かつ手続き的すぎるため、よりコンパクトで宣言的な方法で完成されたものを使用できます。

click を使用してより良いコマンド ライン インターフェイスを作成する

幸いなことに、コマンド ライン インターフェイスを作成するためのサードパーティ ライブラリ click があり、argparse より多くの機能を提供するだけでなく、よりコードスタイル。 argparse を click に置き換えて、スクリプトの最適化を続行します。

import click
from caesar_encryption import encrypt
@click.command()
@click.argument('text', nargs=-1)
@click.option('--decrypt/--encrypt', '-d/-e')
@click.option('--key', '-k', default=1)
def caesar(text, decrypt, key):
text_string = ' '.join(text)
if decrypt:
key = -key
cyphertext = encrypt(text_string, key)
click.echo(cyphertext)
if __name__ == '__main__':
caesar()

コマンド ライン引数とオプションはデコレータで宣言されているため、関数の引数として直接アクセスできることに注意してください。

上記のコードを注意深く分析しましょう:

nargs は、コマンド ライン パラメーターによって受け取られる値の数を定義します。デフォルト値は 1 で、nargs=-1 は任意の値を許可します。提供される単語の数。

--encrypt/--decrypt は相互に排他的なオプションを定義し、最終的にブール値としてプログラムに渡されます。

click.echo は click ライブラリが提供する基本関数で、その機能は print に似ていますが、コンソールに出力されるテキストの色の調整など、より強力な機能を提供します。

ローカル ファイルから入力を読み取る

コマンド ライン パラメータで受け取った値は暗号化される極秘メッセージであるため、ユーザーがプレーン テキストの入力を求められるとセキュリティ上の懸念が生じる可能性があります端末に直接接続します。

より安全なアプローチは、非表示のヒントを使用するか、ローカル ファイルからテキストを読み取ることです。これは長いテキストの場合により実用的です。

同じ考え方が出力にも当てはまります。ユーザーは出力をファイルに保存したり、端末で印刷したりできます。スクリプトの最適化を続けましょう。

import click
from caesar_encryption import encrypt
@click.command()
@click.option(
'--input_file',
type=click.File('r'),
help='File in which there is the text you want to encrypt/decrypt.'
 'If not provided, a prompt will allow you to type the input text.',
)
@click.option(
'--output_file',
type=click.File('w'),
help='File in which the encrypted / decrypted text will be written.'
 'If not provided, the output text will just be printed.',
)
@click.option(
'--decrypt/--encrypt',
'-d/-e',
help='Whether you want to encrypt the input text or decrypt it.'
)
@click.option(
'--key',
'-k',
default=1,
help='The numeric key to use for the caesar encryption / decryption.'
)
def caesar(input_file, output_file, decrypt, key):
if input_file:
text = input_file.read()
else:
text = click.prompt('Enter a text', hide_input=not decrypt)
if decrypt:
key = -key
cyphertext = encrypt(text, key)
if output_file:
output_file.write(cyphertext)
else:
click.echo(cyphertext)
if __name__ == '__main__':
caesar()

スクリプトがより複雑になるため、パラメーターの機能を詳細に説明するパラメーター ドキュメント (click.option デコレーターの help パラメーターを定義することで実装) を作成します。効果は以下の通り。

> python caesar_script_v2.py --help
Usage: caesar_script_v2.py [OPTIONS]
Options:
--input_file FILENAMEFile in which there is the text you want to encrypt/decrypt. If not provided, a prompt will allow you to type the input text.
--output_file FILENAME File in which the encrypted/decrypted text will be written. If not provided, the output text will just be printed.
-d, --decrypt / -e, --encryptWhether you want to encrypt the input text or decrypt it.
-k, --key INTEGERThe numeric key to use for the caesar encryption / decryption.
--help Show this message and exit.

2 つの新しいパラメータ input_file と Output_file があり、タイプは click.File です。クリックするとファイルが正しいモードで開き、発生する可能性のあるエラーが処理されます。たとえば、ファイルが見つかりません:

> python caesar_script_v2.py --decrypt --input_file wrong_file.txt
Usage: caesar_script_v2.py [OPTIONS]
Error: Invalid value for "--input_file": Could not open file: wrong_file.txt: No such file or directory

input_file が指定されていない場合は、click.prompt を使用してコマンド ラインにプロンプ​​ト ウィンドウを作成し、ユーザーがテキストを直接入力できるようにします。 . このプロンプトは暗号化モードで使用されます。は非表示になります。効果は次のとおりです:

> python caesar_script_v2.py --encrypt --key 2
Enter a text: **************
yyy.ukectc.eqo

假设你是一名黑客:想要解密一个用凯撒加密过的密文,但你不知道秘钥是什么。最简单的策略就是用所有可能的秘钥调用解密函数 25 次,阅读解密结果,看看哪个是合理的。但你很聪明,而且也很懒,所以你想让整个过程自动化。确定解密后的 25 个文本哪个最可能是原始文本的方法之一,就是统计所有这些文本中的英文单词的个数。这可以使用 PyEnchant 模块实现:

import click
import enchant
from caesar_encryption import encrypt
@click.command()
@click.option(
'--input_file',
type=click.File('r'),
required=True,
)
@click.option(
'--output_file',
type=click.File('w'),
required=True,
)
def caesar_breaker(input_file, output_file):
cyphertext = input_file.read()
english_dictionnary = enchant.Dict("en_US")
max_number_of_english_words = 0
for key in range(26):
plaintext = encrypt(cyphertext, -key)
number_of_english_words = 0
for word in plaintext.split(' '):
if word and english_dictionnary.check(word):
number_of_english_words += 1
if number_of_english_words > max_number_of_english_words:
max_number_of_english_words = number_of_english_words
best_plaintext = plaintext
best_key = key
click.echo(f'The most likely encryption key is {best_key}. It gives the following plaintext:nn{best_plaintext[:1000]}...')
output_file.write(best_plaintext)
if __name__ == '__main__':
caesar_breaker()

クリックを使用して完璧な Python コマンド ライン プログラムを作成します

使用进度条

示例中的文本包含10^4个单词,因此该脚本需要大约5秒才能解密。这很正常,因为它需要检查所有25个秘钥,每个秘钥都要检查10^4个单词是否出现在英文字典中。

假设你要解密的文本包括10^5个单词,那么就要花费50秒才能输出结果,用户可能会非常着急。因此我建议这种任务一定要显示进度条。特别是,显示进度条还非常容易实现。下面是个显示进度条的例子:

import click
import enchant
from tqdm import tqdm
from caesar_encryption import encrypt
@click.command()
@click.option(
'--input_file',
type=click.File('r'),
required=True,
)
@click.option(
'--output_file',
type=click.File('w'),
required=True,
)
def caesar_breaker(input_file, output_file):
cyphertext = input_file.read()
english_dictionnary = enchant.Dict("en_US")
best_number_of_english_words = 0
for key in tqdm(range(26)):
plaintext = encrypt(cyphertext, -key)
number_of_english_words = 0
for word in plaintext.split(' '):
if word and english_dictionnary.check(word):
number_of_english_words += 1
if number_of_english_words > best_number_of_english_words:
best_number_of_english_words = number_of_english_words
best_plaintext = plaintext
best_key = key
click.echo(f'The most likely encryption key is {best_key}. It gives the following plaintext:nn{best_plaintext[:1000]}...')
output_file.write(best_plaintext)
if __name__ == '__main__':
caesar_breaker()

这里使用了tqdm库,tqdm.tqdm类可以将任何可迭代对象转化为一个进度条。click也提供了类似的接口来创建进度条(click.progress_bar),但我觉得它不如tqdm好用。

クリックを使用して完璧な Python コマンド ライン プログラムを作成します

以上がクリックを使用して完璧な Python コマンド ライン プログラムを作成しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。