Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 24, 2015 15:41:49

Kon52
Зарегистрирован: 2015-01-31
Сообщения: 66
Репутация: +  3  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

Есть функция:

def qwe(lst, new = []):
    for el in lst:
        qwe(el) if isinstance(el, list) else new.append(el)
    return new
При таком раскладе получаю:
a = qwe([1, [2, 3, [4, 5]]])
print a
[1, 2, 3, 4, 5]
НО:
def qwe(lst):
    new = []
    for el in lst:
        qwe(el) if isinstance(el, list) else new.append(el)
    return new
a = qwe([1, [2, 3, [4, 5]]])
print a
[1]
НО:
def qwe(lst):
    global new
    new = []
    for el in lst:
        qwe(el) if isinstance(el, list) else new.append(el)
    return new
a = qwe([1, [2, 3, [4, 5]]])
print a
[4, 5]

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

Офлайн

#2 Окт. 24, 2015 17:22:17

ayb
Зарегистрирован: 2014-04-01
Сообщения: 297
Репутация: +  24  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

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

Офлайн

#3 Окт. 24, 2015 19:45:52

Kon52
Зарегистрирован: 2015-01-31
Сообщения: 66
Репутация: +  3  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

В последнем варианте, значит, каждый раз создаётся новая глобальная переменная new, поэтому в ней и остаются значения с последнего шага цикла.
Вроде разобрался, спасибо.

Офлайн

#4 Окт. 24, 2015 20:01:42

ayb
Зарегистрирован: 2014-04-01
Сообщения: 297
Репутация: +  24  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

Ну вот смотрите :

>>> import inspect
>>> def some_func(a, b=[]):
...     b.append(a)
...     return b
... 
>>> inspect.getargspec(some_func)
ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=([],))

Вроде бы все ок, теперь вызовем функцию 2 раза
>>> some_func(1)
[1]
>>> some_func(2)
[1, 2]
>>> inspect.getargspec(some_func)
ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=([1, 2],))
>>> 

Т.е. в рантайме объект функции сохраняет свои параметры по умолчанию, и если вы внутри функции их меняете, каждый новый вызов будет происходить с измененными параметрами.

По второму примеру :

1. Внутри функции вы объявляете пустой список.
2. На первом шаге цикла for в этот список записывается значение 1.
3. На следующем шаге цикла срабатывает условие, функция начинает рекурсивно вызывать саму себя. При этом она возвращает значения, но Вы их никуда не записываете.
4. Функция заканчивает рекурсивно вызывать саму себя и возвращает список, который вы объявили в самом начале, и там только 1 элемент.

Ну а по третьему примеру все верно - функция каждый раз перезаписывает глобальную переменную.

PS : вообще объявлять функцию вот так функцию как у Вас в первом примере очень херовая практика.

Отредактировано ayb (Окт. 24, 2015 20:03:17)

Офлайн

#5 Окт. 24, 2015 20:19:06

Kon52
Зарегистрирован: 2015-01-31
Сообщения: 66
Репутация: +  3  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

Очень подробно,но не стоило, я после первого ответа врубился.
Ещё раз благодарю


ayb
PS : вообще объявлять функцию вот так функцию как у Вас в первом примере очень херовая практика.
Если честно, это найдено было в сети, а в чем именно её херовость?

Офлайн

#6 Окт. 24, 2015 20:51:29

ayb
Зарегистрирован: 2014-04-01
Сообщения: 297
Репутация: +  24  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

Kon52
Если честно, это найдено было в сети, а в чем именно её херовость?

Почитайте

Офлайн

#7 Окт. 24, 2015 22:44:12

Kon52
Зарегистрирован: 2015-01-31
Сообщения: 66
Репутация: +  3  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

Ну там как бэ не написано, что такая практика херова.
Там написано “важное предупреждение” и далее про то, что с изменяемыми объектами функция будет вести себя вот так.
Далее мысль о том, что уж если вам не нужно такое поведение, можете сделать по- другому(передать None).
То есть, по сути, просто описание без оценочных суждений.

Просто мне кажется, что чел, писавший эту функцию, понимал что он делает и для чего..

Офлайн

#8 Окт. 24, 2015 23:23:12

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

Я вот вижу global в коде и его принципиально не использую. И мне как-бы серенево, понимает его создатель, зачем нужен global или нет

P.S. Хотите писать код, который не будут заворачивать техлид или тимлид - не используйте такие конструкции. Ну и global в том числе.

Офлайн

#9 Окт. 25, 2015 00:02:14

Kon52
Зарегистрирован: 2015-01-31
Сообщения: 66
Репутация: +  3  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

4kpt_III
P.S. Хотите писать код, который не будут заворачивать техлид или тимлид - не используйте такие конструкции. Ну и global в том числе.
Так мы с ayb и не global обсуждали вовсе..Про её использование я в курсе, это так, эксперимент был
Мы первый пример разбирали, в частности- использование изменяемых объектов как аргументов по умолчанию. Он сказал, что так, мол, нельзя делать, я вот и не понял, почему нельзя- то?

Офлайн

#10 Окт. 25, 2015 00:16:33

Stright
От: Кострома
Зарегистрирован: 2015-01-20
Сообщения: 139
Репутация: +  16  -
Профиль   Отправить e-mail  

Список произвольной вложенности.

Когда-то примерно то же самое спрашивал

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version