2017-10-12 7 views
3

Pythonの​​モジュールを使用するためのベストプラクティスまたはスタイルガイドラインはありますか?argparseパーサーを書くためのベストプラクティス

私は​​を定期的に使用していますが、すばやくすべての設定を処理するためにかなりの数の行が必要です。ほぼすべて私はPEP 8に近づくと、きれいで読みやすいコードになりますが、ここではわかりません。最終的な結果は、常に読みにくいコードの醜いブロックです。

読み痛みはPython的ではありません。

Beautiful is better than ugly ... Readibilty counts

だから、PEPまたはより良い、このコードをフォーマットする方法のためのガイドラインを提供し、いくつかの他のリソースがありますか?

(主にPEP 8次)醜さのサンプル:

parser = argparse.ArgumentParser(description='A nontrivial modular command') 
subparsers = parser.add_subparsers(help='sub-command help') 

parser_load = subparsers.add_parser('load', help='Load something somewhere') 
parser_load.add_argument('--config', 
         help='Path to configuration file for special settings') 
parser_load.add_argument('--dir', default=os.getcwd(), 
         help='The directory to load') 
parser_load.add_argument('book', help='The book to load into this big thing') 
parser_load.add_argument('chapter', nargs='?', default='', 
         help='Optionally specify a chapter') 
parser_load.add_argument('verse', nargs='*', 
         help='Optionally pick as many verses as you want to' 
         ' load') 
parser_load.set_defaults(command='load') 

parser_write = subparsers.add_parser(
       'write', help='Execute commands defined in a config file') 
parser_write.add_argument('config', help='The path to the config file') 
parser_write.set_defaults(command='write') 

parser_save = subparsers.add_parser(
       'save', 
       help='Save this big thing for use somewhere later') 
parser_save.add_argument('-n', '--name', default=None, 
         help='The name of the component to save') 
parser_save.add_argument('path', help="The way out of Plato's cave") 
parser_save.set_defaults(command='save') 

... 

args = parser.parse_args() 
+2

「クリック」をチェックアウト:http://click.pocoo.org/5/デコレータを使ってもっと素敵な議論 – economy

+0

あなたが行を壊している場所について一貫性を持たないこととは別に、私は何の問題も見ません。読みやすさを助ける場所ではなく、80文字に準拠する必要がある行だけを破るようにしてください。私はこれがオフトピックではないと確信していません。あなたのコーディング基準に応じて変化するので、意見に基づいています。 – TemporalWolf

+1

@TemporalWolf私は、このコードのフォーマット方法の提案ではなく、標準が存在するかどうか尋ねたのです。 – jpyams

答えて

2

TemporalWolfでコメントしたように、私はラインがより一貫壊し、そしてそれらの多く使用します。コードは今より長く表示された場合でも、私はそれが簡単に読むことを見つける:個々の関数呼び出しの間

  • より垂直方向のスペース、そのため簡単には、行ごとに視覚的に
  • つの引数を区別するため、容易に使用されているものを見るために左マージンに近い
  • 引数、(あなたがhelp文字列を分割1のように)

を必要なため、少ない水平眼球運動と少ない不要改行さらに、名前を変更してparser_X/parser_YX_parser/Y_parserを指定すると、X/Yを区別しやすくなります。あなたのコードは何も問題はありません

parser = argparse.ArgumentParser(
    description='A nontrivial modular command' 
) 
subparsers = parser.add_subparsers(
    help='sub-command help' 
) 

load_parser = subparsers.add_parser(
    'load', 
    help='Load something somewhere' 
) 
load_parser.add_argument(
    '--config', 
    help='Path to configuration file for special settings' 
) 
load_parser.add_argument(
    '--dir', 
    default=os.getcwd(), 
    help='The directory to load' 
) 
load_parser.add_argument(
    'book', 
    help='The book to load into this big thing' 
) 
load_parser.add_argument(
    'chapter', 
    nargs='?', 
    default='', 
    help='Optionally specify a chapter' 
) 
load_parser.add_argument(
    'verse', 
    nargs='*', 
    help='Optionally pick as many verses as you want to load' 
) 
load_parser.set_defaults(
    command='load' 
) 

write_parser = subparsers.add_parser(
    'write', 
    help='Execute commands defined in a config file' 
) 
write_parser.add_argument(
    'config', 
    help='The path to the config file' 
) 
write_parser.set_defaults(
    command='write' 
) 

save_parser = subparsers.add_parser(
    'save', 
    help='Save this big thing for use somewhere later' 
) 
save_parser.add_argument(
    '-n', '--name', 
    default=None, 
    help='The name of the component to save' 
) 
save_parser.add_argument(
    'path', 
    help="The way out of Plato's cave" 
) 
save_parser.set_defaults(
    command='save' 
) 

