Уведомления

Группа в Telegram: @pythonsu

#1 Июнь 7, 2018 12:08:36

steelunicorn
Зарегистрирован: 2018-06-06
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Объясните новичку про open()

Объясните простым русским в чем разница в двух подходах к чтению файла.
Первый:

 		
f = []
d = []
with open(filepath, 'r') as file:
	for line in file:
		d.append(line.split('\t'))
	for r in d:
		if len(r)==33:
			f.append([r[0], r[2], r[6], r[12], r[19], r[10]])
del d

Второй:
 f = [[r[0], r[2], r[6], r[12], r[19], r[10]] for r in [x.split('\t') for x in open(filepath, 'r')] if len(r) == 33]
Результат они дают одинаковый, но я нигде не нашел будет ли автоматически закрываться файл после чтения во втором варианте.

И еще вопрос, если файл попадается большой, скрипт может сожрать до гига памяти, можно ли как-то ограничить это аппетиты?

Отредактировано steelunicorn (Июнь 7, 2018 14:12:32)

Офлайн

#2 Июнь 9, 2018 01:43:48

NiOl
Зарегистрирован: 2018-05-07
Сообщения: 19
Репутация: +  1  -
Профиль   Отправить e-mail  

Объясните новичку про open()

1. Во втором варианте скорее всего автоматом файл не закроется. Проверить легко - добавить close и если будет ошибка, значит выборка сама закрыла файл.

2. В обоих случаях идет анализ файла как текстового с выборкой по строкам. Проблема возникнет только в случае очень длинной строки. Кажется ограничение строки 4GB, нужно посмотреть внимательнее описание. Но такое врят-ли случиться, хотя гарантию никто не даст )))

3. 2й вариант интереснее не просто компактностью, но и тем, что он, требует вдвое меньше памяти, т.к. практически не загружает промежуточный буфер (в 1м варианте предварительное чтение всего файла в массив d, а массивы вроде как более тяжелые, чем кортежи).

Офлайн

#3 Июнь 9, 2018 10:53:30

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2843
Репутация: +  186  -
Профиль   Отправить e-mail  

Объясните новичку про open()

Первый “подход” не правильный, там список d не нужен совсем. Во втором подходе аналогичная ошибка, в место

  [x.split('\t') for x in open(filepath, 'r')] 
должно быть
  ( x.split('\t') for x in open(filepath, 'r') )

> я нигде не нашел будет ли автоматически закрываться файл после чтения во втором варианте.

Сборщик мусора должен его закрыть, но делать это он не обязан.

> если файл попадается большой, скрипт может сожрать до гига памяти, можно ли как-то ограничить это аппетиты?

См. то что я написал выше + в место списков возвращай генератор, замени вложенные списки кортежами.



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#4 Июнь 9, 2018 18:50:20

steelunicorn
Зарегистрирован: 2018-06-06
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Объясните новичку про open()

Rodegast
См. то что я написал выше + в место списков возвращай генератор, замени вложенные списки кортежами.
Кортежами заменил, возвращаю генератор, но столкнулся с проблемой. Изначально код был слегка сложнее, а именно
 d = [[r[2], r[3], r[8], r[7], r[29], r[10]] for r in [x.split('\t') for x in open(filepath, 'r')] if len(r) == 40] or [[r[0], r[2], r[6], r[12], r[19], r[10]] for r in [x.split('\t') for x in open(filepath, 'r')] if len(r) == 33]
поскольку файл может приходить в двух вариантах и нужные столбцы меняют свое положение. Тут все было хорошо, в зависимости от того какой файл пришел, один из списков был пустой и по or в d присваивался полный список.

Сделал
 d = ((r[2], r[3], r[8], r[7], r[29], r[10]) for r in (x.split('\t') for x in open(filepath, 'r')) if len(r) == 40) or ([r[0], r[2], r[6], r[12], r[19], r[10]] for r in (x.split('\t') for x in open(filepath, 'r')) if len(r) == 33)
но с генераторами or не работает, потому что в любом случае возвращается объект генератора, даже если он пустой.

Как вариант я могу присваивать их двум разным переменным, и дважды вызывать executemany() сначала с одним потом с другим. Но может есть вариант сложить генераторы, что-то типа union в sql?

Офлайн

#5 Июнь 9, 2018 19:38:55

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2843
Репутация: +  186  -
Профиль   Отправить e-mail  

Объясните новичку про open()

Попробуй так:

 d = ( (r[2], r[3], r[8], r[7], r[29], r[10]) if len(r) == 40 else ([r[0], r[2], r[6], r[12], r[19], r[10]) for r in ( x.split('\t') for x in open(filepath, 'r') ) if len(r) == 40 or len(r) == 33 )



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#6 Июнь 13, 2018 12:09:17

steelunicorn
Зарегистрирован: 2018-06-06
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Объясните новичку про open()


Rodegast
Попробуй так:
Работает, супер!
Вставил удаление файла в конце - удаляется за милую душу, значит open() все-таки закрывает файл.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version