argparse를 사용하여 부울 값 구문 분석


614

"--foo True"또는 "--foo False"로 작성된 부울 명령 행 인수를 구문 분석하기 위해 argparse를 사용하고 싶습니다. 예를 들면 다음과 같습니다.

my_program --my_boolean_flag False

그러나 다음 테스트 코드는 내가 원하는 것을 수행하지 않습니다.

import argparse
parser = argparse.ArgumentParser(description="My parser")
parser.add_argument("--my_bool", type=bool)
cmd_line = ["--my_bool", "False"]
parsed_args = parser.parse(cmd_line)

슬프게도로 parsed_args.my_bool평가됩니다 True. 이것은 내가 변경할 경우에도 경우입니다 cmd_line["--my_bool", ""]있기 때문에, 의외 인 bool("")에 evalutatesFalse .

어떻게 구문 분석 argparse 얻을 수 있습니다 "False", "F"그리고 그들의 낮은 경우로 변형 False?


40
다음은 @ mgilson 's answer의 한 줄짜리 해석입니다 parser.add_argument('--feature', dest='feature', default=False, action='store_true'). 이 솔루션은 항상 또는 bool값 이있는 유형을 얻도록 보장합니다 . (이 솔루션에는 제약 조건이 있습니다. 옵션에는 기본값이 있어야합니다.)TrueFalse
Trevor Boyd Smith

7
다음은 @ Maxim 's answer 의 한 줄짜리 해석입니다 parser.add_argument('--feature', dest='feature', type=lambda x:bool(distutils.util.strtobool(x))). 이 옵션을 사용하면이 솔루션은 bool값이 True또는 인 유형을 보장합니다 False. 옵션을 사용하지 않으면 얻을 수 None있습니다. ( distutils.util.strtobool(x)다른 stackoverflow 질문에서 온
Trevor Boyd Smith

8
방법에 대해parser.add_argument('--my_bool', action='store_true', default=False)
AruniRC

답변:


275

이전 제안을 사용하지만 "올바른"구문 분석 오류가있는 또 다른 솔루션은 argparse다음 과 같습니다.

def str2bool(v):
    if isinstance(v, bool):
       return v
    if v.lower() in ('yes', 'true', 't', 'y', '1'):
        return True
    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
        return False
    else:
        raise argparse.ArgumentTypeError('Boolean value expected.')

이것은 기본값으로 스위치를 만드는 데 매우 유용합니다. 예를 들어

parser.add_argument("--nice", type=str2bool, nargs='?',
                        const=True, default=False,
                        help="Activate nice mode.")

내가 사용할 수 있습니다 :

script --nice
script --nice <bool>

여전히 기본값을 사용합니다 (사용자 설정에 따라 다름). 참조 -이 접근 한 (간접적으로 관련) 단점은 'nargs'는 위치 인수를 잡을 수 있다는 것입니다 이 관련 질문이 argparse 버그 리포트를 .


4
nargs = '?' 0 또는 1 개의 인수를 의미합니다. docs.python.org/3/library/argparse.html#nargs
Maxim

1
나는 이것을 좋아하지만 default = NICE에 해당하는 오류가 발생하므로 다른 작업을 수행해야합니다.
Michael Mathews

2
@MarcelloRomani str2bool은 Python 의미의 유형이 아니며 위에서 정의한 함수이므로 어딘가에 포함시켜야합니다.
Maxim

4
의 코드는 str2bool(v)로 대체 될 수 있습니다 bool(distutils.util.strtobool(v)). 출처 : stackoverflow.com/a/18472142/2436175
Antonio

4
이 방법을 사용하면 인수가 if args.nice:False로 설정되어 있으면 인수가 beacuse 로 설정되어 있는지 확인할 수 없으며 조건을 전달하지 않습니다. 이것이 바로 그때 인 경우 어쩌면에서 목록을 반환하는 더 나은 str2bool기능과 같은 세트 목록 const이 같은 매개 변수 [True], [False]. 내가 틀렸다면 바로
잡아라

887

이 작업을 수행하는보다 정식적인 방법은 다음과 같습니다.

