Konwertuj wartość Prawda / Fałsz odczytana z pliku na wartość logiczną

86

Odczytuję True - Falsewartość z pliku i muszę przekonwertować ją na wartość logiczną. Obecnie zawsze konwertuje ją na, Truenawet jeśli wartość jest ustawiona na False.

Oto, MWEco próbuję zrobić:

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.datPlik w zasadzie składa się z pojedynczego sznurka z wartością Truelub Falsepisemnej wewnątrz. Aranżacja wygląda na bardzo zawiłą, ponieważ jest to minimalny przykład ze znacznie większego kodu i tak właśnie wczytuję do niego parametry.

Dlaczego flagzawsze przechodzi na True?

Gabriel
źródło
1
pip install str2bool
Symon

Odpowiedzi:

100

bool('True')i bool('False')zawsze zwracają, Trueponieważ ciągi „True” i „False” nie są puste.

Cytując wspaniałego człowieka (i dokumentację Pythona ):

5.1. Testowanie wartości prawdy

Każdy obiekt może zostać przetestowany pod kątem wartości prawdy, do użycia w warunku if lub while lub jako operand poniższych operacji boolowskich. Następujące wartości są uważane za fałszywe:

  • zera każdego typu liczbowa, na przykład, 0, 0L, 0.0, 0j.
  • pustych kolejności, na przykład '', (), [].

Wszystkie inne wartości są uważane za prawdziwe - więc obiekty wielu typów są zawsze prawdziwe.

Funkcja wbudowana boolkorzysta ze standardowej procedury sprawdzania prawdy. Dlatego zawsze dostajesz True.

Aby przekonwertować ciąg na boolean, musisz zrobić coś takiego:

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
źródło
23
ValueErrorRobiąc to, możesz uczynić to „bohaterskim” raise ValueError("Cannot covert {} to a bool".format(s)).
SethMMorton,
Wybranie tego, ponieważ nie używa żadnych dodatkowych pakietów. Dzięki chłopaki!
Gabriel,
1
Co jest nie tak z „dodatkowymi pakietami”? Czy masz na myśli ast? Jest częścią standardowej biblioteki, więc nie jest tak naprawdę dodatkowa.
SethMMorton,
4
to może być głupie pytanie, ale dlaczego boolpo prostu nie konwertuje ciągów znaków Truei Falsena wartości logiczne Truei False? Wydaje się, że zachowanie jest niespójne w porównaniu z tym, co się intdzieje. Jestem po prostu naprawdę ciekawy, dlaczego moje rozumowanie jest błędne i dlaczego inna opcja była tą decyzją.
Charlie Parker
1
Zawsze, gdy porównuję ciągi znaków, lubię spłaszczyć obudowę (w stosownych przypadkach). na przykład użyłbym: if s.upper () == 'TRUE': return True elif s.upper () == 'FALSE' return False
Bill Kidd
75

możesz użyć distutils.util.strtobool

>>> from distutils.util import strtobool

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

Truewartości y, yes, t, true, oni 1; Falsewartości n, no, f, false, offi 0. Podnosi się, ValueErrorjeśli val jest czymś innym.

Francesco Nazzaro
źródło
22
Jeszcze lepiej, wykonaj bool(strtobool(my_string))rzutowanie wyjścia jako zmiennej typu boolean True / False
AlexG
10
@AlexG szalało, że wywołana funkcja strtobool()w rzeczywistości nie zwraca abool
dericke
61

Zastosowanie ast.literal_eval:

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

Dlaczego flaga jest zawsze konwertowana na True?

Niepuste łańcuchy są zawsze True w Pythonie.

Powiązane: Testowanie wartości prawdy


Jeśli NumPy jest opcją, to:

