Summary

  • argparse๋Š” Python ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ํ„ฐ๋ฏธ๋„ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์Šคํฌ๋ฆฝํŠธ ๋‚ด๋ถ€์˜ ๋ณ€์ˆ˜ ๊ฐ’์„ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ์œ ์—ฐํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” CLI ๋„๊ตฌ์ด๋‹ค.
  • ํŒŒ์„œ ์ƒ์„ฑ โ†’ ์ธ์ž ์ถ”๊ฐ€ โ†’ ๋ถ„์„ ์ด๋ผ๋Š” 3๋‹จ๊ณ„์˜ ๋ช…ํ™•ํ•œ ํ๋ฆ„์„ ํ†ตํ•ด ์ง๊ด€์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ๊ตฌ์„ฑํ•œ๋‹ค.
  • ํ•„์ˆ˜ ์ž…๋ ฅ๊ฐ’์ธ โ€˜์œ„์น˜ ์ธ์žโ€™์™€ ๋ถ€๊ฐ€์ ์ธ ์„ค์ •์šฉ์ธ โ€˜์„ ํƒ ์ธ์žโ€™๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • add_argument ๋ฉ”์„œ๋“œ ๋‚ด ๋‹ค์–‘ํ•œ ์˜ต์…˜๋“ค(type, default, choices, action ๋“ฑ)์„ ํ™œ์šฉํ•ด ๋ฐ์ดํ„ฐ ํ˜•๋ณ€ํ™˜, ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ž๋™ํ™”, ํ”Œ๋ž˜๊ทธ ์„ค์ • ๋“ฑ์„ ์†์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

0. ๋“ค์–ด๊ฐ€๋ฉฐ

๋งค๋ฒˆ Python ์Šคํฌ๋ฆฝํŠธ ๋‚ด์—์„œ ๋ณ€์ˆ˜๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์€ ๊ท€์ฐฎ์€ ์ž‘์—…์ด๋‹ค.

Python ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ argparse ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ํ„ฐ๋ฏธ๋„์„ ํ†ตํ•ด Python ํŒŒ์ผ ์‹คํ–‰ํ•  ๋•Œ ํ„ฐ๋ฏธ๋„์—์„œ ์˜ต์…˜์„ ์ž…๋ ฅํ•ด์„œ Python ์ฝ”๋“œ ๋‚ด ๋ณ€์ˆ˜ ๊ฐ’๋“ค์„ ์ œ์–ดํ•ด๋ณด์ž.

์—ฌ๊ธฐ์„œ๋Š” argparse๋ฅผ ์ด์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” CLI(Command Line Interface) ๋„๊ตฌ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•˜์˜€๋‹ค.


1. ๊ฐœ์š”

argparse ๋ž€?

argparse๋Š” ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ ์ปค๋งจ๋“œ ๋ผ์ธ์—์„œ ์ธ์ž(Argument)๋ฅผ ๋ฐ›์•„, ์ด๋ฅผ ํŒŒ์ด์ฌ ๋‚ด๋ถ€ ๋ณ€์ˆ˜๋กœ ์‰ฝ๊ฒŒ ๋ณ€ํ™˜ํ•ด ์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹จ์ˆœํžˆ python main.py๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์•„๋ž˜์ฒ˜๋Ÿผ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

์•„๋ž˜ ๋ช…๋ น์–ด์—์„œ extract, 10, verbose ๊ฐ™์€ ๊ฐ’๋“ค์„ ํŒŒ์ด์ฌ์ด ์•Œ์•„๋จน๋„๋ก ๋„์™€์ฃผ๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ argparse์ด๋‹ค.

python main.py extract --sample 10 --verbose

2. ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

2.1 ํ๋ฆ„

