2013-05-08 3 views
0

рассмотрите следующие функции;ленивая оценка в генераторе

def myfunc(): 
    a=b=c=0 
    x='12' 
    a,b,c=(i for i in x) 
    return a,b,c 

Эта функция генерирует исключение из следующего: ValueError: для распаковки требуется более двух значений. Мое намерение здесь состоит в том, чтобы присвоить доступные значения в переменной «x» переменным с левой стороны в заданном порядке. Таким образом, a = 1, b = 2, c = 3, что я хотел бы сделать.

Для того, чтобы улучшить свое понимание о генераторах, я разобрал функция

>>> dis.dis(myfunc) 
    2   0 LOAD_CONST    1 (0) 
       3 DUP_TOP    
       4 STORE_FAST    0 (a) 
       7 DUP_TOP    
       8 STORE_FAST    1 (b) 
      11 STORE_FAST    2 (c) 

    3   14 LOAD_CONST    2 ('12') 
      17 STORE_FAST    3 (x) 

    4   20 LOAD_CONST    3 (<code object <genexpr> at 0x297b430, file "<stdin>", line 4>) 
      23 MAKE_FUNCTION   0 
      26 LOAD_FAST    3 (x) 
      29 GET_ITER    
      30 CALL_FUNCTION   1 
      33 UNPACK_SEQUENCE   3 
      36 STORE_FAST    0 (a) 
      39 STORE_FAST    1 (b) 
      42 STORE_FAST    2 (c) 

    5   45 LOAD_FAST    0 (a) 
      48 LOAD_FAST    1 (b) 
      51 LOAD_FAST    2 (c) 
      54 BUILD_TUPLE    3 
      57 RETURN_VALUE 

Что я предполагаю, что это UNPACK_SEQUENCE бросает исключение. Возможно ли сделать STORE_FAST до UNPACK_SEQUENCE? Надеюсь, что мой вопрос имеет смысл.

+2

'x = '12'' не'' 123'' и нет, правая сторона всегда оценивается в первую очередь – jamylak

ответ

2

Вы назначаете три различные переменные, используя распаковку. Распаковка имеет, чтобы перебирать правую последовательность, чтобы сделать это.

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

Это не проблема с генераторами. Это ограничение для кортежа заданий, explicitly documented:

  • If the target list is a comma-separated list of targets: The object must be an iterable with the same number of items as there are targets in the target list, and the items are assigned, from left to right, to the corresponding targets.

Та же ошибка будет выброшен при использовании списка:

a, b, c = list(x) 

бросает то же исключение, если x не длина 3, например x = '123'

Вы можете назначить выражение генератора в один переменные:

>>> x = '12' 
>>> a = (i for i in x) 
>>> a 
<generator object <genexpr> at 0x105046dc0> 

Если вы ожидали c оставаться установлены 0 потому что генератор не обеспечивает достаточное количество значений, то это не так, как Работает кортеж.

Вы можете использовать вспомогательную функцию со значениями по умолчанию для этого:

def helper(a=0, b=0, c=0): 
    return a, b, c 

a, b, c = helper(*(i for i in x)) 

Демо:

>>> def helper(a=0, b=0, c=0): 
...  return a, b, c 
... 
>>> a, b, c = helper(*(i for i in x)) 
>>> a, b, c 
('1', '2', 0) 

Вспомогательная функция использует значения по умолчанию для всех параметров, и синтаксис в случае * вызова использует генератор для рассматривайте их как позиционные параметры.

+0

Я понял, есть ли способ предоставить распакованный и фактически назначить переменную? – sardok

+2

@sardok: Что вы ожидаете от назначения здесь? Вы можете назначить генератору только одно имя ** с левой стороны, но что должно быть назначено двум другим именам? –

+0

Я вижу, спасибо за разъяснения.Я понял, что я ищу ответ на что-то вроде a, b, c = 1,2 с сохранением значения c, но назначение a и b выглядит как невозможно. – sardok

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