2012-12-13 9 views
12
>>> 'string with no string formatting markers' % ['string'] 
'string with no string formatting markers' 
>>> 'string with no string formatting markers' % ('string',) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: not all arguments converted during string formatting 

Oczekuję obu przypadków podniesienia TypeError, ale tak nie jest. Dlaczego nie?Dlaczego użycie listy jako parametru formatowania ciągu, nawet bez identyfikatora% s, zwraca oryginalny ciąg znaków?

W tym przedmiocie Python documentation mówi się o łańcuchach, krotkach i słownikach, ale nie mówi nic o listach. Jestem nieco zdezorientowany tym zachowaniem. Udało mi się go powielić w Pythonie 2.7 i 3.2.

+1

Wygląda mi na nieudokumentowaną "cechę" (błąd). – mgilson

+0

FWIW, 'jython2.2.1' * robi * podnosi' TypeError' – mgilson

Odpowiedz

6

Czytając uważnie, dokumentacja stwierdza, że:

Jeśli Format wymaga jednego argumentu, wartości mogą być pojedynczym nie- tuple przedmiot. W przeciwnym razie wartości muszą być tuple o dokładnie takim numerze elementów określonych przez ciąg formatu lub pojedynczy obiekt odwzorowania (na przykład słownik).

Teraz, w tym przypadku format nie wymaga jednego argumentu, a tym samym dokumentacja mówi nam, że należy użyć tuple lub mapowanie jako argumentu; inne przypadki należą do "niezdefiniowanego zachowania" (co się dzieje: zachowanie nie jest spójne we wszystkich przypadkach).

Prawdopodobnie powinno to być uznane za ostateczną odpowiedź na pytanie: jeśli ciąg nie ma żadnego specyfikatora formatu, użycie go jako list (lub innego rodzaju niż tuple lub odwzorowanie) powinno być po prostu uważane za błąd sam w sobie prowadzący do niezdefiniowane zachowanie.

Z tego wynika, że ​​powinieneś zawsze użyć tuple lub dict jako argumentu, w przeciwnym razie trzeba sprawdzić dla formatu specyfikatorami obsługiwać ręcznie lub zachowań nieparzyste.

W twoim przypadku prawdopodobnie możesz rozwiązać problem, używając (['string'],) zamiast ['string'].


Possible „wyjaśnienie” dlaczego wypadkowa zachowanie wydaje się być tak przypadkowy:

Wydaje się, że nie było buggy check w oryginalnym realizacji PyString_Format/PyUnicode_Format, zamiast korzystania PyMappingCheck na this linii :

if (PyMapping_Check(args) && !PyTuple_Check(args) && 
    !PyObject_TypeCheck(args, &PyBaseString_Type)) 
    dict = args; 

został użyty ten kod:

if (Py_TYPE(args)->tp_as_mapping && !PyTuple_Check(args) && 
    !PyObject_TypeCheck(args, &PyBaseString_Type)) 
    dict = args; 

który nie jest równoważny. Na przykład set nie ma zestawu tp_as_mapping (przynajmniej w kodzie źródłowym Python2.7.3, który pobrałem kilka tygodni temu), podczas gdy list ustawia to.

Może to być powodem list (i ewentualnie inne obiekty) nie podnieść TypeError chwilę, set, int i wiele inni.

Jak stwierdzono wcześniej w tej samej odpowiedzi robię dostać TypeError nawet list s:

$ python2 
Python 2.7.3 (default, Sep 26 2012, 21:53:58) 
[GCC 4.7.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> 'some string' % [] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: not all arguments converted during string formatting 

To chyba pokazuje, że powyższy problem nie jest jedynym tutaj.

Patrząc na kod źródłowy Zgadzam się, że teoretycznie liczba argumentów nie jest zaznaczone, jeśli argument nie jest krotka, ale to oznaczałoby 'some string' % 5 -> 'some string' a nie TypeError, więc to musi być coś podejrzanego w ten kod.

+2

Jaką wersję python 2 próbujesz? Nie mogę tego odtworzyć w wersjach 2.5.4, 2.6.1 lub 2.7.2. – geoffspear

+0

To interesujące, że podnosi on "TypeError" dla ciebie w Pythonie 2? Nie dla mnie: 'Python 2.7.3 (domyślnie, 1 sierpnia 2012, 05:14:39) [GCC 4.6.3] na linux2 Wpisz" help "," copyright "," credits "lub "licencja" po więcej informacji. >>> 'jakiś ciąg'% ['a'] 'jakiś ciąg'' –

+1

Nie dostaję 'TypeError', który pokazujesz (i od pytania, nie sądzę, że OP jest albo) tj. '" foobar "% ['kaczka']' szczęśliwie zwraca '" foobar "'. Używam Python2.7.3, 2.6.4, 3.2.3 na OS-X 10.5.8 ... Nie ma błędu w Pythonie2.7.3, 2.6.5, 3.2.0 na Ubuntu – mgilson

Powiązane problemy