Ответ 1
Хорошо, у вас есть в общей сложности 4 вопроса, давайте пойдем один за другим.
1. Почему
str(list)
возвращает, как мы видимlist
на консоли? Как работаетstr(list)
?
Что такое str()
и __str__()
str()
, подлежащий вызову, заключается в том, чтобы вернуть только печатную форму объекта! Из docs
str(object)
не всегда пытается вернуть строку, которая приемлемо дляeval()
; его цель - вернуть печатную строку.
Функция __str__()
в классе вызывается всякий раз, когда вы вызываете str()
на объект. Опять из документация
object.__str__(self)
Вызывается встроенной функцией
str()
и оператором
Что такое list
вызываемый?
list()
вызываемый - это создать список из итеративного переданного в качестве аргумента. Снова из docs
Верните a
list
, элементы которого совпадают и находятся в том же порядке, что и пункты iterable
Таким образом, str(list)
предоставляет вам печатную форму и list(str(list))
будет перебирать строку. Это list(str(list))
даст вам список отдельных символов печатаемой формы переданного аргумента.
Небольшое прохождение между вложенными вызовами,
Данный список, l = ['a','b']
(Извинения за использование меньшего примера, чем в вашем вопросе).
Когда вы вызываете str(l)
, он возвращает печатную форму списка l
, то есть "['a','b']"
.
Теперь вы можете ясно видеть, что "['a','b']"
является строкой и действительно является итерируемой. Теперь, когда вы вызываете list
на этом i.e. list("['a','b']")
, вы получаете странный список, например ['[', "'", 'a', "'", ',', "'", 'b', "'", ']']
. Почему это происходит? Это происходит потому, что строка итерации над ее символами, вы можете проверить это, используя фиктивную строку,
>>> 'dummy'
'dummy'
>>> list('dummy')
['d', 'u', 'm', 'm', 'y']
Таким образом, когда вы вызываете list
в строке, вы получаете список символов. Обратите внимание, что снова здесь, когда вы вызываете str()
на list('dummy')
, вы не вернете исходную строку 'dummy'
, так что вам снова придется использовать join
! Таким образом, для вызова той же функции будет НЕ вернуть исходный объект!
Итак, вызов str()
по списку вызывает встроенный метод __str__()
списка?
Ответ НЕТ!
Что происходит внутри, когда вы вызываете str()
в списке?
Всякий раз, когда вы вызываете str()
в объекте списка, следующие шаги:
- Вызвать
repr()
каждого из элементов списка. - Добавьте fancy
[
спереди и еще один]
в конец списка. - Соедините их с запятой.
Как вы можете видеть из исходного кода объекта списка в cpython on github. Переход через источник код cpython в hg.python, что более понятно, вы можете увидеть следующие три комментария. (Спасибо Ashwini за ссылку на этот код)
/* Do repr() on each element. Note that this may mutate the list, so must refetch the list size on each iteration. */ line (382) /* Add "[]" decorations to the first and last items. */ line (398) /* Paste them all together with ", " between. */ line (418)
Они соответствуют точкам, упомянутым выше.
Теперь что такое repr()
?
repr()
выводит строковое представление всех объектов. Снова из документация
Возвращает строку, содержащую печатаемое представление объекта.
а также обратите внимание на это предложение!
Для многих типов эта функция пытается вернуть строку что даст объект с тем же значением, если он передан на
eval()
, иначе представление представляет собой строку, заключенную в угловые скобки который содержит имя типа объекта вместе с Дополнительная информация часто включает имя и адрес объект.
И теперь ваш второй вопрос здесь,
2. Почему
list(str(list))
не возвращаетstr(list)
в исходный список?
Внутри str(list)
фактически создает представление repr()
объекта списка. Поэтому, чтобы вернуть список после вызова str
в списке, вам действительно нужно сделать eval
, а не list
вызов.
Обходные
Но мы все знаем, что eval
является злым, так что это/является обходным путем (-ами)?
1. Используя literal_eval
Первым обходом будет использование ast.literal_eval
. Это подводит нас к вашему третьему вопросу,
3. Является ли
literal_eval()
тем же, что иeval()
? Безопасен лиeval()
?
ast.literal_eval()
является безопасным в отличие от eval()
функция. В самих документах говорится, что это безопасно -
Безопасно оценить выражение node или строку, содержащую литеральный или контейнерный дисплей Python
2. Использование строковых функций и встроенных функций
Еще одно решение может быть выполнено с помощью str.split()
>>> x = ['abc', 'def', 'ghi']
>>> a = str(x)
>>> a[2:-2].split("', '")
['abc', 'def', 'ghi']
Это простой способ сделать это для списка строк. Для списка целых чисел вам понадобится map
.
>>> x = [1,2,3]
>>> a =str(x)
>>> list(map(int,a[1:-1].split(', '))) # No need for list call in Py2
[1, 2, 3]
Таким образом, в отличие от literal_eval
, это простые хаки, учитывая, что вы знаете элементы списка. Если они являются гетерогенными по своему характеру, например [1, "a", True]
, вам придется перебирать список разделов и обнаруживать тип элемента, а затем преобразовывать его и добавлять преобразованный элемент в конечный список.
Другое место, где это не удается, - это когда сама строка содержит символы кавычек. Как упоминалось nneonneo в comment
Решение
str.split
очень хрупкое и будет ломаться, если вход содержит, например. строки, содержащие", "
, или кортежи, или другие списки... Лучше использоватьast.literal_eval
, потому что это будет касаться всех тонкостей синтаксиса.
И для вашего последнего вопроса,
4. Разрыв кода, если вы делаете
str(list(str(list))))
снова и снова?
Не совсем. Выход будет увеличиваться дольше и дольше, как каждый раз, когда вы создаете list
для str
, а затем снова получаете версию для печати. Ограничение ограничено только вашим физическим ограничением. (который скоро будет достигнут как каждый шаг, длина строки будет умножена на 5.)