Найти - Пользователи
Полная версия: Объясните новичку про open()
Начало » Python для новичков » Объясните новичку про open()
1
steelunicorn
Объясните простым русским в чем разница в двух подходах к чтению файла.
Первый:
 		
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]
Результат они дают одинаковый, но я нигде не нашел будет ли автоматически закрываться файл после чтения во втором варианте.

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

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

3. 2й вариант интереснее не просто компактностью, но и тем, что он, требует вдвое меньше памяти, т.к. практически не загружает промежуточный буфер (в 1м варианте предварительное чтение всего файла в массив d, а массивы вроде как более тяжелые, чем кортежи).
Rodegast
Первый “подход” не правильный, там список d не нужен совсем. Во втором подходе аналогичная ошибка, в место
  [x.split('\t') for x in open(filepath, 'r')] 
должно быть
  ( x.split('\t') for x in open(filepath, 'r') )

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

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

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

См. то что я написал выше + в место списков возвращай генератор, замени вложенные списки кортежами.
steelunicorn
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?
Rodegast
Попробуй так:
 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 )
steelunicorn

Rodegast
Попробуй так:
Работает, супер!
Вставил удаление файла в конце - удаляется за милую душу, значит open() все-таки закрывает файл.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB