Converter valor verdadeiro / falso lido do arquivo para booleano

86

Estou lendo um True - Falsevalor de um arquivo e preciso convertê-lo em booleano. Atualmente, ele sempre o converte em Truemesmo se o valor for definido como False.

Aqui está um exemplo MWEdo que estou tentando fazer:

with open('file.dat', mode="r") as f:
    for line in f:
        reader = line.split()
        # Convert to boolean <-- Not working?
        flag = bool(reader[0])

if flag:
    print 'flag == True'
else:
    print 'flag == False'

O file.datarquivo consiste basicamente em uma única string com o valor Trueou Falseescrito dentro. O arranjo parece muito complicado porque este é um exemplo mínimo de um código muito maior e é assim que eu leio os parâmetros nele.

Por que está flagsempre convertendo para True?

Gabriel
fonte
1
pip install str2bool
Symon

Respostas:

100

bool('True')e bool('False')sempre retorna Trueporque as strings 'True' e 'False' não estão vazias.

Para citar um grande homem (e a documentação do Python ):

5.1. Teste de valor da verdade

Qualquer objeto pode ser testado quanto ao valor de verdade, para uso em uma condição if ou while ou como operando das operações booleanas abaixo. Os seguintes valores são considerados falsos:

  • de zero de qualquer tipo numérico, por exemplo, 0, 0L, 0.0, 0j.
  • qualquer sequência de vazio, por exemplo, '', (), [].

Todos os outros valores são considerados verdadeiros - portanto, objetos de muitos tipos são sempre verdadeiros.

A boolfunção interna usa o procedimento de teste de verdade padrão. É por isso que você sempre consegue True.

Para converter uma string em booleano, você precisa fazer algo assim:

def str_to_bool(s):
    if s == 'True':
         return True
    elif s == 'False':
         return False
    else:
         raise ValueError # evil ValueError that doesn't tell you what the wrong value was
Nigel Tufnel
fonte
23
Você poderia tornar isso um "heróico" ValueErrorfazendo raise ValueError("Cannot covert {} to a bool".format(s)).
SethMMorton
Selecionando este, pois não usa pacotes extras. Obrigado rapazes!
Gabriel
1
O que há de errado com "pacotes extras"? Você está se referindo a ast? Faz parte da biblioteca padrão, portanto, não é realmente extra.
SethMMorton
4
pode ser uma pergunta boba, mas por que boolsimplesmente não converte as strings Truee Falsepara os valores booleanos Truee False? Parece ser um comportamento inconsistente com o que intfaz. Eu apenas estou genuinamente curioso por que meu raciocínio está errado e por que a outra opção foi a decisão.
Charlie Parker
1
Sempre que comparo strings, gosto de achatar a caixa (quando aplicável). por exemplo, eu usaria: if s.upper () == 'TRUE': return True elif s.upper () == 'FALSE' return False
Bill Kidd
75

você pode usar distutils.util.strtobool

>>> from distutils.util import strtobool

>>> strtobool('True')
1
>>> strtobool('False')
0

TrueOs valores são y, yes, t, true, one 1; FalseOs valores são n, no, f, false, offe 0. Aumenta ValueErrorse val for qualquer outra coisa.

Francesco Nazzaro
fonte
22
Melhor ainda, faça bool(strtobool(my_string))para converter a saída como uma variável booleana True / False
AlexG
10
@AlexG louco que uma função chamada strtobool()não retorna, de fato, umbool
dericke
61

Use ast.literal_eval:

>>> import ast
>>> ast.literal_eval('True')
True
>>> ast.literal_eval('False')
False

Por que flag está sempre convertendo para True?

Strings não vazias são sempre True em Python.

Relacionado: Teste de Valor da Verdade


Se NumPy for uma opção, então:

