Преобразование значения True / False, прочитанного из файла, в логическое


86

Я читаю True - Falseзначение из файла, и мне нужно преобразовать его в логическое значение. В настоящее время он всегда преобразует его в, Trueдаже если установлено значение False.

Вот MWEчто я пытаюсь сделать:

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'

file.datФайл в основном состоит из одной строки со значением Trueили Falseписьменной внутри. Расположение выглядит очень запутанным, потому что это минимальный пример из гораздо большего кода, и именно так я считываю в него параметры.

Почему flagвсегда конвертируется в True?


1
pip install str2bool
Symon

Ответы:


100

bool('True')и bool('False')всегда возвращать, Trueпотому что строки «Истина» и «Ложь» не пусты.

Процитирую великого человека (и документацию Python ):

5.1. Проверка истинности

Любой объект может быть протестирован на предмет истинности, для использования в условии if или while или в качестве операнда логических операций ниже. Следующие значения считаются ложными:

  • нуль любого числового типа, например, 0, 0L, 0.0, 0j.
  • любая пустая последовательность, например, '', (), [].

Все остальные значения считаются истинными, поэтому объекты многих типов всегда истинны.

Встроенная boolфункция использует стандартную процедуру проверки истинности. Вот почему ты всегда получаешь True.

Чтобы преобразовать строку в логическое значение, вам нужно сделать что-то вроде этого:

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

23
Вы могли бы сделать это «героическим» ValueError, сделав это raise ValueError("Cannot covert {} to a bool".format(s)).
SethMMorton

Выбор этого варианта, поскольку он не использует дополнительных пакетов. Спасибо ребята!
Габриэль

1
Что не так с «дополнительными пакетами»? Вы имеете в виду ast? Это часть стандартной библиотеки, поэтому на самом деле не лишняя.
SethMMorton

4
это может быть глупый вопрос, но почему boolпросто не преобразовать строки Trueи Falseв логические значения Trueи False? Кажется, непоследовательное поведение от того, что intделает. Мне просто искренне любопытно, почему мои рассуждения неверны и почему был выбран другой вариант.
Чарли Паркер

1
Каждый раз, сравнивая строки, мне нравится сглаживать регистр (где это применимо). например, я бы использовал: if s.upper () == 'TRUE': return True elif s.upper () == 'FALSE' return False
Билл Кидд

75

ты можешь использовать distutils.util.strtobool

>>> from distutils.util import strtobool

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

Trueзначения y, yes, t, true, onи 1; Falseзначения n, no, f, false, offи 0. Повышает, ValueErrorесли val - это что-то еще.


22
Еще лучше, сделать bool(strtobool(my_string))вывод как логическую переменную True / False
AlexG

10
@AlexG сумасшедший, что вызванная функция strtobool()на самом деле не возвращаетbool
dericke

61

Использование ast.literal_eval:

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

Почему flag всегда преобразуется в True?

Непустые строки всегда имеют значение True в Python.

Связанный: Проверка истинности


Если NumPy - вариант, то:

>>> 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)

это может быть глупый вопрос, но почему boolпросто не преобразовать строки Trueи Falseв логические значения Trueи False? Кажется, непоследовательное поведение от того, что intделает. Мне просто искренне любопытно, почему мои рассуждения неверны и почему был выбран другой вариант.
Чарли Паркер

2
ast.literal_eval ('false') выдает исключение, что, как мне кажется, делает его менее желательным
Крис

@Chris Вы всегда можете обернуть его вокруг try-except в пользовательскую функцию вместо того, чтобы использовать ее напрямую.
Ашвини Чаудхари

@HewwoCraziness Он анализирует только выражения, а не случайный код.
Ашвини Чаудхари

15

Самое чистое решение, которое я видел:

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

Конечно, для этого требуется импорт, но он имеет правильную обработку ошибок и требует написания (и тестирования) очень небольшого количества кода.


13

Я не предлагаю это как лучший ответ, это просто альтернатива, но вы также можете сделать что-то вроде:

flag = reader[0] == "True"

flag будет Trueid reader [0] - True, в противном случае будет False.


10

В настоящее время выполняется оценка, Trueпоскольку переменная имеет значение. Здесь есть хороший пример того, что происходит, когда вы оцениваете произвольные типы как логические.

Короче говоря, вы хотите изолировать строку 'True'or 'False'и запустить evalее.

>>> eval('True')
True
>>> eval('False')
False

4
@samyi Использование метода eval опасно. stackoverflow.com/questions/1832940/…
M07

1
К вашему сведению. Это ужасная идея, и вам никогда не следует ее использовать eval(). На мой взгляд, его следует удалить с языка.
Nostalg.io

Это ОЧЕНЬ ПЛОХО, потому что это недостаток безопасности. Если вы используете eval()необработанные данные из файла, это означает, что любой, у кого есть доступ на запись к этому файлу, может выполнять код с тем же уровнем разрешений, что и ваш скрипт.
Кейт Рипли

Кроме того, если значения не имеют точного написания Python, например eval('false'), eval('FALSE')произойдет ошибка.
kev

5

Вы можете использовать dict для преобразования строки в логическое значение. Измените эту строку flag = bool(reader[0])на:

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

5

Если вы хотите не учитывать регистр, вы можете просто сделать:

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

Пример использования:

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


2

Можно обойтись json.

In [124]: import json

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

In [126]: json.loads('true')
Out[126]: True

2

Просто добавлю, что если ваше значение истины может варьироваться, например, если это ввод с разных языков программирования или разных типов, более надежным методом будет:

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

И более производительный вариант будет (набор поиска - O (1)):

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


0

Если вам нужен быстрый способ преобразовать строки в логические значения (которые работают с большинством строк), попробуйте.

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


0

Использование dicts для преобразования "True" в True:

def str_to_bool(s: str):
    status = {"True": True,
                "False": False}
    try:
        return status[s]
    except KeyError as e:
        #logging
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.