{"id":102,"date":"2009-06-12T09:27:00","date_gmt":"2009-06-12T09:27:00","guid":{"rendered":"https:\/\/knielsen-hq.org\/w\/?p=102"},"modified":"2021-09-01T11:29:00","modified_gmt":"2021-09-01T11:29:00","slug":"learning-python","status":"publish","type":"post","link":"https:\/\/knielsen-hq.org\/w\/learning-python\/","title":{"rendered":"Learning Python"},"content":{"rendered":"\n<p>Among other things, these past few months I have been working on setting up <a href=\"http:\/\/askmonty.org\/buildbot\/\">Buildbot<\/a>, including adding various <a href=\"http:\/\/github.com\/knielsen\/buildbot\/tree\/mtr-db\">enhancements and bug fixes<\/a> that are needed to properly build and test the MariaDB and MySQL code base.<\/p>\n\n\n\n<p>Since Buildbot is written in Python, this means I have also had to learn Python. I am an old-time Perl hacker, so this exercise feels a bit like living in enemy territory \ud83d\ude09<\/p>\n\n\n\n<p>Anyway, Python is often touted as a more &#8220;pretty&#8221; language. And in many ways it is. Still, it is not without its own gotchas. Think &#8220;scope rules&#8221;. Obviously someone haven&#8217;t been reading up on the subject before implementing things in Python, causing the language to behave stupidly (and certainly different from what one expects) in the following three cases that I hit during my Buildbot work.<\/p>\n\n\n\n<h2>First assignment is implicit scope declaration<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">    def foo():\n        s = 0\n        def inc():\n            s = s + 1\n        print s\n        inc()\n        print s\n<\/pre>\n\n\n\n<p>This results in this error:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UnboundLocalError: local variable 's' referenced before assignment\n<\/pre>\n\n\n\n<p>Why? Because assigning to `s&#8217; declares a <em>new<\/em> variable. Yep, that&#8217;s right, a nested scope can read the value of a variable in an outer scope, but it cannot assign it!<\/p>\n\n\n\n<p>This is the work-around:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    def foo():\n        s = { 'blarg': 0 }\n        def inc():\n            s['blarg'] = s['blarg'] + 1\n        print s['blarg']\n        inc()\n        print s['blarg']\n<\/pre>\n\n\n\n<p>Now the inner scope in <code>inc()<\/code> does not <em>assign<\/em> to the outer variable `s&#8217;. It merely reads the value, and updates the dictionary it contains. So now things work. Hm &#8230;<\/p>\n\n\n\n<h2>Class vs. instance members<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">    class Bar:\n        s = 0\n        def foo(self, x):\n            self.s += x\n            print self.s\n\n    a = Bar()\n    a.foo(5)\n    b = Bar()\n    b.foo(8)\n<\/pre>\n\n\n\n<p>So this example actually works as one would expect from first glance (it prints &#8220;5&#8221; then &#8220;8&#8221;). But then when I looked closer, I did not understand how it could work. That <code>s = 0<\/code> creates a <em>class<\/em> member, shared by all instances of the class. So how can each instance still get their own private copy, each correctly initialised to 0?<\/p>\n\n\n\n<p>Ah, the answer is another variant of assignment creating a new scope. Look at <code>self.s += x<\/code>. This statement first reads <code>s.self<\/code>, which provides the value of the <em>class<\/em> member. It then assigns the new value to <code>s.self<\/code>, but since this is assignment, it now refers to an <em>instance<\/em> member, so it creates a new instance member! I don&#8217;t know what those Python guys where thinking when they made <code>self.s<\/code> refer to two different variables in a single statement &#8230;<\/p>\n\n\n\n<p>So this means that while the above example works as expected, this very similar one does not:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    class Bar:\n        s = []\n        def foo(self, x):\n            self.s.append(x)\n            print self.s\n\n    a = Bar()\n    a.foo(5)\n    b = Bar()\n    b.foo(8)\n<\/pre>\n\n\n\n<p>The last statement prints <code>[5,8]<\/code> as <code>self.s<\/code> is now a class member shared among all instances.<\/p>\n\n\n\n<p>The work-around here is to initialise member variables in the constructor <code>__init__()<\/code>, not in the class declaration.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    class Bar:\n        def __init__(self):\n            self.s = []\n        def foo(self, x):\n            self.s.append(x)\n            print self.s\n\n    a = Bar()\n    a.foo(5)\n    b = Bar()\n    b.foo(8)\n<\/pre>\n\n\n\n<h2>Late-binding closure construction<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">    b = []\n    for i in range(10):\n        b.append(lambda x: i)\n\n    b[0](42)\n    b[3](42)\n<\/pre>\n\n\n\n<p>This outputs the <em>same<\/em> value &#8220;9&#8221; twice. All of the functions in the list return 9! Oops.<\/p>\n\n\n\n<p>The reason is apparently that the closure created by <code>(lambda ...)<\/code> does late binding of captured outer variables, meaning that it refers to the name, not to the value at the time of closure construction. This is unlike any other language I have ever seen that has lexical scoping, so quite confusing.<\/p>\n\n\n\n<p>I know of two work-arounds in this case, neither of them pretty.<\/p>\n\n\n\n<p>One is to use a dummy extra parameter with a default value:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    b = []\n    for i in range(10):\n        b.append(lambda x, dummy=i: dummy)\n\n    b[0](42)\n    b[3](42)\n<\/pre>\n\n\n\n<p>See, when the variable <code>i<\/code> appears in the default value of a parameter, it is bound early (so to the value of <code>i<\/code> is used, not the name), different from when the variable appears in the body of the lambda expression.<\/p>\n\n\n\n<p>The other work-around is to build and call an extra closure to force binding to the correct value:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    b = []\n    for i in range(10):\n        b.append( (lambda j: (lambda x: j)) (i) )\n\n    b[0](42)\n    b[3](42)\n<\/pre>\n\n\n\n<p>This time, passing the value of <code>i<\/code> to the outer lambda forces early binding, so we get the expected results.<\/p>\n\n\n\n<p>Something to be aware of for an old-time Perl hacker like me, used to using functional style when programming&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Among other things, these past few months I have been working on setting up Buildbot, including adding various enhancements and bug fixes that are needed to properly build and test the MariaDB and MySQL code base. Since Buildbot is written in Python, this means I have also had to learn Python. I am an old-time&hellip; <a class=\"more-link\" href=\"https:\/\/knielsen-hq.org\/w\/learning-python\/\">Continue reading <span class=\"screen-reader-text\">Learning Python<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[35,4,6,34],"_links":{"self":[{"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/posts\/102"}],"collection":[{"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/comments?post=102"}],"version-history":[{"count":1,"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/posts\/102\/revisions"}],"predecessor-version":[{"id":103,"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/posts\/102\/revisions\/103"}],"wp:attachment":[{"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/media?parent=102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/categories?post=102"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/knielsen-hq.org\/w\/wp-json\/wp\/v2\/tags?post=102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}