>>> import StringIO
>>> import numpy as np
>>> s = 'True - False - True'
>>> c = StringIO.StringIO(s)
>>> np.genfromtxt(c, delimiter='-', autostrip=True, dtype=None) #or dtype=bool
array([ True, False,  True], dtype=bool)
Ashwini Chaudhary
fonte
pode ser uma pergunta boba, mas por que boolsimplesmente não converte as strings Truee Falsepara os valores booleanos Truee False? Parece ser um comportamento inconsistente com o que intfaz. Eu apenas estou genuinamente curioso por que meu raciocínio está errado e por que a outra opção foi a decisão.
Charlie Parker
2
ast.literal_eval ('false') lança uma exceção, o que eu acho que a torna menos desejável
Chris
@Chris Você sempre pode envolvê-lo em try-except em uma função personalizada em vez de usá-lo diretamente.
Ashwini Chaudhary
@HewwoCraziness Ele analisa apenas expressões, não qualquer código aleatório.
Ashwini Chaudhary
15

A solução mais limpa que já vi é:

from distutils.util import strtobool
def string_to_bool(string):
    return bool(strtobool(str(string)))

Claro, ele requer uma importação, mas tem tratamento de erros adequado e requer muito pouco código para ser escrito (e testado).

vpetersson
fonte
13

Não estou sugerindo que esta seja a melhor resposta, apenas uma alternativa, mas você também pode fazer algo como:

flag = reader[0] == "True"

flag será Trueid reader [0] é "True", caso contrário, será False.

elParaguai
fonte
10

Atualmente, está avaliando para Trueporque a variável tem um valor. Há um bom exemplo encontrado aqui do que acontece quando você avalia tipos arbitrários como booleanos.

Resumindo, o que você quer fazer é isolar a string 'True'ou 'False'e executá eval-la.

>>> eval('True')
True
>>> eval('False')
False
Gautam Joshi
fonte
4
@samyi É perigoso usar o método eval. stackoverflow.com/questions/1832940/…
M07
1
PARA SUA INFORMAÇÃO. Esta é uma ideia terrível e você nunca deve usar eval(). Na minha opinião, deve ser removido da linguagem.
Nostalg.io
Isso é MUITO RUIM porque é uma falha de segurança. Se você usar eval()dados brutos de um arquivo, isso significa que qualquer pessoa com acesso de gravação a esse arquivo pode executar o código no mesmo nível de permissão do seu script.
Keith Ripley,
Além disso, se os valores não tiverem a grafia exata do python, por exemplo eval('false'), eval('FALSE')haverá um erro.
kev
5

Você pode usar dict para converter string em booleano. Altere esta linha flag = bool(reader[0])para:

flag = {'True': True, 'False': False}.get(reader[0], False) # default is False
ndpu
fonte
5

Se você quiser não diferenciar maiúsculas de minúsculas, pode apenas fazer:

b = True if bool_str.lower() == 'true' else False

Exemplo de uso:

>>> bool_str = 'False'
>>> b = True if bool_str.lower() == 'true' else False
>>> b
False
>>> bool_str = 'true'
>>> b = True if bool_str.lower() == 'true' else False
>>> b
True
Caleb
fonte
3

pip install str2bool

>>> from str2bool import str2bool
>>> str2bool('Yes')
True
>>> str2bool('FaLsE')
False
Symon
fonte
2

Você pode fazer com json.

In [124]: import json

In [125]: json.loads('false')
Out[125]: False

In [126]: json.loads('true')
Out[126]: True
Rahul KP
fonte
2

Apenas para acrescentar que se o seu valor de verdade pode variar, por exemplo, se for uma entrada de diferentes linguagens de programação ou de diferentes tipos, um método mais robusto seria:

flag = value in ['True','true',1,'T','t','1'] # this can be as long as you want to support

E uma variante de maior desempenho seria (set lookup is O (1)):

TRUTHS = set(['True','true',1,'T','t','1'])
flag = value in truths
Daniel Dubovski
fonte
1

Se seus dados forem da JSON, você pode fazer isso

import json

json.loads ('true')

Verdadeiro

Ivan Camilito Ramirez Verdes
fonte
0

Se você precisa de uma maneira rápida de converter strings em bools (que funcionam com a maioria das strings), tente.

def conv2bool(arg):
   try:
     res= (arg[0].upper()) == "T"
   except Exception,e:
     res= False
   return res # or do some more processing with arg if res is false

user6830669
fonte
0

Usando dicts para converter "True" em True:

def str_to_bool(s: str):
    status = {"True": True,
                "False": False}
    try:
        return status[s]
    except KeyError as e:
        #logging
Chris
fonte