Python 3: urllib, csv reader и StringIO - почему разница? - PullRequest
2 голосов
/ 28 октября 2019

Эти два подхода дают разные результаты в Python 3.7.3:

res = urllib.request.urlopen(url, timeout=timeout)
content = res.read().decode('utf-8')
reader = csv.reader(StringIO(content))
lines = list(reader)

И

res = urllib.request.urlopen(url, timeout=timeout)
content = res.read().decode('utf-8')
reader = csv.reader(content)
lines = list(reader)

Первый дает мне то, что я хочу, список строк из CSVпоследний дает мне список, содержащий списки длиной 1 только из отдельных символов (каждый символ в тексте является собственным списком), поэтому:

Year,PID
2019,1
2018,2

И

Y
e
a
r,
P
i
d
(etc)

Чторазница?

Ответы [ 2 ]

3 голосов
/ 28 октября 2019

поток в памяти для ввода / вывода текста

Для строк StringIO можно использовать как файл, открытый в текстовом режиме

csv.reader обрабатывает StringIO(content) как открытый файл. И reader - это

объект чтения, который будет перебирать строки в данном файле csvfile

  • Так что lines = list(reader) вернет вам список строк вcontent

Во втором случае content имеет тип string.

  • Поэтому csv.reader(content) вернет итератор по строке.

И это , потому что :

csv.reader (csvfile, dialect = 'excel', ** fmtparams) csvfile может быть любым объектом, который поддерживает протокол итератораи возвращает строку каждый раз, когда вызывается ее следующий () метод

  • Именно поэтому lines = list(reader) возвращает список символов, поскольку он обрабатывает каждый символ в content как ряд.
2 голосов
/ 28 октября 2019

Просмотрите документацию для csv.reader:

Возвращает объект чтения, который будет повторяться по строкам в данном csvfile . csvfile может быть любым объектом, который поддерживает протокол итератора и возвращает строку каждый раз, когда вызывается его метод __next__() - подходят файловые объекты и объекты списка.

Если выВы не уверены, что такое «протокол итератора», он в основном эквивалентен тому, что происходит, когда вы перебираете какой-то объект в цикле for. Например, для list:

>>> l = [1, 2, 3]
>>> for item in l:
...     print(item)
1
2
3

То есть для list s протокол итератора реализован «очевидным» способом, который возвращает каждый элемент списка по порядку. Для строк:

>>> s = 'row,from,csv'
>>> for char in s:
...     print(char)
...
r
o
w
,
f
r
o
m
,
c
s
v

Для большинства «файловых» объектов, таких как StringIO, протокол итератора определен так, что каждый цикл возвращает одну строку текста (с завершающим символом новой строки):

>>> s = """\
... row,1
... row,2
... """
>>> b = StringIO(s)
>>> for line in b:
...     print(line)
...
row,1

row,2

Таким образом, в последнем случае он обрабатывает простую строку как последовательность "строк" одного символа из CSV.

...