argparse์˜ ์‚ฌ์šฉ ํ๋ฆ„์€ ์ •ํ˜•ํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ, 3๋‹จ๊ณ„๋งŒ ๊ธฐ์–ตํ•˜๋ฉด ๋œ๋‹ค.

  1. Parser ์ƒ์„ฑ(ArgumentParser): ๋‹ด์„ ๊ทธ๋ฆ‡(๊ฐ์ฒด)์„ ์ƒ์„ฑ
  2. ์ธ์ž ์ถ”๊ฐ€ (add_argument): ์–ด๋–ค ์ž…๋ ฅ์„ ๋ฐ›์„์ง€ ๊ทœ์น™์„ ์ •ํ•˜๊ธฐ
  3. ๋ถ„์„ (parse_args): ๋“ค์–ด์˜จ ์ž…๋ ฅ์„ ์‹ค์ œ๋กœ ํ•ด์„ํ•˜์—ฌ ๋ณ€์ˆ˜์— ๋‹ด์Šต๋‹ˆ๋‹ค.
import argparse 
 
# 1. Parser ์ƒ์„ฑ
parser = argparse.ArgumentParser(description="์ด ํ”„๋กœ๊ทธ๋žจ์€ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.")
 
# 2. ์ธ์ž ์ถ”๊ฐ€
parser.add_argument("name", help="์‚ฌ์šฉ์ž ์ด๋ฆ„") 
parser.add_argument("--age", help="๋‚˜์ด")
 
# 3. ๋ถ„์„
args = parser.parse_args()
 
print(f"์ด๋ฆ„: {args.name}, ๋‚˜์ด: {args.age}")

2.2 ์œ„์น˜ ์ธ์ž vs ์„ ํƒ ์ธ์ž

add_argument๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ€์žฅ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋ถ€๋ถ„์œผ๋กœ ์ธ์ž ์ด๋ฆ„ ์•ž์— ๋ถ™๋Š” ํ•˜์ดํ”ˆ(-)์˜ ์œ ๋ฌด๊ฐ€ ๊ฒฐ์ •์ ์ธ ์ฐจ์ด

๊ตฌ๋ถ„์œ„์น˜ ์ธ์ž(Positional Arguments)์„ ํƒ ์ธ์ž(Optional Arguments)
ํŠน์ง•์ด๋ฆ„ ์•ž์— ํ•˜์ดํ”ˆ (-) ์—†๋‹ค (์˜ˆ: filename, mode)์ด๋ฆ„ ์•ž์— ํ•˜์ดํ”ˆ(-, --) ์ด ๋ถ™๋Š”๋‹ค (์˜ˆ: -f, --file)
๊ทœ์น™ํ•„์ˆ˜ ์ž…๋ ฅ์ด๋ฉฐ, ์ž‘์„ฑ ์ˆœ์„œ๊ฐ€ ์ค‘์š”์ž…๋ ฅํ•˜์ง€ ์•Š์•„๋„ ์—๋Ÿฌ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ , ์ˆœ์„œ๋„ ์ƒ๊ด€์—†๋‹ค
์šฉ๋„ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ, ์—†์–ด์„œ๋Š” ์•ˆ ๋  ํ•ต์‹ฌ ๋ฐ์ดํ„ฐ์˜ต์…˜ ์„ค์ •, ๋ชจ๋“œ ๋ณ€๊ฒฝ ๋“ฑ ๋ถ€๊ฐ€์ ์ธ ๊ธฐ๋Šฅ

2.3 ํ•ต์‹ฌ ์˜ต์…˜๋“ค

add_argument() ๋ฉ”์„œ๋“œ ๋‚ด ๊ธฐ๋Šฅ ์„ค๋ช…

์˜ต์…˜๊ธฐ๋Šฅ์„ค๋ช…
typeํƒ€์ž… ์ง€์ •์ž…๋ ฅ๊ฐ’์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฌธ์ž์—ด(str) ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ
defalut๊ธฐ๋ณธ๊ฐ’ ์„ค์ •์˜ต์…˜ ๋ฏธ์ž…๋ ฅ์‹œ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฐ’ ์ง€์ •
choices์„ ํƒ์ง€ ์ œํ•œ์ •ํ•ด์ง„ ๊ฐ’ ์™ธ ์ž…๋ ฅ์ด ๋“ค์–ด์˜ค๋ฉด ์—๋Ÿฌ ์ผ์œผํ‚ด (์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ž๋™ํ™”)
actionํ”Œ๋ž˜๊ทธ ์„ค์ •๊ฐ’์ด ์•„๋‹Œ ์˜ต์…˜ ์กด์žฌ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ
requiredํ•„์ˆ˜ ์˜ต์…˜ ์„ค์ •์„ ํƒ ์ธ์ž์ง€๋งŒ, ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ์„ ๊ฐ•์ œ
nargs๋ฆฌ์ŠคํŠธ๋กœ ๋ฐ›๊ธฐ์ž…๋ ฅ๊ฐ’์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฐ›๊ธฐ
# 1. ํƒ€์ž… ์ง€์ •: count ๋ณ€์ˆ˜๋ฅผ intํ˜•์œผ๋กœ ์ง€์ •
parser.add_argument("--count", type = int)
 
