October 28, 2008Python's enigmatic selfThe old 'self' controversy is making another appearance, stirred up by Bruce Eckel's proposal to remove the requirement. Let's start with a quick summary of the controversy. In Python, you have to declare "self" as a first parameter of all your methods:
class Foo():
def baz(self, x):
pass
This is just a convention. The name "self" is not enforced by the compiler but it's necessary to declare it as the first parameter of your method or Python will consider your method to be a function.
Python programmers feel strangely strongly about this convention and most of them don't see this requirement as a problem (which is the reason why there is so much misunderstanding between both camps). Interestingly, both sides often seem to miss the main reason why this controversy exists in the first place. It is *not* about typing less characters, it is *not* about having to prefix fields with that name (most people are fine with typing "self.f = 42"). This is strictly about consistency, and James Watson summarized the problem very cleanly in his comment on Bruce Eckel's proposal: I think a lot of people are bothered by this because there is a disconnect between the number of arguments in the declaration and the number of arguments in the call.In short: the method 'baz' above is declared with two parameters in the class but you invoke it with only one. This problem goes beyond Python and OO philosophies: it's the violation of a fundamental concept that has been the foundation of programming languages going decades back: when you declare a function with n parameters, you should invoke it with n parameters (slight exception if some of these parameters are optional, but this aspect is not germane to the discussion). Guido took some time to explain why Bruce's proposal cannot work. This is not the first time that explicit self has been under attack, and Guido has defended his design many times over the years. I went over Guido's explanation several times and to be honest, my eyes glazed over. My take away is that the reasons for the current design seem to be pretty serious and they dive deep into Python's implementation. And that's mostly why I keep being bothered by explicit self: it seems to me it's a design that is dictated more by the implementation than by the will to make this part of the language intuitive and in line with the estalbished science of computer languages. C++, Java, C# and many other object-oriented languages support the concept of a self object available within the scope of the current method, and none of them require you to declare that parameter explicitly, so it can obviously be done. Arguing that it's cleaner to require that parameter for the sake of readability when the real reason seems to be a limitation in the implementation strikes me as a bit dishonest. To make matter worse (or better, if you're into that sort of thing), Python has been adding dynamic features over these past years (such as adding a method inside a class outside the declaration of that class) that pretty much mean that the explicit self will never go away. I'm not convinced that these dynamic features were worth closing the door on the possibility of ever resolving the explicit self controversy, but the damage is done, and at this point, it's pretty clear that Python will never lose its explicit self. Comments
arrrggghh...python is a terrible language - only perl sucks worse. I wrote enough python (actually jython) scripting servers to call myself an expert. Did it all OO and clean. Several months later i've already forgotten the language & its funky api. Its painful revisiting the code. JavaScript rocks compared to that mess - though Scala is appealing to me more and more. Posted by: xsonymathew at October 28, 2008 12:05 PMWell, with C#3 extensions methods you have frequently methods that take more parameters in the declaration than in their call. public string FirstLetter(this string theString) could be called like this string s = "toto"; Actually, the "this" modifier acts a lot like the self parameter in Python (a language I love BTW). Posted by: Yann Schwartz at October 28, 2008 12:22 PMIn previous sample, replace with public string FirstLetter(this string theString) don't try this particular method at home, it doesn't check for nulls and it is totally useless too. Posted by: Yann Schwartz at October 28, 2008 12:24 PMSorry for spamming, but the method SHOULD be static too. And it's syntaxic sugar to avoid calling the method from a static utility class. Very handy and general and a life saver when chaining calls. Posted by: Yann Schwartz at October 28, 2008 12:26 PMIt's simply a by product of the evolution of python. OOP was tacked on plain and simple. Period. It's not the end of the world. Look at GObject and other examples of this. No language is perfect. There are warts in Java, Python, C#, etc. The issue is, that python zealots don't ever acknowledge that fact. Not much different from republicans. As others mentioned, javascript, ruby, boo, groovy, and numerous other scripting-friendly languages have first class OOP support. I share your opinion: "explicit self" is redundant, not explicit, and not "pythonic" at all. But what makes me angry about it is trying to disguise implementation limitations as "by design". Posted by: Daniel Serodio at October 29, 2008 05:34 AMOnce upon a time I was a Python fan. Various pros and cons exist to the language, but I'd have to say that explicit 'self' is definitely one of the worst parts. Posted by: Tom at October 29, 2008 07:40 AMI do like the syntactic sugar suggested in a comment on Eckel's blog and mentioned again by Guido that: class Example(object): should behave just like: class Example(object): That would indeed make the call and the definition look the same. Would that be less warty? The problem I have with Eckel's proposal as it stands is that "def" would do different things in different circumstances. Right now it does the same thing wherever you use it, whether in a class, in another function or at global scope: it creates a new function and gives it a name in the local scope. It's the *class* that then creates bound methods when you access it. I fear you would be fixing a superficial inconsistency only to introduce a serious but non-obvious one. Posted by: Weeble at October 29, 2008 09:41 AMNimpy, I think you're thinking of Perl with your "OOP being tacked on, plain and simple" comment. Python was OOP (though multi paradigm) from the start. Explicit self was a conscious decision, it was actually borrowed from Modula-3 Posted by: Philip Jenvey at October 29, 2008 12:18 PMI'm constantly amazed by your ability to pontificate on languages with which you don't appear to have much real world experience. >>This problem goes beyond Python and OO >>philosophies: it's the violation of a >>fundamental concept that has been the >>foundation of programming languages going >>decades back: when you declare a function with >>n parameters, you should invoke it with n >>parameters (slight exception if some of these >>parameters are optional, but this aspect is not >>germane to the discussion). This "fundamental concept" you're discussing, for instance...aside from your "slight" exception (which isn't really slight, and in fact is completely germane to the discussion), is also broken by varargs, is it not? Maybe you should bring back those old nonsensical "dynamic languages can't be refactored" posts. Posted by: Brian at November 2, 2008 07:10 PMWhile we're at it, why don't we just fix the whitespace bug in Python, and the truncation bug on function definitions, and the other whitespace bug that uses ascii char 95 instead of 40 for some names? Posted by: Aaron at November 10, 2008 09:52 AMI totally agree with you, it's an unnecessary syntactic sugar, it's the same as passing the this reference to every Java method declaration. I think it causes more damages than benefits, mainly because of the confusion on the arguments' call. Posted by: Rafael Naufal at November 10, 2008 11:24 AM@Rafael, self is not passed explicitly into a function call. my_object.my_method() calls def my_method(self): ... In this sense, it is closer to C-Struct style of OOP. I use Python daily, and self can be very helpful in a dynamic language like Python, since the absence of variable declarations means that scope has to be explicitly specified. @Chui Tey I've understood your point of view, but I was talking about the possible misunderstanding quoted by James Watson. Btw, if you omit the self on the method declaration, Python considers it as a being static? Posted by: Rafael Naufal at November 11, 2008 01:23 PMI shared the author's view and wish the following syntax sugar be implemented in next release 2.x or 3.1. def self.foobar(): as an alternative of current: it just makes explicit that a method is nothing more than a fonction with a parameter referencing the object it's acting on what is so mind bending ?
Many people new to Python may be told that python is Objected-Oriented as others:C++, Java, C#, etc. foo.baz(x,y) is translated to: baz(foo, x,y) For those who insist baz(foo, x, y) is good, think about the string functions before python 2.0, when at that time string functions are global functions: now: "a String".replace("a", "b") //python 2.0 Think about why python made the above change? Isn't that to make python more Object-Oriented? If so, then isn't that the above change removed the first argument as a reference of object? like "self"? If python removed first object reference in functions, then why not try to remove the "self", in the first argument in class method? I bet there's some way to do that, such as compiler could automatically insert a self reference in class method's argument list under cover. But it's a pity that python 3000 did not even think about it at the beginning when Guido designed the 3000. Posted by: frasier at December 7, 2008 08:33 AMAs mentioned above this is similar to Modula-3 and Oberon; Oberon-2 added syntactic sugar for proper methods. Itīs just evolution (involution) of concepts and syntax. Very few pure languages have existed (lisp, Smalltalk ...): they have a very long life and inspire others, but most languages are mongrels . And, like dogs (mongrels), they are the most flexible though not the most beautiful. Like others my current favorite mongrel is Scala (objects and functions and values, but a mongrel anyway). I know this is far past the original posting, but: "when you declare a function with n parameters, you should invoke it with n parameters" This irregularity has been around a long time. (Whether it counts as a *good* idea is debatable - but dates as least into the 1980's.) Yes, it was a hack then - and not one I would promote - but strictly speaking this has been around a long time. Posted by: Preston L. Bannister at February 17, 2009 02:29 AMPost a comment
|