[Python] argparse 사용법

김봉석·2021년 9월 2일
0
post-thumbnail

요즘 강화학습 / 딥러닝 하퍼파라미터 튜닝등 반복적인 실험이 필요한경우
이를 효율적으로 관리하는 것은 매우 중요하다고 느낀다.
이때 유용하게 사용할 수있는 argparser 모듈에 대해서 알아 보고자 한다.

reference : Johnny Metz Youtube


cylinder_volume 예제

먼저 원통의 부피를 구하는 간단한 프로그램을 작성해보면서 살펴 보자

import math 

def cylinder_volume(radius, height):
    vol = (math.pi)*(radius**2)*(height)
    return vol

if __name__ =='__main__':
    print(cylinder_volume(2,4))

위와 같이 원의 부피를 구하는 cylinder_volume(radius,height) 함수를 간단하게 작성하였다.

argparse 객체 생성 & Positional argument

import math 
import argparse

# 1. parser 객체 생성 
parser = argparse.ArgumentParser(description='Calculate volume of a Cylinder')
# 2. 사용할 인수 등록,  이름/타입/help
parser.add_argument('radius', type=int, help='Radius of Cylinder')
parser.add_argument('height', type=int, help='Height of Cylinder')
# 3. 사용자에게 전달받은 인수를 args에 저장 
args = parser.parse_args()

def cylinder_volume(radius, height):
    vol = (math.pi)*(radius**2)*(height)
    return vol

if __name__ =='__main__':
	# 4. args에 전달된 인수를 이용해 함수 결과값 출력
    print(cylinder_volume(args.radius, args.height))
  1. argparse 모듈을 import하고 parser 객체를 생성한다 (parameter를 담는 일종의 container라 생각하면 편하다), description에는 설명 내용을 적어준다(뒤의 파트에서 보면 왜 적는지 알 수 있다.)

  2. 객체에 우리가 원하는 파라미터를 전달해준다.

    • parser.add_argument('radius', type=int, help='Radius of Cylinder')
    • radius : 인자의 이름
    • type = int : 인자의 타입 (default는 string type 이므로 int로 설정한다)
    • help : 인자를 설명하는 글을 작성한다 ( 이것도 나중에 보면 왜 적는지 알 수 있다.)

실행 방법

커맨드라인에서 실행을 하는 방법은 다음과 같다. py 파일 뒤에 인수를 전달하면 되는데 지금 상태에서는 postional argument로 들어가기 때문에 순서를 유의해서 실행해야한다.

이제 *.py -h 를 실행해보자 (help문으로 인자에 대한 설명을 확인 할 수 있다.)


실행결과를 보게 되면, 이전에 작성했던 description, help 설명문이 나오는 것을 확인할수있다.

  • argparse.ArgumentParser(description='Calculate volume of a Cylinder')
  • parser.add_argument('radius', type=int, help='Radius of Cylinder')
  • parser.add_argument('height', type=int, help='Height of Cylinder')

optional argument

만약 전달해야할 인자가 많다면, 위와 같이 positional argumnet 형식으로 전달하는 것은 무리가 있다.
이번에는 optional argument 형식으로 전달하는 방법을 알아보자.

import math 
import argparse

#  parser 객체 생성 
parser = argparse.ArgumentParser(description='Calculate volume of a Cylinder')
parser.add_argument('-r','--radius', type = int,  help = 'Radius of Cylinder' )
parser.add_argument('-H','--height', type = int,  help = 'Height of Cylinder' )

args = parser.parse_args()

def cylinder_volume(radius, height):
    vol = (math.pi)*(radius**2)*(height)
    return vol

if __name__ =='__main__':
    print(cylinder_volume(args.radius, args.height))

달라진 사항은 없다.

  • raidus \rightarrow --radius(대쉬 두개)로 변경하면 사용할 수있다. 동시에 shortcut을 지정 할수 있는데 -r (대쉬 하나)로 쉽게 설정 할 수 있다.

    다시 help문을 실행시키게 되면, optional argument를 설정하면서 이름이 길어져서 format이 이상하게 되는 현상을 목격하게 된다.

이런 경우 metavar option을 추가해서 format 형식을 바꿀 수 있다.
또한 추가적으로 required option을 추가해서 특정 argument값이 전달 되지 않으면 error가 발생하도록 설정 할 수 있다. (아무 값이 전달 되지 않으면, default는 None으로 전달한다)

import math 
import argparse

#  parser 객체 생성 
parser = argparse.ArgumentParser(description='Calculate volume of a Cylinder')
parser.add_argument('-r','--radius', type = int, metavar='', required=True, help = 'Radius of Cylinder' )
parser.add_argument('-H','--height', type = int, metavar='', required=True, help = 'Height of Cylinder' )

args = parser.parse_args()

def cylinder_volume(radius, height):
    vol = (math.pi)*(radius**2)*(height)
    return vol

if __name__ =='__main__':
    print(cylinder_volume(args.radius, args.height))

실행을 시켜보면 이제는 다음과 같이 깔끔하게 help 명령문이 실행되는 것을 확인 할 수 있다.

parser.add_mutually_exclusive_group()

이번에는 parser.add_mutually_exclusive_group()에 대해서 알아보자.
우리가 실행하는 함수에 input을 직접적으로 들어가지는 않지만, 다른 option을 부여해서 어떠한 특수한 동작을 하길 원할때 사용할 수 있다(현재 training 진행 상황을 출력하길 원한다던지..)

  • group.add_argument('-q', '--quiet', action ='store_true', help='print queit')
    : 마찬가지로 이전에 계속해서 했던 방식과 정확히 동일하지만 다른점이 있다면, True/False flag를 반환한다. 예를들어 커맨드라인에서 -q인자를 전달한다면, True가 저장되게 되고, 전달을 하지 않는다면 False가 반환된다. 이를 통해서 우리가 원하는 방식으로 동작하게 만들 수 있다.
import math 
import argparse 

# 1. parser 객체 생성 
parser = argparse.ArgumentParser(description='Calculate volume of a Cylinder')
parser.add_argument('-r','--radius', type = int, metavar='', required=True, help = 'Radius of Cylinder' )
parser.add_argument('-H','--height', type = int, metavar='', required=True, help = 'Height of Cylinder' )

group = parser.add_mutually_exclusive_group()
group.add_argument('-q', '--quiet', action ='store_true', help='print queit')
group.add_argument('-v', '--verbose', action ='store_true', help='print verbose')

args = parser.parse_args()

def cylinder_volume(radius, height):
    vol = (math.pi)*(radius**2)*(height)
    return vol

if __name__ =='__main__':
    volume = cylinder_volume(args.radius, args.height)

    if args.queit :
        print(volume) 
    elif args.verbose : 
        print(f"Volume of a Cylinder with radius {args.radius} and height {args.height} is {volume}")
    else : 
        print(f"Volume of Cylinder = {volume}")

만약 -v 인자를 전달 하게 된다면, True가 arg.verbose에 저장되게 되고, if-else문을 거쳐 원하는 동작을 하게끔 만들 수 있는 것이다.

이제까지 간단한 argparser의 사용법에 대해 알아보았다!

1개의 댓글

comment-user-thumbnail
2022년 8월 5일

좋은 글 감사합니다 ! 맨 마지막 코드 블럭 if args.queit : 에 오타가 있는 것 같습니다 :)

답글 달기