2011-08-16 6 views
13

Pisząc klasę niedawno, ja początkowo obejmowała __repr__ metodę wzdłuż następujących linii:Zawiera sformatowaną iterable jako część większego sformatowany ciąg

return "{}({!r}, {!r}, {!r})".format(
       self.__class__.__name__, 
       self.arg1, 
       self.arg2, 
       self.arg3) 

powtarzając „{R!}” Snippet tak czuje źle i byłoby to nużące do utrzymania, gdybym kiedykolwiek dodał więcej argumentów do tej klasy. Jednak bardziej zdecydowane alternatywy, które mi się przydały, również nie wygrają żadnych nagród za elegancję.

Budowanie ciąg formatu programowo:

fmt = "{}(%s)" % ", ".join(["{!r}"]*3) 
return fmt.format(self.__class__.__name__, 
        self.arg1, 
        self.arg2, 
        self.arg3) 

Formatowanie argumenty oddzielnie str.join:

args = ", ".join(map(repr, [self.arg1, self.arg2, self.arg3])) 
return "{}({})".format(self.__class__.__name__, args) 

Mam aktualnie realizowane klasę używając ostatni przykład, ale jestem zainteresowany sugestie dla alternatywnych podejść (ponieważ nie jestem szczególnie zadowolony z żadnej z powyższych opcji).

Aktualizacja: Zainspirowany odpowiedź Neda, mam teraz dodaje następującą funkcję użytkową do modułu pomocniczego:

def format_iter(iterable, fmt='{!r}', sep=', '): 
    return sep.join(fmt.format(x) for x in iterable) 

>>> format_iter(range(10)) 
'0, 1, 2, 3, 4, 5, 6, 7, 8, 9' 
>>> format_iter(range(10), sep='|') 
'0|1|2|3|4|5|6|7|8|9' 
>>> format_iter(range(10), fmt='{:04b}', sep='|') 
'0000|0001|0010|0011|0100|0101|0110|0111|1000|1001' 
>>> format_iter(range(10), fmt='{0.real}+{0.imag}j') 
'0+0j, 1+0j, 2+0j, 3+0j, 4+0j, 5+0j, 6+0j, 7+0j, 8+0j, 9+0j' 

Update2: skończyło się na dodanie drugiego funkcję użytkową, prawie identyczne z odpowiedzią agf:

def call_repr(name, *args): 
    return "{}({})".format(name, format_iter(args)) 

Tak więc pierwotnie obrażająca funkcja __repr__ teraz wygląda:

def __repr__(self): 
    return call_repr(self.__class__.__name__, 
        self.arg1, 
        self.arg2) 

(Tak, jeden z pierwszych argumentów konstruktora odszedł wcześniej dzisiaj.)

Odpowiedz

8

Jeśli jest to wzór masz zamiar powtórzyć, prawdopodobnie używać:

# This is a static method or module-level function 
def argrepr(name, *args): 
    return '{}({})'.format(name, ', '.join(repr(arg) for arg in args)) 

def __repr__(self): 
    return argrepr(self.__name__, self.arg1, self.arg2, self.arg3) 

lub

# This is a static method or module-level function 
def argrepr(*args): 
    return '(' + ', '.join(repr(arg) for arg in args) + ')' 

def __repr__(self): 
    return repr(self.__name__) + argrepr(self.arg1, self.arg2, self.arg3) 
+0

Jak się okazało, skończyłem to robić, tylko z wywołaniem 'format_iter (args)' ' inline inv ocation z '' str.join'' – ncoghlan

8

Moja skłonność byłoby, jeśli nie podoba ci się kod, ukryć go w funkcji:

def repr_all(*args): 
    return ", ".join(repr(a) for a in args) 


def __repr__(self): 
    args = repr_all(self.arg1, self.arg2, self.arg3) 
    return "{}({})".format(self.__class__.__name__, args) 
+0

zaakceptowany, ponieważ to był bezpośrednią inspiracją do tego, co skończyło się robi (patrz Aktualizacja) – ncoghlan

+0

Cóż, była na chwilę akceptowaną odpowiedzią, dopóki moje rozwiązanie nie zmieniło się tak, aby wyglądało bardziej jak sugestia od agfa :) – ncoghlan

0

I może to nie podoba:

def __repr__(self): 
    return "{0}({1})".format(
     type(self).__name__, 
     ", ".join(repr(arg) for arg in (self.arg1, self.arg2, self.arg3))) 

lub:

_init_getter = operator.attrgetter('arg1', 'arg2', 'arg3') 
def __repr__(self): 
    return "{0}({1})".format(
     type(self).__name__, 
     ", ".join(repr(arg) for arg in self._init_getter(self))) 
Powiązane problemy