command --feature

command --no-feature

argparse 이 버전을 잘 지원합니다 :

parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

물론 실제로 --arg <True|False>버전을 원한다면 ast.literal_eval"type"또는 사용자 정의 함수로 전달할 수 있습니다 ...

def t_or_f(arg):
    ua = str(arg).upper()
    if 'TRUE'.startswith(ua):
       return True
    elif 'FALSE'.startswith(ua):
       return False
    else:
       pass  #error condition maybe?

96
나는 여전히 type=bool상자 밖으로 작동해야 한다고 생각 합니다 (위치 인수를 고려하십시오!). 을 추가로 지정하더라도 choices=[False,True]"False"와 "True"는 True로 간주됩니다 (문자열에서 부울로의 캐스트로 인해?). 아마 관련 문제
돌고래

41
맞아, 나는 이것이 예상대로 작동하지 않는 것에 대한 정당성이 없다고 생각한다. 안전 점검이나 오류 메시지가 없기 때문에 이것은 매우 잘못된 것입니다.
돌고래

69
@mgilson - 내가 오해의 소지가 찾을 것은 당신이 것을 할 수 유형 = 부울을 설정, 당신은 당신이 때문에 방법에 (당신의 가정 부울 변수에 True를 얻을, 모두 "거짓"과 "참"문자열 인수, 아직 오류 메시지가 없으며, 타입 캐스팅은 파이썬에서 작동합니다). 따라서 type = bool은 명확하게 지원되지 않아야하며 (일부 경고, 오류 등은 생략) 유용하고 직관적으로 예상되는 방식으로 작동해야합니다.
돌고래

14
@ dolphin-각각 동의하지 않습니다. 나는 그 행동이 정확히 있어야하는 방식이며, 파이썬의 "특별한 경우는 규칙을 어기는 것만 큼 특별하지 않다"고 생각합니다. 그러나 이것에 대해 강력하게 생각한다면, 다양한 파이썬 메일 링리스트 중 하나에서 가져 오십시오 . 거기 에서이 문제에 대해 무언가 를 힘이있는 사람을 설득 할 수 있습니다 . 당신이 저를 설득 할 수 있었다고해도, 당신은 저를 설득하는데 성공했을 것입니다. 그리고 나는 개발자가 아니기 때문에 행동이 여전히 변하지 않을 것입니다.)
mgilson

15
파이썬 bool()함수가 무엇을해야하는지, 또는 argparse가 무엇을 받아 들여야하는지에 대해 논쟁하고 type=fn있습니까? 모든 argparse확인은 fn호출 가능합니다. fn하나의 문자열 인수를 가져 와서 값을 리턴 할 것으로 예상 합니다. 의 행동은 fn프로그래머의 책임 argparse's입니다.
hpaulj

235

나는 그러나 상호 배타적 인 그룹과 mgilson의 답변을 추천
당신이 사용할 수 있도록 --feature하고 --no-feature동시에.

command --feature

command --no-feature

하지만

command --feature --no-feature

스크립트:

feature_parser = parser.add_mutually_exclusive_group(required=False)
feature_parser.add_argument('--feature', dest='feature', action='store_true')
feature_parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

그런 다음 많은 도우미를 설정하려는 경우이 도우미를 사용할 수 있습니다.

def add_bool_arg(parser, name, default=False):
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument('--' + name, dest=name, action='store_true')
    group.add_argument('--no-' + name, dest=name, action='store_false')
    parser.set_defaults(**{name:default})

add_bool_arg(parser, 'useful-feature')
add_bool_arg(parser, 'even-more-useful-feature')

5
@CharlieParker add_argument는로 호출됩니다 dest='feature'. set_defaults로 호출됩니다 feature=True. 이해하다?
fnkr

4
이 질문이나 mgilson의 답변은 OP가 원했지만 --flag False, SO 답변의 일부는 HOW가 아니라 해결하려는 것에 관한 것이어야합니다. 이 절대적으로해야 할 이유가 없을 것 --flag False또는 --other-flag True다음 부울로 문자열을 변환하는 일부 사용자 지정 파서를 사용 .. action='store_true'action='store_false'부울 플래그를 사용하는 가장 좋은 방법입니다
kevlarr

