2014-02-09 9 views
5

Nach einer Bemerkung hier: How to define a new string formatter, versuchte ich Unterklasse string.Formatter. Hier ist was ich getan habe. Leider scheinen ich es in der AsUnterklasse string.Formatter

import string 
from math import floor, log10 

class CustFormatter(string.Formatter): 
    "Defines special formatting" 
    def __init__(self): 
     super(CustFormatter, self).__init__() 

    def powerise10(self, x): 
     if x == 0: return 0, 0 
     Neg = x < 0 
     if Neg: x = -x 
     a = 1.0 * x/10**(floor(log10(x))) 
     b = int(floor(log10(x))) 
     if Neg: a = -a 
     return a, b 

    def eng(self, x): 
     a, b = self.powerise10(x) 
     if -3 < b < 3: return "%.4g" % x 
     a = a * 10**(b%3) 
     b = b - b%3 
     return "%.4g*10^%s" % (a, b) 

    def format_field(self, value, format_string): 
     # handle an invalid format 
     if format_string == "i": 
      return self.eng(value) 
     else: 
      return super(CustFormatter,self).format_field(value, format_string) 

fmt = CustFormatter() 
print('{}'.format(0.055412)) 
print(fmt.format("{0:i} ", 55654654231654)) 
print(fmt.format("{} ", 0.00254641)) 

Prozess gebrochen zu haben, wenn wie in der letzten Zeile, ich habe nicht auf die Variablen von Position beziehen, habe ich eine KeyError bekommen. Es erwartet natürlich einen Schlüssel, der in der ursprünglichen Klasse optional ist, aber ich verstehe nicht warum und ich bin mir nicht sicher, was ich falsch gemacht habe.

Antwort

4

str.formatdoes auto numbering, während string.Formatter nicht.

Ändern __init__ und überschreiben get_value wird den Trick tun.

def __init__(self): 
    super(CustFormatter, self).__init__() 
    self.last_number = 0 

def get_value(self, key, args, kwargs): 
    if key == '': 
     key = self.last_number 
     self.last_number += 1 
    return super(CustFormatter, self).get_value(key, args, kwargs) 

BTW, funktioniert obiger Code nicht streng Mimik str.format Verhalten. str.format beschwert sich, wenn wir automatische Nummerierung mit manueller Nummer mischen, aber oben nicht.

>>> '{} {1}'.format(1, 2) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: cannot switch from automatic field numbering to manual field specification 
>>> '{0} {}'.format(1, 2) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: cannot switch from manual field specification to automatic field numbering 
1

Gute Nachrichten: Sie haben nichts falsch gemacht. Schlechte Nachrichten: das ist, wie string.Formatter verhält, unterstützt es nicht {}-ähnliche Positionsformat. Der letzte Aufruf wird also auch ohne Unterklassen fehlschlagen. Eine gute Nachricht: Das kann durch Überschreiben der parse Verfahren festgelegt werden:

import string 

class CF(string.Formatter): 
    def parse(self, s): 
     position = 0 
     for lit, name, spec, conv in super(CF, self).parse(s): 
      if not name: 
       name = str(position) 
       position += 1 
      yield lit, name, spec, conv 

Schlechte Nachrichten ... Ah, nein, das ist es im Grunde:

>>> CF().format('{} {}!', 'Hello', 'world') 
'Hello world!' 
+0

Vielen Dank, wissen Sie, was sind die + und - overding parse oder get_value wie vom vorherigen Poster angeboten? Oder ist es gleichwertig? – Cambium

+0

@Cambium falsetrus Version sieht für mich lesbarer aus, außerdem müssen Sie eine Methode weniger überschreiben (obwohl Sie den Konstruktor überschreiben und ein Attribut einfügen müssen). Sein Lob über das Mischen der Stile gilt auch für meinen Code (obwohl Sie beide Versionen erweitern können, um das zu beheben). – bereal