>>> 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
źródło
to może być głupie pytanie, ale dlaczego boolpo prostu nie konwertuje ciągów znaków Truei Falsena wartości logiczne Truei False? Wydaje się, że zachowanie jest niespójne w porównaniu z tym, co się intdzieje. Jestem po prostu naprawdę ciekawy, dlaczego moje rozumowanie jest błędne i dlaczego inna opcja była tą decyzją.
Charlie Parker
2
ast.literal_eval ('false') zgłasza wyjątek, co moim zdaniem czyni go mniej pożądanym
Chris,
@Chris Zawsze możesz owinąć to try-z wyjątkiem funkcji niestandardowej zamiast używać jej bezpośrednio.
Ashwini Chaudhary
@HewwoCraziness Przetwarza tylko wyrażenia, a nie losowy kod.
Ashwini Chaudhary
15

Najczystszym rozwiązaniem, jakie widziałem, jest:

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

Oczywiście, wymaga importu, ale ma odpowiednią obsługę błędów i wymaga bardzo niewielkiej ilości kodu do napisania (i przetestowania).

vpetersson
źródło
13

Nie sugeruję, że to najlepsza odpowiedź, tylko alternatywa, ale możesz też zrobić coś takiego:

flag = reader[0] == "True"

flaga będzie miała wartość TrueID czytnika [0] ma wartość „True”, w przeciwnym razie będzie False.

elParaguayo
źródło
10

Obecnie jest oceniany do, Trueponieważ zmienna ma wartość. Znajduje się tutaj dobry przykład tego, co się dzieje, gdy oceniasz dowolne typy jako wartości logiczne.

Krótko mówiąc, to, co chcesz zrobić, to wyizolować ciąg 'True'lub 'False'i uruchomić evalna nim.

>>> eval('True')
True
>>> eval('False')
False
Gautam Joshi
źródło
4
@samyi Używanie metody eval jest niebezpieczne. stackoverflow.com/questions/1832940/…
M07
1
FYI. To okropny pomysł i nigdy nie powinieneś go używać eval(). Moim zdaniem należy go usunąć z języka.
Nostalg.io
Jest to BARDZO BARDZO ZŁE, ponieważ jest to luka w zabezpieczeniach. Jeśli używasz eval()surowych danych z pliku, oznacza to, że każdy, kto ma prawo do zapisu w tym pliku, może wykonywać kod na tym samym poziomie uprawnień, co twój skrypt.
Keith Ripley
Dodatkowo, jeśli wartości nie mają dokładnej pisowni, np Pythona eval('false'), eval('FALSE')będzie to błąd.
kev
5

Możesz użyć dict, aby przekonwertować ciąg znaków na wartość logiczną. Zmień tę linię flag = bool(reader[0])na:

flag = {'True': True, 'False': False}.get(reader[0], False) # default is False
ndpu
źródło
5

Jeśli chcesz nie rozróżniać wielkości liter, możesz po prostu:

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

Przykładowe użycie:

>>> 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
źródło
3

pip zainstaluj str2bool

>>> from str2bool import str2bool
>>> str2bool('Yes')
True
>>> str2bool('FaLsE')
False
Symon
źródło
2

Możesz zrobić z json.

In [124]: import json

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

In [126]: json.loads('true')
Out[126]: True
Rahul KP
źródło
2

Wystarczy dodać, że jeśli wartość prawdy może się różnić, na przykład jeśli jest to dane wejściowe z różnych języków programowania lub z różnych typów, bardziej niezawodną metodą byłoby:

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

Bardziej wydajnym wariantem byłby (wyszukiwanie zestawu to O (1)):

TRUTHS = set(['True','true',1,'T','t','1'])
flag = value in truths
Daniel Dubovski
źródło
1

Jeśli Twoje dane pochodzą z json, możesz to zrobić

import json

json.loads („prawda”)

Prawdziwe

Ivan Camilito Ramirez Verdes
źródło
0

Jeśli potrzebujesz szybkiego sposobu na konwersję ciągów znaków na boole (które działają z większością łańcuchów), spróbuj.

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
źródło
0

Używanie dykt do konwersji „True” na True:

def str_to_bool(s: str):
    status = {"True": True,
                "False": False}
    try:
        return status[s]
    except KeyError as e:
        #logging
chris
źródło