LINUX.ORG.RU

Не понимаю эти ваши замыкания в Go

 , , ,


0

2

Читаю урок по анонимным функциям:


Преимуществом анонимных функций является то, что они имеют доступ к окружению, в котором они определяются. Здесь функция square определяет локальную переменную x и возвращает анонимную функцию. Анонимная функция увеличивает значение переменной x и возвращает ее квадрат. Таким образом, мы можем зафиксировать у внешней функции square состояние в виде переменной x, которое будет изменяться в анонимной функции.


Хорошо, то есть, анонимная функция будет иметь какой-то хитрый доступ к переменной x, существующей в функции square(). Надо это проверить, и вызвать square() между вызовами анонимной функции.

И что можно увидеть?

Код:

package main
import "fmt"

func square() func() int {
	var x int = 2
	fmt.Println("X variable in square function ", x)

	return func() int {
		x++
		return x * x
	}
}

func main() {
	f := square()
	fmt.Println(f())
	fmt.Println(f())

	square() // <---------- Проверка

	fmt.Println(f())
	fmt.Println(f())
}

Результат:
X variable in square function  2
9
16
X variable in square function  2
25
36

Получается, что анонимная функция не работает с переменной x, размещенной в square(). Происходит какое-то копирование переменной, и потом работа идет с этой копией. То есть, реальность для переменной x «расщепляется»: Внутри square() у нее одно значение, а при вызове анонимной функции - другое.

Как это можно понять? Как это можно уложить в голове? Как этим можно пользоваться?

★★★★★

Последнее исправление: maxcom (всего исправлений: 1)

Видать я совсем старый стал.

3 раза перечитал вводную мессагу и не могу понять причем тут замыкание и видимость внутренней переменной снаружи функции ?

Замыкание это когда возвращаемая функция залазит в переменную и таким образом формирует замыкание.

mx__ ★★★★★
()
Последнее исправление: mx__ (всего исправлений: 1)
Ответ на: комментарий от static_lab

Пгастите, а што тут ваапще написано? Так-то в подобных случаях метод filter самописный, а именуется как переменная значение метода year(). Если же какой-то фреймворк для работы с данными или ORM, то обычно фильтры более очевидные. (как в том же pandas)

Shadow ★★★★★
()
Ответ на: комментарий от Xintrea

Это особенность Go? В плюсиках же есть список захвата.

В плюсиках при желании тоже можно утянуть весь контекст, [=](){} (с копированием) или [&](){} (по ссылке).

anonymous
()
Ответ на: комментарий от alysnix

это паттерн такой тащемта, а не «механизм». в пуктоне к нему специальный синтаксис даже сделали, что в общем-то необязательно, когда за счет перегрузки операторов можно любой объект сделать callable (чем в питоне активно пользуются даже в стандартной библиотеке, в частности якобы «функция» int на самом деле класс :)
в вебе это называется миддлварью еще

anonymous
()
Ответ на: комментарий от anonymous

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

зачем вот его спеуциальным образом вводить в язык

Вот, есть много-много функций, которые что-то успешно там считают и возвращают.

И вдруг стала необходимость результаты шифровать. Какие варианты? Навскидку:

  • продублировать код шифрования результата в определении каждой функции
  • написать обертку, найти вызовы этих функций и обернуть их в функцию шифрования
  • написать обертку и использовать её как декоратор - тело функций не меняется, вызов функций не меняется, а результат достигнут. Профит?
vvn_black ★★★★★
()
Ответ на: комментарий от alysnix

Во всех этих PEP и прочих пропозалах, от джавы до питона, приводятся рациональные соображения и обоснование, зачем эту НЁХ вводить в данный язычок. Наверное, если найти PEP на декораторы, то там будет подробно описано, «зачем».
Но в целом, как и очень многое в питоне это чисто практическое решение: на пратике это решение удобное и позволяет сократить бойлерплэйт, давайте его запилим в язык. В классах декораторы позволяют удобно описывать свойства (property), статические методы (staticmethod), методы класса (classmethod), и в общем и в целом со стороны глянешь – и правда удобно и органично, хотя казалось бы, минимальный «сахарок».
В питоне с фундаментальными вещами всё плоховато, разве что итераторы неплохи в целом, но как набор практических лайфхаков он крайне удачен.

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от vvn_black

написать обертку и использовать её как декоратор - тело функций не меняется, вызов функций не меняется, а результат достигнут. Профит?

если я правильно понимаю выгоды питонового декоратора… даже в сишечке вы можете подменить старую функцию funfun, просто переименовов ее в funfun__, и написав новую funfun c декорированием старой, которая теперь funfun__. и весь остальной код надо просто пересобрать по зависимостям.

void funfun(){
  lalala();
  funfun__(); /// <- это старая funfun
  trololo();
}
alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

А если у тебя этих функций ну прям достаточное количество, может быть это API какой или клиент? Мне кажется, что устанешь переименовывать. Или даже, вот продолжая мой пример, есть работающий код и надо его расширить, и при этом что-то из существующих интерфейсов надо расширять, а что-то нет, легко запутаться.

Т.е., было:

def funfun1(...):
    ...


def funfun2(...):
    ...

...


def funfunN(...):
    ...

а с декоратором будет как-то так:

def cypher(func):
    def wrapper():
        result = func()
        return encode(result)
    return wrapper


@cypher
def funfun1(...):
    ...


def funfun2(...):
    ...

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

vvn_black ★★★★★
()
Ответ на: комментарий от vvn_black

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

ничто так не запутывает программу, как «удобные ништяки» на всякий случай жизни

Спорить не буду, потому что второй пункт Zen of Python идёт лесом

Явное лучше, чем неявное

Но, всё дело привычки и выбранного инструмента.

vvn_black ★★★★★
()
Ответ на: комментарий от Xintrea

В плюсиках же есть список захвата

Он нужен т.к. в крестах есть ссылки. Поэтому замыкать можно по-разному: по значению, или по ссылке. По этой же причине список захвата есть в пыхе.

no-such-file ★★★★★
()
Ответ на: комментарий от alysnix

зачем вот его спеуциальным образом вводить в язык

Иначе придётся эту композицию функций вручную делать, и это будет а) многословно и уродливо б) у всех слегка по-разному.

Если бы недоязычки пыхоплеяды были лиспами, пункт а) решался бы с помощью макросов. И те, кому механизм middleware не нужен (ха-ха, да он вообще кругом, если приглядеться, не только в вебе), могли бы им не пользоваться и вообще ничего про него не знать.

Но увы. Поэтому остаётся только жрать что дают в том виде, в котором дают, и нахваливать.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 2)