2017-04-18 43 views
9

Czy istnieje zwięzły sposób formatowania liczby, która może być również ciągiem znaków?wartość formatu, która może być liczbą i/lub łańcuchem w pytonie 3

Liczba normalnie będzie liczbą zmiennoprzecinkową, ale czasami jest również oznaczana jako ciąg "n/a".

Chciałbym sformatować zmienną ze stałą liczbą miejsc po przecinku, ale wydrukować cały ciąg na wypadek, gdyby nie był liczbą.

Na przykład:

var=3.145623 
print("This is {0:.2f}".format(var)) 

>>>This is 3.14 

, ale

var = "n/a" 
print("This is {0:.2f}".format(var)) 

>>> File "<stdin>", line 1, in <module> 
>>> ValueError: Unknown format code 'f' for object of type 'str' 

Nie jestem zaskoczony ValueError, ale zastanawiam się, czy jest tam zwięzły sposób wokół niego, najlepiej bez wyraźnego IF-oświadczenie.

+0

Wydaje się, że za pomocą wyraźnego 'if-else' jest najprostsza droga ... To jest problem pojawi się, gdy mamy do czynienia z mieszane typy i dlaczego powinieneś tego unikać, jeśli to możliwe. –

+0

@ juanpa.arrivillaga: Właśnie dlatego, że przegapiłem zmianę w .format() lub czymś - wydaje mi się, że to byłby problem, który często pojawia się u ludzi, a więc może już coś jest wbudowane ... – Gerhard

+0

Czy mogę zapytać, dlaczego jest możliwe, że otrzymasz albo 'float' lub ciąg' 'n/a" '? Wygląda na to, że to prawdziwy problem. –

Odpowiedz

4

Python obsługuje nie-liczbę jako float('nan') i może być bardziej przydatny niż ciąg "n/a" w kodzie. Działa z formatowaniem i daje bardziej rozsądne wyniki niż ciąg znaków, jeśli użyjesz go w obliczeniach.

NaN:

>>> n = float('nan') 
>>> n 
nan 
>>> "{0:.2f}".format(n) 
'nan' 
>>> n == 3 
False 
>>> n * 2 
nan 
>>> n < 5 
False 

String:

>>> n = 'n/a' 
>>> "{0:.2f}".format(n) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: Unknown format code 'f' for object of type 'str' 
>>> n == 3 
False 
>>> n * 2 
'n/an/a' 
>>> n < 5 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unorderable types: str() < int() 
+0

Na tym właśnie skończyłem - konwertując wartość "n/a" na "nan". – Gerhard

6

Rzeczywiście, specyfikator formatu f działa tylko na rzeczywistych wartościach float. Nie można uniknąć sytuacji, w której trzeba zachować szczególną wartość dla swojej wartości n/a.

można formatować pływaka oddzielnie i warunkowo, następnie interpolować wynik do większej formy:

var_formatted = format(var, '.2f') if var != 'n/a' else var 
print("This is {0:4}".format(var_formatted)) 

Jeśli jesteś naprawdę przeciwny if, można użyć wyjątek obchodzenia też:

try: 
    var_formatted = format(var, '.2f') 
except ValueError: 
    var_formatted = 'n/a' 
print("This is {0:4}".format(var_formatted)) 

Inną opcją jest zawinięcie wartości w klasie za pomocą metody __format__:

class OptionalFloat(object): 
    def __init__(self, value): 
     self.value = value 
    def __format__(self, fmt): 
     try: 
      return self.value.__format__(fmt) 
     except ValueError: 
      return self.value 

print("This is {0:.2f}".format(OptionalFloat(var))) 

Ten przesuwa wymóg wykrywania typu do innej metody klasy, zachowując swój kod wyjściowy trochę czystsze i wolne od tych wszystkich brzydkie warunkowych lub ładowarki wyjątek:

>>> var = 3.145623 
>>> print("This is {0:.2f}".format(OptionalFloat(var))) 
This is 3.15 
>>> var = 'n/a' 
>>> print("This is {0:.2f}".format(OptionalFloat(var))) 
This is n/a 
1

może coś takiego

str = "{0:.2f}".format(var) if isinstance(var, float) else var 
print(str)