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=bool을 type='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()문서화되지 않았지만 숨겨지지 않았습니다. 대부분의 프로그래머 때문에 그것에 대해 알 필요가 없습니다 type및 action테이크 기능과 클래스 값. 둘 다에 대한 사용자 정의 값을 정의하는 많은 스택 오버 플로우 예제가 있습니다.


이전 논의에서 명확 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.