Преобразование значения 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)))

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

Vpetersson
источник
13

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

flag = reader[0] == "True"

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

elParaguayo
источник
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
Калеб
источник
3

pip install str2bool

>>> from str2bool import str2bool
>>> str2bool('Yes')
True
>>> str2bool('FaLsE')
False
Саймон
источник
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
Даниэль Дубовски
источник
1

Если ваши данные из json, вы можете сделать это

импортировать json

json.loads ('истина')

Правда

Иван Камилито Рамирес Вердес
источник
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

пользователь6830669
источник
0

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

def str_to_bool(s: str):
    status = {"True": True,
                "False": False}
    try:
        return status[s]
    except KeyError as e:
        #logging
Крис
источник