UProLa

Неокріпші думки

Python. Multiline lambda

with 2 comments

Як це відомо, в Пітоні немає можливості створювати багаторядкові лямбда функції. Якщо потрібно щось складніше за lambda x: x*x, то Python-way рекомендує створити окрему нову функцію і викликати її лямбдою. Звісно, це абсолютно нормальна техніка, проте хотілось-би показати, що є як мінімум два способи зробити майже повноцінні анонімні методи (привіт, C#!).

Задача

Ну, покажу ідею на прикладі реальної ситуації. Моя програма аналізує текст і зустрівши кодове макрослово, робить відповідну макропідстановку. Проблема в тому, що макропідстановка робиться за допомогою лямбда-функції, тобто може бути не просто REPLACE, а якою завгодно складною функцією.

Макроси в моїй програмі додаються командою addMacro():

addMacro("SOMEMACRO", lambda x: do_macro_SOMEMACRO(x))

Згодом у коді для кожного SOMEMACRO викликається зв’язана з ним лямбда і їй передаються ті ж параметри, що і для SOMEMACRO

Python way

def replace_CODEWORD_macro(w, faddr, naddr):
	global MACROTEXT, lastCFA
	res = """	.db "{0}", {1}
				.dw {2}
	{3}:		.dw {4} 
	""".format(
				iif(len(w)%2 == 0," ", "") + toName(w), len(toName(w)),
				FUNCS["rammap"](lastCFA),
	naddr,		faddr
				)
	MACROTEXT += res
	lastCFA = naddr
	addCompiledWord(w, naddr)


addMacro("CODEWORD", replace_CODEWORD_macro)

В принципі, не варто намагатись зрозуміти, що код робить, основне завдання – показати, що функція не записується одним лямбда виразом, а отже доведеться плодити окремі функції для усіх таких макросів. Сам Великодушний і Безсердечний признав, що було би класно мати багаторядкові лямбди як частину Пітону, проте вони не вписуються у синтаксис або філософію.

Лямбда через eval

Нехитрий спосіб обходу даного обмеження )

addMacro("CODEWORD", lambda w, faddr, naddr: exec("""
	res = """+'"""'+"""	.db "{0}", {1}
				.dw {2}
	{3}:		.dw {4}
	"""+'""""'+""".format(
				iif(len(w)%2 == 0," ", "") + toName(w), len(toName(w)),
				FUNCS["rammap"](lastCFA),
	naddr,		faddr
				)
	exec("MACROTEXT += '{0}'".format(res),globals())
	exec("lastCFA = '{0}'".format(naddr),globals())
	addCompiledWord(w, naddr)
	""", locals()))

Одразу видно недоліки даного методу. По-перше, підсвітка коду у деяких редакторах перестає працювати, а подруге, спроба використати локальні і глобальні змінні у одному контексті перетворюється у exec()-кошмар. Не згадуючи уже про “лапки-fail”…

Prolog way

Для використання даного способу потрібно, щоб усі ваші функції (які використовуються у лямбда виразі) повертали True. Тоді з’явиться можливість конкатенації рядків за допомогою ключового слова and:

addMacro("CODEWORD", lambda w, faddr, naddr:                       True and
	pasteMacro("""
				.db "{0}", {1}
				.dw {2}
	{3}:		.dw {4}
	""".format(
				iif(len(w)%2 == 0," ", "") + toName(w), len(toName(w)),
				FUNCS["rammap"](lastCFA),
	naddr,		faddr
				), True, False)                                        and
	gEX("lastCFA = '{0}'".format(naddr))                               and
	addCompiledWord(w, naddr)
)

Видно, що зміна глобального MACROTEXT тепер перетворилась у функцію, exec(…, globals()) став gEX(), а у всіх інших функціях я вставив return True останнім рядком. Такий код нормально підсвічується у будь-якому редакторі, легко пишеться і навіть дозволяє НЕДОТРИМУВАТИСЬ табуляції!

Від автора

  • Не рекомендую намагатись запустити приведений код.
  • Синтаксис Пітон 3. Рекомендую всім переходити на Пітон 3.
  • Ця частина коду приведена з моєї бакалаврської – використання Пітона як макро-препроцесора асемблерного коду з AVR синтаксисом заради більш потужної кодогенерації у метапрограмній парадигмі програмування.
  • Written by danbst

    Травень 29, 2011 at 14:02

    Оприлюднено в Програмування

    Tagged with

    Відповідей: 2

    Subscribe to comments with RSS.

    1. Не зрозуміло лише нащо писати

      lambda w, faddr, naddr: replace_CODEWORD_macro(w, faddr, naddr)
      

      там де можна написати

      replace_CODEWORD_macro
      

      bunyk

      Травень 29, 2011 at 15:08


    Залишити відповідь

    Заповніть поля нижче або авторизуйтесь клікнувши по іконці

    Лого WordPress.com

    Ви коментуєте, використовуючи свій обліковий запис WordPress.com. Log Out / Змінити )

    Twitter picture

    Ви коментуєте, використовуючи свій обліковий запис Twitter. Log Out / Змінити )

    Facebook photo

    Ви коментуєте, використовуючи свій обліковий запис Facebook. Log Out / Змінити )

    Google+ photo

    Ви коментуєте, використовуючи свій обліковий запис Google+. Log Out / Змінити )

    З’єднання з %s

    %d блогерам подобається це: