Python 2, nonlocal and immutable variables
Нудний вступ я опущу, і перейду зразу до розваги:
def case(func): # декоратор прикладу print func.__name__ # печатаємо назву try: func() # виконуємо функцію except Exception, e: # Якщо є помилки print 'Error:', e # помічаємо і продовжуємо print @case def test_a(): x = 1 def inner(): x = 2 # x в цій області імен посилається на новий об’єкт - 2 print 'inner:', x # x == 2 inner() print 'outer:', x # x == 1. Цю область імен ми не чіпали @case def test_b(): x = [1] def inner(): x[0] = 2 # при обчисленні x[0], ми шукаємо x у всіх просторах тут і вище print 'inner:', x # x == [2], x посилається на все той же об’єкт, але він змінився inner() print 'outer:', x # x == [2], сказано ж, об’єкт змінився. @case def test_c(): x = 1 def inner(): x +=1 # генерує UnboundLocalError # бо x - в лівій частині присвоєння, що робить його локальним. # а в правій частині - x + 1, значення якого ще не визначено # бо ж x щойно з’явився в просторі імен # детальніше про те чому так: http://eli.thegreenplace.net/2011/05/15/understanding-unboundlocalerror-in-python/ print 'inner:', x inner() print 'outer:', x # сюди ми не доходимо # Як реалізувати нелокальну змінну, якщо ви працюємо не з третім Python? @case def test_d(): # використати mutable об’єкт nonlocal = lambda:7 # функція підходить nonlocal.x = 1 def inner(): nonlocal.x += 1 print 'inner:', nonlocal.x # == 2 inner() print 'outer:', nonlocal.x # == 2
Мораль теж опущу, все таки потрібно працювати. 😉
Хм.. я бы моделировал замыкания передачей доп. параметров функции inner
Хотя подозреваю, что это не самое лучшее решение.
jtimv
30 Травня, 2012 at 14:55
Але я напевне даремно опустив мораль всіх експериментів: заміна об’єкта на який посилається дане ім’я веде за собою перетворення імені на локальне відносто поточного простору імен.Якщо вам потрібно змінювати якесь значення ззовні – слідкуйте за тим щоб об’єкт за ним не замінювався новим. Це можливо тільки коли він mutable..
А передача параметра впринципі працює аналогічно, значення повернеться назад тільки якщо воно всередині mutable об’єкта. Інакше – створиться нова локальна версія, невидима ззовні.
bunyk
30 Травня, 2012 at 15:07
Точно. Практически полная аналогия с передачей параметра.
[trollmode ]Я даже не знаю, но наверное это хорошо, что я не на Python программирую 😉 [/trollmode]
jtimv
30 Травня, 2012 at 15:44
В кожній мові потрібно знати деякі речі аби випадково не накодити якусь х*ню. З тих з якими я знайомий. (Хаскель туди не входить). 🙂
Але головне – добре що не на Python 2.
bunyk
30 Травня, 2012 at 17:43
Треш. А чому кругом уточнення “Python 2”? Для третього там щось інше?
danbst
31 Травня, 2012 at 06:56
В третьому є ключове слово
nonlocal
, яке працює так само якglobal
, алеglobal
шукає тільки в глобальному просторі імен:В той час як
nonlocal
просто каже що змінну просто потрібно шукати десь вище:bunyk
31 Травня, 2012 at 10:53