Ik wil argparse gebruiken om booleaanse opdrachtregelargumenten te ontleden die zijn geschreven als “–foo True” of “–foo False”. Bijvoorbeeld:
my_program --my_boolean_flag False
De volgende testcode doet echter niet wat ik zou willen:
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)
Helaas evalueert parsed_args.my_bool
tot True
. Dit is zelfs het geval wanneer ik cmd_line
verander in ["--my_bool", ""]
, wat verrassend is, aangezien bool("")
evalueert tot False
.
Hoe kan ik ervoor zorgen dat argparse "False"
, "F"
en hun varianten in kleine letters om False
te ontleden?
Antwoord 1, autoriteit 100%
Nog een andere oplossing die de vorige suggesties gebruikt, maar met de “juiste” parseerfout van 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.')
Dit is erg handig om schakelaars te maken met standaardwaarden; bijvoorbeeld
parser.add_argument("--nice", type=str2bool, nargs='?',
const=True, default=False,
help="Activate nice mode.")
kan ik gebruiken:
script --nice
script --nice <bool>
en nog steeds een standaardwaarde gebruiken (specifiek voor de gebruikersinstellingen). Een (indirect gerelateerd) nadeel van die aanpak is dat de ‘nargs’ een positioneel argument kunnen vangen — zie deze gerelateerde vraagen dit argparse-bugrapport.
Antwoord 2, autoriteit 95%
Ik denk dat een meer canonieke manier om dit te doen is via:
command --feature
en
command --no-feature
argparse
ondersteunt deze versie goed:
parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)
Als u echt de --arg <True|False>
-versie wilt, kunt u natuurlijk ast.literal_eval
doorgeven als het “type”, of een door de gebruiker gedefinieerde functie …
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?
Antwoord 3, autoriteit 74%
Als je --feature
en --no-feature
tegelijkertijd wilt toestaan (laatste wint)
Hiermee kunnen gebruikers een shell-alias maken met --feature
en deze overschrijven met --no-feature
.
Python 3.9 en hoger
parser.add_argument('--feature', default=True, action=argparse.BooleanOptionalAction)
Python 3.8 en lager
Ik raad het antwoord van mgilson aan:
parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)
Als u --feature
en --no-feature
NIET tegelijkertijd wilt toestaan
U kunt een wederzijds uitsluitende groep gebruiken:
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)
Je kunt deze helper gebruiken als je er veel wilt instellen:
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')
Antwoord 4, autoriteit 24%
Hier is een andere variatie zonder extra rij / s om standaardwaarden in te stellen. De Booleaanse waarde wordt altijd toegewezen, zodat deze in logische verklaringen kan worden gebruikt zonder vooraf te controleren:
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(f"Check that args.do_something={args.do_something} is always a bool.")
5, Autoriteit 15%
Oneliner:
parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))
6, Autoriteit 9%
Er lijkt enige verwarring te zijn over wat type=bool
en type='bool'
zou kunnen betekenen. Moet een (of beide) betekenen ‘Run de functie bool()
of’ retourneer een boolean ‘? Zoals het staat type='bool'
betekent niets. add_argument
Geeft een 'bool' is not callable
FOUT, hetzelfde als u gebruikte type='foobar'
, of type='int'
.
Maar argparse
heeft register waarmee u zoekwoorden als deze kunt definiëren. Het wordt meestal gebruikt voor action
, b.v. `Actie = ‘Store_true’. U kunt de geregistreerde trefwoorden bekijken met:
parser._registries
die een woordenboek weergeeft
{'action': {None: argparse._StoreAction,
'append': argparse._AppendAction,
'append_const': argparse._AppendConstAction,
...
'type': {None: <function argparse.identity>}}
Er zijn veel acties gedefinieerd, maar slechts één type, de standaard, argparse.identity
.
Deze code definieert een ‘bool’-zoekwoord:
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()
is niet gedocumenteerd, maar ook niet verborgen. Voor het grootste deel hoeft de programmeur er niets van te weten omdat type
en action
functie- en klassewaarden aannemen. Er zijn veel stackoverflow-voorbeelden van het definiëren van aangepaste waarden voor beide.
In het geval dat het niet duidelijk is uit de vorige discussie, bool()
betekent niet ‘een string ontleden’. Uit de Python-documentatie:
bool(x): Converteer een waarde naar een Boolean, met behulp van de standaard waarheidstestprocedure.
Vergelijk dit met
int(x): Converteer een getal of tekenreeks x naar een geheel getal.
Antwoord 7, autoriteit 6%
Een vergelijkbare manier is om:
feature.add_argument('--feature',action='store_true')
en als je het argument –feature in je commando zet
command --feature
het argument zal True zijn, als u geen type –feature instelt, zijn de standaardargumenten altijd False!
Antwoord 8, autoriteit 4%
Ik was op zoek naar hetzelfde probleem, en ik denk dat de mooie oplossing is:
def str2bool(v):
return v.lower() in ("yes", "true", "t", "1")
en dat gebruiken om de string te ontleden naar boolean, zoals hierboven gesuggereerd.
Antwoord 9, autoriteit 3%
Eenvoudigste & meest correcte manier is:
from distutils.util import strtobool
parser.add_argument('--feature', dest='feature',
type=lambda x: bool(strtobool(x)))
Houd er rekening mee dat True-waarden y, yes, t, true, on en 1 zijn;
false waarden zijn n, no, f, false, off en 0. Verhoogt ValueError als val iets anders is.
Antwoord 10, autoriteit 3%
Naast wat @mgilson zei, moet worden opgemerkt dat er ook een ArgumentParser.add_mutually_exclusive_group(required=False)
methode die het triviaal zou maken om af te dwingen dat --flag
en --no-flag
zijn’ t tegelijkertijd gebruikt.
Antwoord 11, autoriteit 3%
Dit werkt voor alles wat ik ervan verwacht:
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
De code:
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')
Antwoord 12, autoriteit 2%
Het eenvoudigst. Het is niet flexibel, maar ik geef de voorkeur aan eenvoud.
parser.add_argument('--boolean_flag',
help='This is a boolean flag.',
type=eval,
choices=[True, False],
default='True')
EDIT:Als je de invoer niet vertrouwt, gebruik dan geen eval
.
Antwoord 13, autoriteit 2%
Een eenvoudigere manier zou zijn om te gebruiken zoals hieronder.
parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])
Antwoord 14
De eenvoudigste manier is om keuzeste gebruiken:
parser = argparse.ArgumentParser()
parser.add_argument('--my-flag',choices=('True','False'))
args = parser.parse_args()
flag = args.my_flag == 'True'
print(flag)
Niet doorgeven –my-flag evalueert naar False. De optie required=Truekan worden toegevoegd als u altijd wilt dat de gebruiker een keuze expliciet opgeeft.
Antwoord 15
Ik denk dat de meest canonieke manier zal zijn:
parser.add_argument('--ensure', nargs='*', default=None)
ENSURE = config.ensure is None
Antwoord 16
Als een verbetering van het antwoord van @Akash Desarda, zou je kunnen doen
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)
En het ondersteunt 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
Antwoord 17
Snel en gemakkelijk, maar alleen voor argumenten 0 of 1:
parser.add_argument("mybool", default=True,type=lambda x: bool(int(x)))
myargs=parser.parse_args()
print(myargs.mybool)
De uitvoer zal “False” zijn na aanroepen vanaf terminal:
python myscript.py 0
Antwoord 18
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)
19
vergelijkbaar met @akash maar hier is een andere benadering die ik heb gebruikt. Het gebruikt str
dan lambda
omdat Python lambda
altijd een buitenaardse gevoelens geeft.
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")
20
Doe gewoon het volgende, u kunt --test = True
maken door
te gebruiken
Python-bestandsnaam – Test
parser.add_argument("--test" , default=False ,help="test ?", dest='test', action='store_true')
21
Converteer de waarde:
def __arg_to_bool__(arg):
"""__arg_to_bool__
Convert string / int arg to bool
:param arg: argument to be converted
:type arg: str or int
:return: converted arg
:rtype: bool
"""
str_true_values = (
'1',
'ENABLED',
'ON',
'TRUE',
'YES',
)
str_false_values = (
'0',
'DISABLED',
'OFF',
'FALSE',
'NO',
)
if isinstance(arg, str):
arg = arg.upper()
if arg in str_true_values:
return True
elif arg in str_false_values:
return False
if isinstance(arg, int):
if arg == 1:
return True
elif arg == 0:
return False
if isinstance(arg, bool):
return arg
# if any other value not covered above, consider argument as False
# or you could just raise and error
return False
[...]
args = ap.parse_args()
my_arg = options.my_arg
my_arg = __arg_to_bool__(my_arg)