# 2. ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •: mode ๋ณ€์ˆ˜ ๊ธฐ๋ณธ๊ฐ’์„ 'normal'๋กœ ์„ค์ •
parser.add_argument("--mode", defalut = "normal")
 
# 3. ์„ ํƒ์ง€ ์ œํ•œ: color ๋ณ€์ˆ˜๋Š” red, blue, green ๊ฐ’๋งŒ ๋ฐ›์Œ
parser.add_argument("color", choices = ['red', 'blue','green'])
 
# 4. ํ”Œ๋ž˜๊ทธ ์„ค์ •: --verbose๋ฅผ ์ž…๋ ฅํ•˜๋ฉด True, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด False
parser.add_argument('--verbose', action = 'store_true')
 
# 5. ํ•„์ˆ˜ ์˜ต์…˜: api-key ๋ณ€์ˆ˜๋Š” ํ•„์ˆ˜ ์ž…๋ ฅ๊ฐ’์œผ๋กœ ์„ค์ •
parser.add_argument('--api-key', required = True)
 
# 6. ๋ฆฌ์ŠคํŠธ ๋ฐ›๊ธฐ: files ๋ณ€์ˆ˜๋Š” list ๊ฐ’์„ ๋ฐ›๊ธฐ (์˜ˆ์‹œ, ['a.txt', 'b.txt', 'c.txt'])
parser.add_argument('--files', nargs = '*')

3. ํ™œ์šฉ

์ฝ”๋“œ

์•„๋ž˜ ์ฝ”๋“œ๋Š” mode๋ผ๋Š” ์œ„์น˜ ์ธ์ž(ํ•„์ˆ˜ ์ž…๋ ฅ)์™€ --sample์ด๋ผ๋Š” ์„ ํƒ ์ธ์ž(์„ ํƒ ์ž…๋ ฅ) ์˜ต์…˜์„ ์กฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.

import argparse
import sys
 
