2017-10-12 2 views
3

파이썬의 argparse 모듈을 사용하기위한 베스트 프랙티스 또는 스타일 가이드 라인이 있습니까?argparse 파서 작성을위한 모범 사례

나는 정기적으로 argparse으로 작업하며, 모든 구성을 처리하는 데 상당한 수의 라인을 신속하게 사용합니다. 거의 모든 부분에서 나는 PEP 8에 가깝게 깔끔하게 읽을 수있는 코드를 만들어 냈지만 여기서는 그렇지 않습니다. 최종 결과는 항상 읽기 힘든 코드 블록입니다.

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

체크 아웃 : clickclick : http://click.pocoo.org/5/ 데코레이터를 통한 더 멋진 인수 – economy

+0

줄을 끊는 위치에 대해 일관성이 없으면서도 아무런 문제가 보이지 않습니다. 가독성을 높이기보다는 80자를 준수해야하는 부분을 깰 수 있습니다. 나는 이것이 오프 토픽이 아니라고 확신하지 않는다 : 당신의 코딩 표준에 따라 다양해질 것이므로 의견을 기반으로한다. – TemporalWolf

+1

@TemporalWolf 나는이 코드를 어떻게 포맷해야하는지에 대한 제안이 아니라 표준이 존재 하는지를 묻는 이유를 알 수있다. – jpyams

답변

2

TemporalWolf 댓글을 달았습니다, 나는이 선을 사용하는 것이 더 지속적으로 나누기, 그 중 더. 코드가 지금 이상 나타나지 않더라도, 나는 그것이 읽기 쉽게 찾을 수 있습니다 : 개별 함수 호출 사이

  • 더 수직 공간 때문에 쉽게이 한 줄에 시각적으로
  • 하나의 인수를 구분하기 때문에 쉽게 사용되는 것을 볼을 왼쪽 여백에 가까운
  • 인수, (당신이 help 문자열을 분할 한이 같은)

이 필요하므로 적은 수평 안구 운동 적은 원치 않는 줄 바꿈 또한 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

은, 그것은 argparse 모듈을 사용하여 단지 결과입니다. 필자가 개인적으로 선호하는 것은 파서의 생성을 함수로 분해하는 것이다. 이 경우 생성 한 각 하위 파서마다 함수를 만들 수 있습니다.

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

개발자 중이 특정 모듈의 스타일에 대한 논의는 없었습니다. 관련 버그/문제를 면밀히 지켜 보았습니다.

저는 스타일과 레이아웃보다 문제를 해결하는 것이 더 중요하지만 읽기 쉽고 이해하기 쉬운 코드를 좋아합니다. 반복 패턴의 큰 블록이있는 경우 유틸리티 함수, 사전 및 목록을 사용하는 것을 좋아합니다.

최근 질문이므로 How to design object oriented subparsers for argparse?은 OOP 하위 구문 정의에 대해 질문했습니다.나는 그의 초기 클래스를 가져다 방법 추가 : 그래서 객체의 집합으로 파서를 채우는 데 사용 후

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

또는

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

과 함께 정의 할 수 있습니다

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

을 :

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 파일 항목을 사용하여 큰 argparse 파서를 생성하는 코드.