
{"id":4790,"date":"2020-11-24T00:20:29","date_gmt":"2020-11-24T05:20:29","guid":{"rendered":"https:\/\/ikriv.com\/blog\/?p=4790"},"modified":"2020-11-24T00:30:31","modified_gmt":"2020-11-24T05:30:31","slug":"equivalent-of-c-delegates-in-python","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=4790","title":{"rendered":"Equivalent of C# delegates in Python"},"content":{"rendered":"<p>Coming from C# background, I was trying to understand whether Python allows to pass <code>obj.method<\/code> where ordinary function is expected, and if yes, how could it possibly work.<\/p>\n<p>Consider this code fragment:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\ndef call_twice(f):\r\n    f()\r\n    f()\r\n\r\nclass Foo:\r\n    def __init__(self, data):\r\n        self.data = data\r\n    \r\n    def print_value(self):\r\n        print(f&quot;Value is {self.data}&quot;)\r\n\r\nfoo = Foo(42)\r\ncall_twice(foo.print_value)  # can it work? how?\r\n<\/pre>\n<p>The short answer is: yes, it works, <code>foo.print_value<\/code> returns an equivalent of C# delegate that knows about <code>foo<\/code> variable.<\/p>\n<h2>Longer answer<\/h2>\n<p>Unlike C++ and the languages influenced by it, methods definitions in Python accept &#8220;this&#8221; parameter explicitly. It is usually called &#8220;<code>self<\/code>&#8221; by convention, but in fact any name would work:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nclass Foo:\r\n  def print_value(this):\r\n     print(f&quot;Value is {this.data}&quot;)\r\n<\/pre>\n<p>It looks suspiciously like C, and in C passing a one-argument function to something that expects a zero-argument function would not work. So, how can we pass <code>foo.print_value<\/code> to <code>call_twice()<\/code> and then invoke it with no arguments?<\/p>\n<p>The answer is that while <code>Foo.print_value<\/code> is indeed an ordinary function that accepts one argument, <code>foo.print_value<\/code> is a callable object that accepts no arguments. When invoked, it calls <code>Foo.print_value(foo)<\/code>. This is very similar to how C# delegates work, and somewhat similar to C++ functional objects that define <code>operator ()<\/code>.<\/p>\n<p>In other words, <code>foo.print_value()<\/code> is not simply syntactic sugar for <code>Foo.print_value(foo)<\/code> as I originally thought. The expression <code>foo.print_value<\/code> returns an object of type <code>method<\/code>. This object can then be called immediately, or passed to another function to be called later.<\/p>\n<p>More details here: https:\/\/stackoverflow.com\/questions\/6685232\/how-are-methods-classmethod-and-staticmethod-implemented-in-python<\/p>\n<h2>Some Interesting Implications<\/h2>\n<p>Since methods are actually regular functions, they can be applied to arbitrary objects. Consider this code:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nclass Bar:\r\n    def run(self):\r\n        self.go(&quot;fast&quot;)\r\n\r\n    def go(self, msg):\r\n        print(f&quot;Bar.go({msg})&quot;)\r\n\r\nclass Bus:\r\n    def __init__(self, name):\r\n        self.name = name\r\n\r\n    def go(self, msg):\r\n        print(f&quot;{self.name} is going {msg}!&quot;)\r\n\r\nbus = Bus(&quot;Yellow bus&quot;)\r\nBar.run(bus)  # prints &quot;Yellow bus is going fast!&quot;\r\n<\/pre>\n<p>We apply <code>Bar.run()<\/code> to an object of type <code>Bus<\/code>, which is completely unrelated to <code>Bar<\/code>, and yet it invokes <code>Bus.go()<\/code> and prints the expected message. Of course, this feature should be used with care, but it does occasionally become useful, e.g. when we want to be 100% certain method of what class we are calling on an object in presence of multiple inheritance.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Coming from C# background, I was trying to understand whether Python allows to pass obj.method where ordinary function is expected, and if yes, how could it possibly work. Consider this <a href=\"https:\/\/ikriv.com\/blog\/?p=4790\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[4,26],"tags":[28],"class_list":["entry","author-ikriv","post-4790","post","type-post","status-publish","format-standard","category-hack","category-python","tag-python"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4790","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4790"}],"version-history":[{"count":7,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4790\/revisions"}],"predecessor-version":[{"id":4795,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4790\/revisions\/4795"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4790"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4790"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4790"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}