Posts tagged ‘closures’

Simulating nonlocal Keyword in Python 2.x

2013-08-04 15:30

The overall direction where Python 3 is going might be a bit worrying, but it’s undeniable that the 3.0 line has some really nice features and quality-of-life improvements. What’s not to love about Unicode string literals enabled by default? Or the print function? What about range, map and filter all being generators? Neato!

There are also few lesser known points. One is the new nonlocal keyword. It shares the syntax with the global keyword, which would make it instantaneously fishy just by this connotation. However, nonlocal looks genuinely useful: it allows to modify variables captured inside function’s closure:

  1. def count_parity(numbers):
  2.     even_count = odd_count = 0
  3.  
  4.     def examine(number):
  5.         if number % 2 == 0:
  6.             nonlocal even_count
  7.             even_count += 1
  8.         else:
  9.             nonlocal odd_count
  10.             odd_count += 1
  11.  
  12.     list(map(examine, numbers))
  13.     return even_count, odd_count

It’s something you would do quite a lot in certain other languages (*cough* JavaScript), so it’s good that Python has got around to support the notion as well. Syntax here is a bit clunky, true, but that’s simply a trade off, stemming directly from the lack of variable declarations in Python.

What about Python 2.x, though – are we out of luck? Well, not completely. There are a few ways to emulate nonlocal through other pythonic capabilities, sometimes even to better effect than the nonlocal keyword would yield.

Use generator instead

Speaking of yielding… As you have probably noticed right away, the example above is quite overblown and just plain silly. You don’t need to play functional just to count some values – you would use a loop instead:

  1. def count_parity(numbers):
  2.     even_count = odd_count = 0
  3.     for number in numbers:
  4.         if number % 2 == 0:
  5.             even_count += 1
  6.         else:
  7.             odd_count += 1
  8.      return even_count, odd_count

Really, the previous version is just a mindless application of the classic Visitor pattern, which is another reason why you shouldn’t do that: pattern overuse is bad. This saying, Visitor obviously has its place: it’s irreplaceable when traversing more complicated structures in more bureaucratic languages. A simple list of numbers in Python is the direct opposite of both of these characteristics.

Complex data structures exist in any language, however. How would we run some Python code for every node in a tree, or maybe graph? Unrolling the DFS or BFS or whatever traversal algorithm we use certainly doesn’t sound like an elegant and reusable approach.
But even then, there is still no need for functions and closures. We can easily get away with the simple for loop, if we just find a suitable iterable to loop over:

  1. def bst_count_parity(tree):
  2.     """Count the number of even and odd numbers in binary search tree."""
  3.     even_count = odd_count = 0
  4.     for node in bst_nodes(tree):
  5.         if node.value % 2 == 0:
  6.             even_count += 1
  7.         else:
  8.             odd_count += 1
  9.     return even_count, odd_count

The bst_nodes function above is not black magic by any stretch. It’s just a simple example of generator function, taking advantage of the powerful yield statement:

  1. def bst_nodes(tree):
  2.     """Yields nodes of binary tree in breadth-first order."""
  3.     queue = [tree]
  4.     while queue:
  5.         node = queue.popleft()
  6.         yield node
  7.         if node.left:
  8.             queue.append(node.left)
  9.         if node.right:
  10.             queue.append(node.right)

This works because both bst_count_parity and bst_nodes functions are executed “simultaneously”. That has the same practical effect as calling the visitor function to process a node, only the “function” is concealed as the body of for loop.

Language geeks (and Lisp fans) would say that we’ve exchanged a closure for continuation. There is probably a monad here somewhere, too.

Create reference where there is none

Generators can of course solve a lot of problems that we may want to address with nonlocal, but it’s true you cannot write them all off just by clever use of yield statement. For the those rare occasions – when you really, positively, truly need a mutable closure – there are still some options on the board.

The crucial observation is that while the closure in Python 2.x is indeed immutable – you cannot add new variables to it – the objects inside need not be. If you are normally able to change their state, you can do so through captured variables as well. After all, you are still just “reading” those variables; they do not change, even if the objects they point to do.

Hence the solution (or workaround, more accurately) is simple. You need to wrap your value inside a mutable object, and access it – both outside and inside the inner function – through that object only. There are few choices of suitable objects to use here, with lists and dictionaries being the simplest, built-in options:

  1. def incr(redis, key):
  2.     """Increments value of Redis key, as if Redis didn't have INCR command.
  3.    :return: New value for the key
  4.    """
  5.     res = []
  6.  
  7.     def txn(pipe):
  8.         res[0] = int(pipe.get(key)) + 1
  9.         pipe.multi()
  10.         pipe.set(key, res[0])
  11.  
  12.     redis.transaction(txn, key)
  13.     return res[0]