6
@cowlinator 왜 "명시된 질문들"에 대한 답을 하는가? 에 따르면 자신의 지침 , anwer ... can be “don’t do that”, but it should also include “try this instead”(나에게 적어도) 답변을 의미 할 때 적절한 깊이로 이동합니다. 우리 중 일부가 질문을 게시하는 것이 더 나은 / 우수 사례 등에 대한 지침으로부터 도움을받을 수있는 경우가 있습니다. 즉, 너무 많은 (또는 잘못) 가정하는 대답에 대한 좌절은 완전히 유효합니다.
kevlarr

2
사용자가 기능을 명시 적으로 지정하지 않은 경우에 대한 세 번째 값을 원하면 마지막 행을parser.set_defaults(feature=None)
Alex Che

2
help=이 인수 에 대한 항목 을 추가하려면 어디로 가야합니까? 에서 add_mutually_exclusive_group()호출? add_argument()통화 중 하나 또는 둘 다 ? 다른 곳?
Ken Williams

57

다음은 기본값을 설정하기 위해 추가 행이없는 다른 변형입니다. 부울은 항상 사전 점검없이 논리 문에서 사용될 수 있도록 지정된 값을 갖습니다.

import argparse
parser = argparse.ArgumentParser(description="Parse bool")
parser.add_argument("--do-something", default=False, action="store_true" , help="Flag to do something")
args = parser.parse_args()

if args.do_something:
     print("Do something")
else:
     print("Don't do something")
print("Check that args.do_something=" + str(args.do_something) + " is always a bool")

5
이 답변은 과소 평가되었지만 단순성에는 훌륭합니다. 설정하지 마십시오. 그렇지 않으면 required=True항상 True 인수가 발생합니다.
Garren S

1
제발 결코 부울 또는 nonetype 같은 것들에 평등 연산자를 사용하지 않습니다. 대신 IS 를 사용해야 합니다
webKnjaZ

2
중복 부울 문자열을 요구하지 않고 부울 값을 설정하기 위해 플래그가 있는지 확인하기 때문에 허용되는 것보다 더 나은 대답입니다. (Yo dawg, 부울을 좋아한다고 들었습니다 ... 그래서 부울을 설정하기 위해 부울과 함께 부울을주었습니다!)
Siphon

4
흠 ... 질문은 언급 한 바와 같이 명령 행 자체에서 "True"/ "False"를 사용하는 것 같습니다. 그러나이 예제에서는로 python3 test.py --do-something False실패 error: unrecognized arguments: False하므로 실제로 질문에 대답하지 않습니다.
sdbbs

38

짧막 한 농담:

parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))

4
oneliner 팬에게도 좋으며, 약간 개선 될 수도 있습니다.type=lambda x: (str(x).lower() in ['true','1', 'yes'])
Tu Bui

35

무엇 type=booltype='bool'의미 하는지 혼동이있는 것 같습니다 . 하나 (또는 ​​둘 다)가 '함수를 실행 bool()하거나'부울을 반환 하십시오 '를 의미해야합니까 ? 그것이 의미 type='bool'하는 것은 아무것도 의미하지 않습니다. add_argument제공 'bool' is not callable사용한 경우와 같은 오류 type='foobar', 또는 type='int'.