def main():
    # 1. ํŒŒ์„œ ์ƒ์„ฑ (description์œผ๋กœ ๋„์›€๋ง ์ œ๊ณต)
    parser = argparse.ArgumentParser(description="์•„ํŒŒํŠธ ๋„๋ฉด ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ")
 
    # [์œ„์น˜ ์ธ์ž] ์‹คํ–‰ ๋ชจ๋“œ (choices๋กœ ์˜คํƒ€ ๋ฐฉ์ง€)
    parser.add_argument(
        "mode", 
        choices=["extract", "convert", "validate", "all"], 
        help="์‹คํ–‰ ๋ชจ๋“œ (extract: ์ถ”์ถœ, convert: ๋ณ€ํ™˜, validate: ๊ฒ€์ฆ, all: ์ „์ฒด)"
    )
 
    # [์„ ํƒ ์ธ์ž] ํ…Œ์ŠคํŠธ์šฉ ์ƒ˜ํ”Œ ๊ฐœ์ˆ˜ (int ํ˜•๋ณ€ํ™˜)
    # ํŒ: ๋‹จ์ถ• ์˜ต์…˜ '-s'์™€ ์ „์ฒด ์˜ต์…˜ '--sample'์„ ๊ฐ™์ด ์ง€์ •ํ•˜๋ฉด ํŽธ๋ฆฌํ•จ
    parser.add_argument(
        "-s", "--sample", 
        type=int, 
        default=None,
        help="ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์ฒ˜๋ฆฌํ•  ์ƒ˜ํ”Œ ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜ (๊ธฐ๋ณธ๊ฐ’: ์ „์ฒด)"
    )
    
    # [์„ ํƒ ์ธ์ž] ์ƒ์„ธ ๋กœ๊ทธ ์ถœ๋ ฅ (ํ”Œ๋ž˜๊ทธ)
    parser.add_argument(
        "-v", "--verbose",
        action="store_true",
        help="์ƒ์„ธ ๋กœ๊ทธ ์ถœ๋ ฅ ํ™œ์„ฑํ™”"
    )
 
    # ์ธ์ž ๋ถ„์„
    args = parser.parse_args()
 
    # --- ์‹ค์ œ ๋กœ์ง ---
    print(f"๐Ÿš€ ์‹คํ–‰ ๋ชจ๋“œ: {args.mode}")
    
    if args.verbose:
        print("๐Ÿ“ข ์ƒ์„ธ ๋กœ๊ทธ ๋ชจ๋“œ๊ฐ€ ์ผœ์กŒ์Šต๋‹ˆ๋‹ค.")
 
    if args.sample:
        print(f"๐Ÿงช [TEST] ์ƒ˜ํ”Œ {args.sample}๊ฐœ๋งŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.")
    else:
        print("โœ… ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.")
 
    # ๋ชจ๋“œ๋ณ„ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ
    if args.mode in ["extract", "all"]:
        print("... ๋ฐ์ดํ„ฐ ์ถ”์ถœ ์ค‘ ...")
        # run_extraction(limit=args.sample) ํ˜ธ์ถœ
    
    if args.mode in ["convert", "all"]:
        print("... ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ์ค‘ ...")
 
if __name__ == "__main__":
    main()

์‹คํ–‰ ๊ฒฐ๊ณผ ์˜ˆ์‹œ

๊ฐ ์ƒํ™ฉ๋ณ„ ๊ฒฐ๊ณผ ์˜ˆ์‹œ

# 1. ๋„์›€๋ง ํ™•์ธ
>>> python main.py -h
### help ๋ฉ”์‹œ์ง€์™€ usage๊ฐ€ ์ถœ๋ ฅ
 
# 2. ์ •์ƒ ์‹คํ–‰: ๋ชจ๋“œ(extract), ์ƒ˜ํ”Œ ๊ฐœ์ˆ˜(5), ์ƒ์„ธ ๋กœ๊ทธ ์ถœ๋ ฅ
>>> python main.py extract -s 5 --verbose
# [output]
๐Ÿš€ ์‹คํ–‰ ๋ชจ๋“œ: extract
๐Ÿ“ข ์ƒ์„ธ ๋กœ๊ทธ ๋ชจ๋“œ๊ฐ€ ์ผœ์กŒ์Šต๋‹ˆ๋‹ค.
๐Ÿงช [TEST] ์ƒ˜ํ”Œ 5๊ฐœ๋งŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
... ๋ฐ์ดํ„ฐ ์ถ”์ถœ ์ค‘ ...
 
# 3. ์—๋Ÿฌ: ์œ„์น˜ ์ธ์ž๊ฐ’ ์ค‘ ์œ ํšจํ•œ ๊ฐ’์ด ์•„๋‹Œ ๊ฒฝ์šฐ
>>> python main.py delete 
# [output]
usage: main.py [-h] [-s SAMPLE] [-v] {extract,convert,validate,all}
main.py: error: argument mode: invalid choice: 'delete' ...

๋งˆ์น˜๋ฉฐ

argparse๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ ์ˆ˜์ • ์—†์ด ํ„ฐ๋ฏธ๋„ ๋ช…๋ น์–ด๋งŒ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์˜ ๋™์ž‘์„ ์œ ์—ฐํ•˜๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค. choices๋ฅผ ํ™œ์šฉํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ --help ์ž๋™ ์ƒ์„ฑ ๊ธฐ๋Šฅ์€ ๊ฐœ๋ฐœ์ž์˜ ์ˆ˜๊ณ ๋ฅผ ๋œ์–ด์ค€๋‹ค.


Reference