If you become fond of this technique, you may want to be more explicit and roll out your own wrapper. It might be something like a Var class with get and set methods, or just a value attribute.

Classy solution

Finally, there is a variant of the above approach that involves a class rather than function. It is strangely similar to “functor” objects from the old C++, back when it didn’t support proper lambdas and closures. Here it is:

  1. def incr(redis, key):
  2.     """Increments value of Redis key, as if Redis didn't have INCR command.
  3.    :return: New value for the key
  4.    """
  5.     class IncrTransaction(object):
  6.         def __call__(self, pipe):
  7.             self.result = int(pipe.get(key)) + 1
  8.             pipe.multi()
  9.             pipe.set(key, self.result)
  10.  
  11.     txn = IncrTransaction()
  12.     redis.transaction(txn, key)
  13.     return txn.result

Its main advantage (besides making it a bit clearer what’s going on) is the potential for extracting the class outside of the function – and thus reusing it. In the above example, you would just need to add the __init__(self, key) method to make the class independent from the enclosing function.

Ironically, though, that would also defeat the whole point: you don’t need a mutable closure if you don’t need a closure at all. Problem solved? ;-)

Tags: , , , ,
Author: Xion, posted under Programming » Comments Off on Simulating nonlocal Keyword in Python 2.x

The Subshell Gotcha

2013-05-20 13:13

Many are the quirks of shell scripting. Most are related to confusing syntax, but some come from certain surprising semantics of Bash as a language, as well as the way scripts are executed.
Consider, for example, that you’d like to list files that are within certain size range. This is something you cannot do with ls alone. And while there’s certainly some awk incantation that makes it trivial, let’s assume you’re a rare kind of scripter who actually likes their hacks readable:

  1. #!/bin/sh
  2.  
  3. min=$1
  4. max=$2
  5.  
  6. ls | while read filename; do
  7.     size=$(stat -f %z $filename)
  8.     if [ $size -gt $min ] && [ $size -lt $max ]; then
  9.         echo $filename
  10.     fi
  11. done

So you use an explicit while loop, obtain the file size using stat and compare it to given bounds using a straightforward if statement. Pretty simple code that shouldn’t cause any troubles later on… right?

But as your needs grow, you find that you also want to count how many files fall within your range, and how many do not. Given that you have an explicit if, it appears like a simple addition (in quite literal sense):

  1. matches=0
  2. misses=0
  3. ls | while read filename; do
  4.     size=$(stat -f %z $filename)
  5.     if [ $size -gt $min ] && [ $size -lt $max ]; then
  6.         echo $filename
  7.         ((matches++))
  8.     else
  9.         ((misses++))
  10.     fi
  11. done
  12.  
  13. echo >&2 "$matches matches"
  14. echo >&2 "$misses misses"

Why it doesn’t work, then? Because clearly this is not the output we’re looking for (ls_between is our script here):

  1. $ ls -al
  2. total 25296
  3. drwxrwxr-x  19 xion  staff       646 15 Apr 18:44 .
  4. drwxrwxr-x  15 xion  staff       510 20 May 11:15 ..
  5. -rw-rw-r--   1 xion  staff        16 10 May  2012 hello.py
  6. -rw-rw-r--   1 xion  staff      4005 28 May  2012 keyword_stats.py
  7. -rw-rw-r--   1 xion  staff       218  5 Aug  2012 magical.py
  8. -rw-rw-r--   1 xion  staff     19901 11 May  2012 space_invaders.py
  9. $ ls_between 1024 10241024
  10. keyword_stats.py
  11. space_invaders.py
  12. 0 matches
  13. 0 misses

It seems that neither matches nor misses are counted properly, even though it’s clear from the printed list that everything is fine with our if statement and loop. Wherein lies the problem?

Tags: , , , ,
Author: Xion, posted under Applications, Programming » 2 comments

C++11 est arrivé!

2011-08-20 1:38

O ile tylko ktoś nie spędził zeszłego tygodnia na Antarktydzie, w amazońskiej dżungli czy w innym podobnie odciętym od cywilizacji miejscu, z pewnością słyszał najważniejszą nowinę ostatnich lat. A już na pewno wspomnianego tygodnia – bo przecież jak tu ją nawet porównywać z takimi błahostkami jak choćby zakup Motoroli przez Google. Przecież mówimy tutaj o pomyślnym końcu procesu rozpoczętego w czasach, gdy Google nawet nie istniał! To musi robić wrażenie… I nawet jeśli owym wrażeniem jest głównie: “No wreszcie; co tak długo?!”, to przecież w niczym nie umniejsza to rangi wydarzenia.