그러나 argparse이와 같은 키워드를 정의 할 수있는 레지스트리가 있습니다. action`action = 'store_true'와 같이 주로 사용됩니다 . 다음과 같이 등록 된 키워드를 볼 수 있습니다.

parser._registries

사전을 표시하는

{'action': {None: argparse._StoreAction,
  'append': argparse._AppendAction,
  'append_const': argparse._AppendConstAction,
...
 'type': {None: <function argparse.identity>}}

많은 작업이 정의되어 있지만 기본 유형 인 한 가지 유형 만 argparse.identity있습니다.

이 코드는 'bool'키워드를 정의합니다.

def str2bool(v):
  #susendberg's function
  return v.lower() in ("yes", "true", "t", "1")
p = argparse.ArgumentParser()
p.register('type','bool',str2bool) # add type keyword to registries
p.add_argument('-b',type='bool')  # do not use 'type=bool'
# p.add_argument('-b',type=str2bool) # works just as well
p.parse_args('-b false'.split())
Namespace(b=False)

parser.register()문서화되지 않았지만 숨겨지지 않았습니다. 대부분의 프로그래머 때문에 그것에 대해 알 필요가 없습니다 typeaction테이크 기능과 클래스 값. 둘 다에 대한 사용자 정의 값을 정의하는 많은 스택 오버 플로우 예제가 있습니다.


이전 논의에서 명확 bool()하지 않은 경우 '문자열 구문 분석'을 의미하지 않습니다. 파이썬 문서에서 :

bool (x) : 표준 진리 테스트 절차를 사용하여 값을 부울로 변환합니다.

이것과 대조

int (x) : 숫자 또는 문자열 x를 정수로 변환합니다.


3
또는 다음을 사용하십시오. parser.register ( 'type', 'bool', (( "yes", "true", "t", "1"))의 λ x : x.lower ())
Matyas

17

나는 같은 문제를 찾고 있었고 예쁜 해결책은 다음과 같습니다.

def str2bool(v):
  return v.lower() in ("yes", "true", "t", "1")

위의 제안대로 문자열을 부울로 구문 분석하는 데 사용합니다.


5
이 경로를 사용하려면을 제안하십시오 distutils.util.strtobool(v).
CivFan

1
distutils.util.strtobool반환 1 또는 0이 아닌 실제 부울.
CMCDragonkai

14

비슷한 방법으로 다음을 사용하십시오.

feature.add_argument('--feature',action='store_true')

명령에 --feature 인수를 설정하면

 command --feature

type --feature를 설정하지 않으면 인수의 기본값은 항상 False입니다!


1
다른 방법으로 극복 할 수있는이 방법의 단점이 있습니까? 이것은 OP (그리고이 경우 나)가 원했던 것에 도달하는 가장 쉽고 간결한 솔루션 인 것 같습니다. 나는 그것을 좋아한다.
Simon O'Hanlon 2016 년

2
간단하지만 질문에 대답하지 않습니다. OP는 당신이 지정할 수있는 논쟁을 원합니다--feature False
Astariul


12

이것은 내가 기대하는 모든 것에 적용됩니다.

add_boolean_argument(parser, 'foo', default=True)
parser.parse_args([])                   # Whatever the default was
parser.parse_args(['--foo'])            # True
parser.parse_args(['--nofoo'])          # False
parser.parse_args(['--foo=true'])       # True
parser.parse_args(['--foo=false'])      # False
parser.parse_args(['--foo', '--nofoo']) # Error

코드:

def _str_to_bool(s):
    """Convert string to bool (in argparse context)."""
    if s.lower() not in ['true', 'false']:
        raise ValueError('Need bool; got %r' % s)
    return {'true': True, 'false': False}[s.lower()]

def add_boolean_argument(parser, name, default=False):                                                                                               
    """Add a boolean argument to an ArgumentParser instance."""
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '--' + name, nargs='?', default=default, const=True, type=_str_to_bool)
    group.add_argument('--no' + name, dest=name, action='store_false')

우수한! 나는이 대답으로 갈 것입니다. 나는 한 번 _str_to_bool(s)변환 하고 s = s.lower()테스트 한 다음 if s not in {'true', 'false', '1', '0'}마침내 하도록 조정했습니다 return s in {'true', '1'}.
Jerry101

6

더 간단한 방법은 다음과 같이 사용하는 것입니다.

parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])

5

가장 간단합니다. 융통성이 없지만 단순성을 선호합니다.

  parser.add_argument('--boolean_flag',
                      help='This is a boolean flag.',
                      type=eval, 
                      choices=[True, False], 
                      default='True')

편집 : 입력을 신뢰하지 않으면를 사용하지 마십시오 eval.


이것은 매우 편리해 보입니다. 유형이 eval 인 것으로 나타났습니다. 나는 이것에 대해 질문을했다 : eval은 어떻게 정의되어야합니까, 또는 그것을 사용하기 위해 수입이 필요합니까?
edesz

1
eval내장 함수입니다. docs.python.org/3/library/functions.html#eval 다른보다 유연한 접근 방식이 활용하는 모든 단항 함수일 수 있습니다.
러셀

이봐, 대단해. 감사!
edesz

2
그것은 귀엽지 만, 악의 평가를 모르는 사용자가 그것을 대본에 복사하여 붙여 넣는 야생에 넣는 것은 매우 위험합니다 .
아르네의

@Arne, 좋은 지적. 그러나, 의도가 좋은 사용자가 실수로 위험한 일을하는 것은 꽤 어려운 것처럼 보입니다.
러셀

3

가장 간단한 방법은 선택 을 사용하는 것입니다 .

parser = argparse.ArgumentParser()
parser.add_argument('--my-flag',choices=('True','False'))

args = parser.parse_args()
flag = args.my_flag == 'True'
print(flag)

--my-flag를 전달하지 않으면 False로 평가됩니다. 필요 = 사실 당신은 항상 명시 적으로 선택을 지정하려면 사용자가 원하는 경우에 옵션을 추가 할 수 있습니다.


2

가장 표준적인 방법은 다음과 같습니다.

parser.add_argument('--ensure', nargs='*', default=None)

ENSURE = config.ensure is None

1
class FlagAction(argparse.Action):
    # From http://bugs.python.org/issue8538

    def __init__(self, option_strings, dest, default=None,
                 required=False, help=None, metavar=None,
                 positive_prefixes=['--'], negative_prefixes=['--no-']):
        self.positive_strings = set()
        self.negative_strings = set()
        for string in option_strings:
            assert re.match(r'--[A-z]+', string)
            suffix = string[2:]
            for positive_prefix in positive_prefixes:
                self.positive_strings.add(positive_prefix + suffix)
            for negative_prefix in negative_prefixes:
                self.negative_strings.add(negative_prefix + suffix)
        strings = list(self.positive_strings | self.negative_strings)
        super(FlagAction, self).__init__(option_strings=strings, dest=dest,
                                         nargs=0, const=None, default=default, type=bool, choices=None,
                                         required=required, help=help, metavar=metavar)

    def __call__(self, parser, namespace, values, option_string=None):
        if option_string in self.positive_strings:
            setattr(namespace, self.dest, True)
        else:
            setattr(namespace, self.dest, False)

1

가장 간단하고 가장 정확한 방법은

from distutils import util
arser.add_argument('--feature', dest='feature', type=lambda x:bool(distutils.util.strtobool(x)))

True 값은 y, yes, t, true, on 및 1입니다. false 값은 n, no, f, false, off 및 0입니다. val이 다른 경우 ValueError가 발생합니다.


0

빠르고 쉬운 반면 인수 0 또는 1에 대해서만

parser.add_argument("mybool", default=True,type=lambda x: bool(int(x)))
myargs=parser.parse_args()
print(myargs.mybool)

터미널에서 호출 한 후 출력은 "False"가됩니다.

python myscript.py 0

-1

@Akash와 비슷하지만 여기에 내가 사용한 또 다른 접근법이 있습니다. 그것은 사용하는 str것보다 lambda파이썬이 있기 때문에 lambda항상 나에게 외계인 느낌을 제공합니다.

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument("--my_bool", type=str, default="False")
args = parser.parse_args()

if bool(strtobool(args.my_bool)) is True:
    print("OK")

-1

@Akash Desarda의 답변을 향상 시키면 할 수 있습니다.

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument("--foo", 
    type=lambda x:bool(strtobool(x)),
    nargs='?', const=True, default=False)
args = parser.parse_args()
print(args.foo)

그리고 그것은 지원합니다 python test.py --foo

(base) [costa@costa-pc code]$ python test.py
False
(base) [costa@costa-pc code]$ python test.py --foo 
True
(base) [costa@costa-pc code]$ python test.py --foo True
True
(base) [costa@costa-pc code]$ python test.py --foo False
False
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.