2013-07-17 2 views
2

Рассмотрим следующий код:Как проверить, можно ли повторить повторный вызов?

def my_fun(an_iterable): 
    for val in an_iterable: 
    do_work(val) 
    if some_cond(val): 
     do_some_other_work(an_iterable) 
     break 

если an_iterable является list/tuple, do_some_other_work получите весь список снова. Но если an_iterable был iterator или generator, он получит только остальные элементы в списке. Как я могу различать два случая? Я хочу, чтобы do_some_other_work получил только остальные предметы.

+1

бы с помощью 'isinstance (объект, генератор) или hasattr (OBJ,«ряд»)' работы? Итераторы должны поддерживать 'next', а другие проверяют тип генератора. –

+0

Нет ли других типов стандартных объектов python, которые поддерживают только одно перемещение? Как функция генератора? – balki

+0

Вы _could_ используете 'tee' или более простую оболочку, которая позволяет вам заглянуть в один элемент без потребления, или тот, который позволяет вам возвращаться на итератор (по цепочке) или даже просто« list »в качестве обертки. Затем вы можете разрушить проверку, перезапускается ли итератор, и вы все равно не потеряли данные (потому что они находятся в обертке). Но это было бы глупо. – abarnert

ответ

3

Там нет никакого общего способа узнать, можно ли перебрать объект несколько раз , Файлоподобные объекты, в частности, скорее всего, испортят проверки. К счастью, вам не нужно это проверять. Если вы просто хотите, чтобы убедиться, что do_some_other_work только получает остальную часть пунктов, вы можете явно запросить итератор:

def my_fun(iterable): 
    iterable = iter(iterable) 
    # Do whatever. 
+0

Я согласен, что это похоже на/право/способ сделать это. Особенно с тем, насколько уродлива альтернатива. –

+0

Какой из них лучше или это просто вопрос вкуса? 'iterable = iter (iterable)' или 'iterable = (val for val in iterable)'? – balki

+2

@balki: 'iter' лучше, потому что он точно говорит о том, что он делает, без лишних отвлекающих факторов. Это также более кратким и быстрым, и работает в странных крайних случаях, когда вы заботитесь о разнице между фактическим итератором и новым итератором, который случается для повторения одних и тех же вещей. – abarnert

-1

Рассмотрим следующий фрагмент кода:

import types 

def which(obj): 
    if isinstance(obj, types.GeneratorType): 
     print 'Generator' 
    elif hasattr(obj, 'next') and (iter(obj) == obj): 
     print 'Iterator' 
    elif hasattr(obj, '__iter__'): 
     print 'Iterable' 
    else: 
     print 'Object' 

def my_gen(length): 
    for i in xrange(length): 
     yield i 

# Reports 'Generator' 
which(my_gen(10)) 
# Reports 'Iterable' 
which(iter(xrange(10))) 
# Reports 'Object' 
which([i for i in xrange(10)]) 

with open('foo.txt', 'w+') as fout: 
    for _ in xrange(10): 
     fout.write('hello\n') 

# Reports 'Iterable' 
with open('foo.txt') as fin: 
    which(fin) 

Это определяет их как «генератор», «Iterable», а затем «Object»

+0

Не работает с файлами. – user2357112

+1

Я не согласен. Он сообщает «итератору» для меня. –

+0

... huh. Файловые объекты являются их собственными итераторами. Я не понимал, что они приняли это решение. Я что-то узнал! – user2357112

Смежные вопросы