Tak, mamy w końcu nowy standard C++! I to w sumie mogłoby wystarczyć za całą notkę, bo chyba wszystko, co można by powiedzieć na temat kolejnej wersji jednego z najważniejszych języków programowania, zostało już pewnie dawno powiedziane w dziesiątkach serwisów informacyjnych, tysiącach blogów i milionach tweetów. Znaczącą ich część zajmują omówienia nowych możliwości języka, dostępnych zresztą od jakiegoś czasu (acz w niepełnej formie) w kilku wiodących kompilatorach. Możliwości tych jest całkiem sporo i dlatego nie mam zamiaru nawet wyliczać ich wszystkich. Zdecydowałem, że w zamian przyjrzę się bliżej tylko trzem z nich – tym, które uważam za najbardziej znaczące i warte uwagi.

Prawie jak lambda, w Javie

2011-06-02 20:52

Wiadomo powszechnie, że Java listenerami stoi i typowe jest używanie jest różnego rodzaju klas wewnętrznych, które są następnie podawane jako interfejsy do wywołań zwrotnych. W ten sposób obsługuje się różnego rodzaju zdarzenia, począwszy od interakcji użytkownika z programem aż po ważne notyfikacje pochodzące z systemu operacyjnego.
Gdy klasa zawierające takie handlery dostatecznie się rozrośnie, pojawia się oczywiście potrzeba jej zrefaktorowania i podzielenia na dwie lub większą liczbę mniejszych. W trakcie tego procesu czasami chciałoby się też wydzielić owe klasy wewnętrzne, obsługujące zdarzenia – i wtedy możemy napotkać pewien kłopot. Kłopocik właściwie ;)

Dotyczy on zależności między klasami wewnętrznymi a klasą je otaczającą. Ponieważ mówimy o niestatycznych niestatycznych klasach wewnętrznych, typowe jest odwoływanie się do składników klasy otaczającej z klasy zewnętrznej. Mówiąc bardziej po ludzku, implementacja np. zdarzenia kliknięcia przycisku może sięgać do obiektu okna/dialogu/itp., zawierającego tenże przycisk:

  1. private final OnClickListener buttonsListener = new View.OnClickListener() {
  2.     @Override
  3.     public void onClick(View v) {
  4.         if (v.getId() == R.id.exit_button) finish();
  5.     }
  6. }

Przeniesienie całej powyższej klasy w inne miejsce nastręcza wówczas problem, gdyż odwołuje się ona do metody klasy ją otaczającej (czyli finish()). Należałoby więc posiadać obiekt tej klasy, zapewnić aby rzeczona metoda była dostępna (co nie zawsze jest wskazane), aby wywoływać ją z właściwymi parametrami – które też trzeba jakoś przekazać – i tak dalej… Krótko mówiąc na naszej drodze do ładnie zorganizowanego kodu naraz pojawia się sporo przeszkód.

Czy nie dałoby się po prostu jakoś przekazać tego “kawałka kodu”, tych kilku czy kilkunastu instrukcji opakowanych w coś, co można podać w inne miejsce programu?… Okazuje się, że jak najbardziej, a rozwiązaniem na problem refaktorowanych klas wewnętrznych jest… więcej klas wewnętrznych ;-) Nic nie stoi bowiem na przeszkodzie, aby rzeczony fragment procedury zdarzeniowej zapakować w metodę klasy implementującej interfejs Runnable. Tak, dokładnie ten interfejs który zazwyczaj kojarzy się z wątkami i klasą Thread. W rzeczywistości reprezentuje on “cokolwiek co da się uruchomić”, więc jak ulał pasuje w charakterze rozwiązania problemu.
Aplikując je do powyższego przykładu, możemy wydzielić powyższy listener (potencjalnie wraz z kilkunastoma podobnymi) i kazać mu jedynie wywoływać metodę run jakiegoś obiektu Runnable. W niej zaś umieszczamy nasz pierwotny kod i przekazujemy do nowo wydzielonej klasy:

  1. Buttons.setExitAction(new Runnable() {
  2.     @Override
  3.     public void run() { finish(); }
  4. }

Znawcy tematu powiedzieliby, że w ten sposób utworzyliśmy domknięcie (closure), bo w inne miejsce programu przekazaliśmy fragment kodu wraz z jego kontekstem; w tym przypadku jest to chociażby referencja this na rzecz której wywoływany jest finish. Fani programowania funkcyjnego stwierdzą z kolei, że ta technika jest kiepską imitacją wyrażeń lambda i najprawdopodobniej też będą mieli rację.
Nie zmienia to jednak faktu, że jeśli programujemy w starej (nie)dobrej Javie, to technika ta może być po prostu użyteczna – niezależnie od tego, jaki paradygmat za nią stoi. Dlatego też chciałem dzisiaj się nią podzielić.

Tags: , , , ,
Author: Xion, posted under Programming » 9 comments
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.