... 

args = parser.parse_args() 
+0

コメントに記載されている名前の変更を実装しなかった理由がわかりません。私は100%それに同意する。私の好みの書式設定は[それほど異質ではありません](https://repl.it/M8gm/0)ですが、私の提案では[これはさらに良い](https://repl.it/M8gm/1)と思われますコメントを削除する。 – TemporalWolf

+1

@TemporalWolf私は答えを掲示した後でしか考えていなかったので、それを実装しませんでした。 – mkrieger1

2

は、それが​​モジュールを使用しただけの結果です。私の個人的な好みは、パーサの作成を機能に分解することです。この場合、作成した各サブパーパに対して関数を作成できます。

def parse_args(args=sys.argv[1:]): 
    parser = argparse.ArgumentParser(description='A nontrivial modular command') 
    subparsers = parser.add_subparsers(help='sub-command help') 

    add_load_subparser(subparsers) 
    add_write_subparser(subparsers) 
    add_save_subparser(subparsers) 

    return parser.parse_args(args) 


def add_load_subparser(subparsers): 
    parser = subparsers.add_parser('load', help='Load something somewhere') 
    parser.add_argument('--config', 
         help='Path to configuration file for special settings') 
    parser.add_argument('--dir', default=os.getcwd(), 
         help='The directory to load') 
    parser.add_argument('book', help='The book to load into this big thing') 
    parser.add_argument('chapter', nargs='?', default='', 
         help='Optionally specify a chapter') 
    parser.add_argument('verse', nargs='*', 
         help='Optionally pick as many verses as you want to' 
         ' load') 
    parser.set_defaults(command='load') 


def add_write_subparser(subparsers): 
    parser = subparsers.add_parser(
      'write', help='Execute commands defined in a config file') 
    parser.add_argument('config', help='The path to the config file') 
    parser.set_defaults(command='write') 


def add_save_subparser(subparsers): 
    parser = subparsers.add_parser(
       'save', 
       help='Save this big thing for use somewhere later') 
    parser.add_argument('-n', '--name', default=None, 
         help='The name of the component to save') 
    parser.add_argument('path', help="The way out of Plato's cave") 
    parser.set_defaults(command='save') 


args = parse_args() 
1

この特定のモジュールのスタイルについては、開発者の間で議論されていません(私は関連するバグや問題を詳しく追ってきました)。

私は、スタイルやレイアウトよりも問題を解決することにもっと関心がありますが、読みやすく理解しやすいコードが好きです。繰り返されるパターンの大きなブロックがある場合、私はユーティリティ関数、辞書、リストを使用するのが好きです。

最近のSOの質問How to design object oriented subparsers for argparse?は、OOPサブパーサー定義について尋ねました。私は彼の最初のクラスを取って、メソッドを追加しました:

def make_sup(self,sp): 
     self.parser = sp.add_parser(self.name) 
     self.parser.add_argument('--foo') 
     self.parser.set_defaults(action=self) 

だから、オブジェクトのセットが

cmds = [] 
cmds.append(Cmd('list')) 
cmds.append(Cmd('foo')) 
cmds.append(Cmd('bar')) 

あるいは

cmds = [Cmd('list'), Cmd('foo'),...] 

で定義され、その後でパーサを移入するために使用することができ:

parser = argparse.ArgumentParser() 
sp = parser.add_subparsers(dest='cmd') 
for cmd in cmds: 
    cmd.make_sup(sp) 

引数を伴わない単純な例です。

unittestファイルtest_argparse.pyには、パーサー定義を合理化するために、かなり精巧なシステムがあります。 (バックまたは少なくともいくつかのバージョンを持っていた)い

def no_groups(parser, argument_signatures): 
     """Add all arguments directly to the parser""" 
     for sig in argument_signatures: 
      parser.add_argument(*sig.args, **sig.kwargs) 

Ipython

argument_signatures = [Sig('--foo-bar'), Sig('--baz', dest='zabbaz')] 
argument_signatures = [ 
    Sig('-x', type=float), 
    Sig('-3', type=float, dest='y'), 
    Sig('z', nargs='*'), 
] 

そして、パーサーテストクラスのようなメソッドがあります。

class Sig(object): 

    def __init__(self, *args, **kwargs): 
     self.args = args 
     self.kwargs = kwargs 

テストケースは、これらのSigオブジェクトのリストを作成します引数を定義するためにconfigファイルエントリを使用して大きな​​パーサを作成するコード。

関連する問題