Convertir valor verdadero / falso leído del archivo a booleano

86

Estoy leyendo un True - Falsevalor de un archivo y necesito convertirlo a booleano. Actualmente, siempre lo convierte Trueincluso si el valor está establecido en False.

Aquí está una MWEde lo que estoy tratando de hacer:

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'

El file.datarchivo consta básicamente de una sola cadena con el valor Trueo Falseescrito en su interior. El arreglo parece muy complicado porque este es un ejemplo mínimo de un código mucho más grande y así es como leo los parámetros en él.

¿Por qué flagsiempre se está convirtiendo a True?

Gabriel
fuente
1
pip install str2bool
Symon

Respuestas:

100

bool('True')y bool('False')siempre regresaTrue porque las cadenas 'True' y 'False' no están vacías.

Para citar a un gran hombre (y documentación de Python ):

5.1. Prueba de valor de verdad

Se puede probar cualquier objeto para determinar su valor de verdad, para usarlo en una condición if o while o como operando de las operaciones booleanas siguientes. Los siguientes valores se consideran falsos:

  • ...
  • cero de cualquier tipo numérico, por ejemplo, 0, 0L, 0.0,0j .
  • cualquier secuencia de vacío, por ejemplo, '', (),[] .
  • ...

Todos los demás valores se consideran verdaderos, por lo que los objetos de muchos tipos siempre son verdaderos.

La boolfunción incorporada utiliza el procedimiento estándar de prueba de verdad. Es por eso que siempre estás recibiendoTrue .

Para convertir una cadena en booleano, debe hacer algo como esto:

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
fuente
23
Podrías convertirlo en un "heroico" ValueErrorhaciéndolo raise ValueError("Cannot covert {} to a bool".format(s)).
SethMMorton
Seleccionando este ya que no usa paquetes adicionales. ¡Gracias chicos!
Gabriel
1
¿Qué pasa con los "paquetes adicionales"? ¿Te refieres a ast? Es parte de la biblioteca estándar, por lo que no es realmente extra.
SethMMorton
4
podría ser una pregunta tonta, pero ¿por qué boolsimplemente no convierte las cadenas Truey Falselos valores booleanos Truey False? Parece ser un comportamiento inconsistente de lo que inthace. Tengo curiosidad genuina de por qué mi razonamiento es incorrecto y por qué la otra opción fue la decisión.
Charlie Parker
1
Siempre que comparo cadenas, me gusta aplanar el caso (cuando corresponda). por ejemplo, usaría: if s.upper () == 'TRUE': return True elif s.upper () == 'FALSE' return False
Bill Kidd
75

puedes usar distutils.util.strtobool

>>> from distutils.util import strtobool

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

Truevalores son y, yes, t, true,on y 1; Falselos valores son n, no, f, false, offy 0. Sube ValueErrorsi val es otra cosa.

Francesco Nazzaro
fuente
22
Aún mejor, haga bool(strtobool(my_string))para convertir la salida como una variable booleana Verdadero / Falso
AlexG
10
@AlexG loco que una función llamada strtobool()no, de hecho, devuelve unbool
dericke
61

Utilizar ast.literal_eval:

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

¿Por qué la bandera siempre se convierte en True?

Las cadenas no vacías siempre son verdaderas en Python.

Relacionado: Prueba de valor de verdad


Si NumPy es una opción, entonces:

>>> 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
fuente
podría ser una pregunta tonta, pero ¿por qué boolsimplemente no convierte las cadenas Truey Falselos valores booleanos Truey False? Parece ser un comportamiento inconsistente de lo que inthace. Tengo curiosidad genuina de por qué mi razonamiento es incorrecto y por qué la otra opción fue la decisión.
Charlie Parker
2
ast.literal_eval ('false') arroja una excepción, que creo que la hace menos deseable
Chris
@Chris Siempre puede ajustarlo a try, excepto en una función personalizada en lugar de usarlo directamente en ese momento.
Ashwini Chaudhary
@HewwoCraziness Analiza solo expresiones, no ningún código aleatorio.
Ashwini Chaudhary
15

La solución más limpia que he visto es:

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

Claro, requiere una importación, pero tiene un manejo adecuado de errores y requiere muy poco código para ser escrito (y probado).

vpetersson
fuente
13

No me sugiero que esta sea la mejor respuesta, solo una alternativa, pero también puede hacer algo como:

flag = reader[0] == "True"

la bandera será Trueid reader [0] es "True", de lo contrario lo será False.

elParaguayo
fuente
10

Actualmente, está evaluando a Trueporque la variable tiene un valor. Aquí se encuentra un buen ejemplo de lo que sucede cuando evalúa tipos arbitrarios como booleanos.

En resumen, lo que quiere hacer es aislar la cadena 'True'o 'False'y ejecutarla eval.

>>> eval('True')
True
>>> eval('False')
False
Gautam Joshi
fuente
4
@samyi Es peligroso usar el método eval. stackoverflow.com/questions/1832940/…
M07
1
FYI. Esta es una idea terrible y nunca debería usarla eval(). En mi opinión, debería eliminarse del idioma.
Nostalg.io
Esto es MUY MUY MALO porque es una falla de seguridad. Si usa eval()datos sin procesar de un archivo, significa que cualquier persona con acceso de escritura a ese archivo puede ejecutar código con el mismo nivel de permisos que su script.
Keith Ripley
Además, si los valores no tienen la ortografía exacta de Python, por ejemplo eval('false'), eval('FALSE')se producirá un error.
kev
5

Puede usar dict para convertir cadenas a booleanas. Cambie esta línea flag = bool(reader[0])a:

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

Si desea distinguir entre mayúsculas y minúsculas, puede hacer lo siguiente:

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

Uso de ejemplo:

>>> 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
fuente
3

pip instalar str2bool

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

Puede hacer con json.

In [124]: import json

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

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

Solo para agregar que si su valor de verdad puede variar, por ejemplo, si es una entrada de diferentes lenguajes de programación o de diferentes tipos, un método más robusto sería:

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

Y una variante más eficaz sería (set lookup is O (1)):

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

Si sus datos son de json, puede hacerlo

importar json

json.loads ('verdadero')

Cierto

Ivan Camilito Ramirez Verdes
fuente
0

Si necesita una forma rápida de convertir cadenas en bools (que funciona con la mayoría de las cadenas) intente.

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

usuario6830669
fuente
0

Usar dictados para convertir "Verdadero" en Verdadero:

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