2012-07-12 20 views
6

Jest to mniej więcej ten sam problem, co w przypadku this question about floats.Formatowanie ciągów z "{0: d}" nie konwertuje na liczbę całkowitą

Gdy masz wartość, która może zostać przekonwertowana na liczbę całkowitą, stara %d dokona konwersji, ale format nie.

class MyIntegerTenClass: 
    def __int__(self): 
     return 10 
    def __str__(self): 
     return 'ten' 
ten = MyIntegerTenClass() 
print '%d, %02X, %s' % (ten, ten, ten) # ok 
print '{0}'.format(ten) # ok 
print '{0:d}, {0:02X}'.format(ten) # ValueError: Unknown format code 'd' for object of type 'str' 

Czy istnieje sposób, aby zmodyfikować zachowanie formatu, bez dotykania klasę wartości mają być sformatowane (bez dodawania metody __format__ do tej klasy)?

Edytuj: Moim celem jest, aby formatowanie było zależne od łańcucha formatu, ale nie od wartości. Więc jeśli ciąg formatu mówi "d" lub "x", przekonwertuj wartość na int, a następnie na reprezentację dziesiętną lub szesnastkową. Jeśli ciąg formatu mówi "s", przekonwertuj go bezpośrednio na ciąg. Tak jak zrobił to stary %.

Właściwie mógłbym dodać metodę do klasy wartości. Ale jak sprawdzić w tej metodzie, czy podana specyfikacja formatu jest specyfikacją formatu liczb całkowitych? Bez ponownego wdrażania parsera specyfikacji formatu wbudowanego formatu.

Edytuj: Oto rozwiązanie z __format__ i wyjątkami. Jakieś lepsze pomysły?

class MyIntegerTenClass: 
    def __int__(self): 
     return 10 
    def __str__(self): 
     return 'ten' 
    def __format__(self, spec): 
     fmt = '{0:%s}'%spec 
     try: 
      return fmt.format(str(self)) 
     except: 
      return fmt.format(int(self)) 
ten = MyIntegerTenClass() 
print '%d, %02X, %s' % (ten, ten, ten) # ok, prints "10, 0A, ten" 
print '{0:d}, {0:02X}, {0}'.format(ten) # ok, prints "10, 0A, ten" 
+1

Mówi, że dziesięć jest ciągiem, próbujesz sformatować go jako liczbę. –

Odpowiedz

0

Pierwsze podejście do tego problemu może być po prostu try go:

class MyIntegerTenClass: 
    def __int__(self): 
     return 10 
    def __str__(self): 
     return 'ten' 
    def __format__(self, format_spec): 
     try: 
      s = format(str(self), format_spec) 
     except ValueError: 
      s = format(int(self), format_spec) 
     return s 

Jeśli MyIntegerTenClassmoże być wstawiony do tekstu formatu jako ciąg znaków, będzie. Jeśli nie, zostanie przekonwertowany na int i ponownie przesłany do format.

>>> print '{0}, {0:s}, {0:d}, {0:02X}, {0:f}'.format(ten) 
ten, ten, 10, 0A, 10.000000 

Jeśli chcesz domyślną reprezentacją być 10 zamiast ten, trzeba tylko zamienić wiersze konwersji: wyjście

def __format__(self, format_spec): 
     try: 
      s = format(int(self), format_spec) 
     except ValueError: 
      s = format(str(self), format_spec) 
     return s 

testu:

>>> print '{0}, {0:s}, {0:d}, {0:02X}, {0:f}'.format(ten) 
10, ten, 10, 0A, 10.000000 

jako dodatek, ja nie wierz, że będziesz w stanie uzyskać pożądane zachowanie bez definiowania __format__; można jednak opracować bardziej wyrafinowane podejście przy użyciu obiektu Formatter. Mimo to, myślę, że podejście oparte na wyjątkach daje wiele wbudowanych funkcji za darmo.

+0

Dzięki. Wygląda na to, że mamy to samo rozwiązanie mniej więcej w tym samym czasie (patrz moja druga edycja). Chociaż twoje rozwiązanie wydaje się być nieco przyjemniejsze, ponieważ nie wymaga "% 0:% s" specyfikacji. Nie zdawałem sobie sprawy, że istnieje funkcja formatu, którą możesz wywołać w ten sposób. – Sebastian

1

Podaj liczbę całkowitą zamiast ciągu, a wszystko będzie działać poprawnie.

>>> print '{0:d}'.format(1) 
1 
>>> print '{0:d}'.format('1') 

Traceback (most recent call last): 
    File "<pyshell#57>", line 1, in <module> 
    print '{0:d}'.format('1') 
ValueError: Unknown format code 'd' for object of type 'str' 
+2

Wiedziałem o tym. Ale nie chcę przekazywać liczby całkowitej. Chcę przekazać obiekt mojej klasy, który można przekonwertować na liczbę całkowitą. – Sebastian

0

Mówi, że dziesięć to ciąg znaków, próbujesz sformatować go jako liczbę.

Spróbuj owijając ją w gipsie:

>>> print '{0:d}, {0:02X}'.format(int(ten)) 
10, 0A 
+0

Nie działa w moim przypadku użycia.Nie chcę zmieniać wartości nadanej formatowi. – Sebastian

Powiązane problemy