Рассмотрим следующий фрагмент Python:
af=open("a",'r')
bf=open("b", 'w')
for i, line in enumerate(af):
if i < K:
bf.write(line)
Теперь предположим, что я хочу обработать случай, когда K
равно None
, поэтому запись продолжается до конца файла.В настоящее время я делаю
if K is None:
for i, line in enumerate(af):
bf.write(line)
else:
for i, line in enumerate(af):
bf.write(line)
if i==K:
break
Это явно не лучший способ справиться с этим, так как я дублирую код.Есть ли более интегрированный способ, которым я могу справиться с этим?Естественно было бы, чтобы код if/break
присутствовал только в том случае, если K
не None
, но это включает в себя написание синтаксиса на лету в виде макросов Лиспа, чего Python на самом деле не может сделать.Просто чтобы прояснить, меня не волнует конкретный случай (который я выбираю частично из-за его простоты), так же как и изучение общих приемов, с которыми я, возможно, не знаком.
ОБНОВЛЕНИЕ: После прочтения ответы людейопубликовал и провел больше экспериментов, вот еще несколько комментариев.
Как уже было сказано выше, я искал общие методы, которые можно было бы обобщить, и я думаю, что ответ Пола, а именно использование takewhile
из iterrools
подходит лучше всего.В качестве бонуса, он также намного быстрее, чем наивный метод, который я перечислил выше;Я не уверен почему.Я не очень знаком с itertools
, хотя я смотрел на него несколько раз.С моей точки зрения это случай функционального программирования для Win !(Забавно, что однажды автор itertools
попросил дать отзыв об отбрасывании takewhile
. См. Начало темы http://mail.python.org/pipermail/python-list/2007-December/522529.html.) Я упростил мою ситуацию выше, реальная ситуация немного более грязная - я пишук двум различным файлам в цикле. Таким образом, код выглядит примерно так:
for i, line in enumerate(af):
if i < K:
bf.write(line)
cf.write(line.split(',')[0].strip('"')+'\n')
Учитывая мой опубликованный пример, @Jeff разумно предположил, что в случае, когда K
было None
, я просто скопировалфайл. Так как на практике я все равно зацикливаюсь, сделать это не такой очевидный выбор. Однако takewhile
безболезненно обобщает этот случай. У меня также был другой вариант использования, который я здесь не упомянул, и смог использовать takewhile
там тоже, что было приятно. Второй пример выглядит так (дословно)
i=0
for line in takewhile(illuminacond, af):
line_split=line.split(',')
pid=line_split[1][0:3]
out = line_split[1] + ',' + line_split[2] + ',' + line_split[3][1] + line_split[3][3] + ',' \
+ line_split[15] + ',' + line_split[9] + ',' + line_split[10]
if pid!='cnv' and pid!='hCV' and pid!='cnv':
i = i+1
of.write(out.strip('"')+'\n')
tf.write(line)
здесь я смог использовать условие
if K is None:
illuminacond = lambda x: x.split(',')[0] != '[Controls]'
else:
illuminacond = lambda x: x.split(',')[0] != '[Controls]' and i < K
для @ исходного примера Пола. Однако яЯ не совсем доволен тем, что я получаю i
из внешней области видимости, хотя код работает. Есть ли лучший способ сделать это? Или, возможно, это должен быть отдельный вопрос. В любом случае, спасибовсем, кто ответил на мой вопрос.Похвальный отзыв @Jeff, который сделал несколько хороших предложений.