The Artima Developer Community
Sponsored Link

Weblogs Forum
Self in the Argument List: Redundant is not Explicit

43 replies on 3 pages. Most recent reply: Nov 30, 2011 2:26 AM by ilian zapryanov

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 43 replies on 3 pages [ 1 2 3 | » ]
Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Self in the Argument List: Redundant is not Explicit (View in Weblogs)
Posted: Sep 23, 2008 1:49 PM
Reply to this message Reply
Summary
The response to arguments about self in Python is "explicit is better than implicit." In a discussion at Pycon Brazil, I realized that we do need self in the body of a method, but being forced to place it in the argument list is redundant. I'm not actually expecting it to change, but I want to try to establish that this isn't a dumb argument.
Advertisement

self is necessary to distinguish between global variables/functions and those of the object, for example. It provides a scoping mechanism, and I personally find it clearer than Ruby's @ and @@, but I'm sure that's just because I'm used to it, probably because it's similar to this in C++ and Java.

Something has always bugged me about self, however, and I've blogged about it before -- I had hoped that it would have been rectified in Python 3 and this caused the usual furor which ends up by people saying "explicit is better than implicit."

In a conversation with Luciano Ramalho (president of the Brazilian Python group) while I was in Brazil, he made me realize that it wasn't self everywhere that has been bugging me, it's self in the argument list which I think could actually be called un-pythonic.

How it Works Now

Here's some simple Python code showing the use of classes:

def f(): pass
a = 1

class C1(object):
    a = 2
    def m1(self):
        print a # Prints '1'
        print self.a # Prints '2'
        f() # The global version
        self.m2() # Must scope other members

    def m2(self): pass

obj = C1()
obj.m1()

First, you see f() and the global a, so we have something to call at the global scope. The class C1 is defined by inheriting from object, which is the standard procedure for defining a new class (I think this might become implicit in Python 3).

Note that both m1() and m2() have a first argument of self. In Python, self is not a keyword, but the name "self" is conventionally used to represent the address of the current object. The address of the object is always the first argument.

The a that is defined at class scope represents one way to create object fields, but you can also just assign to self.a within a method, and the first time this happens the storage will be created for that field. However, the two versions of a must now be differentiated. If you just say a within a method, you'll get the global version, but self.a produces the object field (you can also assign to global variables from within classes, but I'll skip that for the current discussion).

Similarly, an unqualified call to f() produces the global function, and self.m2() calls the member function by qualifying it (and simultaneously passing the address of the current object to be used as the self argument for m2()).

Now let's look at a class with a method that has arguments:

class C2(object):
    def m2(self, a, b): pass

To call the method, we create an instance of the object and use the dot notation to call m2() on the object obj:

obj = C2()
obj.m2(1,2)

In the call, the address of obj is implicitly passed as self for the call to m2(), and here we see a big inconsistency: why is implicit better than explicit when you define the method, but it's OK to be implicit when you call the method?

I certainly think that the method call syntax is desireable, but it means that you define a method differently than you call it, which I don't see as either "explicit" or pythonic. This is seen when you call the method with the wrong number of arguments:

obj.m2(1)

Here's the resulting error:

Traceback (most recent call last):
  File "classes.py", line 9, in <module>
    obj.m2(1)
TypeError: m2() takes exactly 3 arguments (2 given)

Because of the implicit argument pass of self during a method call, the above error message is actually saying that it wants you to call the method this way:

C2.m2(obj,1,2)

Even though the above line does run, this of course isn't the way you actually do it; you use the normal method calling syntax and give it two arguments:

obj.m2(1,2)

The message m2() takes exactly 3 arguments (2 given) is not only confusing for beginners, but it confuses me every time I see it, which I think suggests non-Pythonicness and points out the inconsistency between method definition and method invocation.

The Hopeless Suggestion

So what am I suggesting, despite the long history of hopelessness for this idea?

Make self a keyword in Python 3.1 (what's a bit more backwards incompatibility, as long as we're at it?) (Or even use this to make it easier for C++ and Java programmers to transition). All the existing rules for self remain the same.

The only difference: you don't have to put self in a method argument list. That's the only place it becomes implicit; everywhere else it's explicit -- except, just as it is now, the method call.

This produces consistency between the method definition and the method call, so you define a method with the same number of arguments that you call it with. When you call a method with the wrong number of arguments, the error message tells you the actual number of arguments the method is expecting, instead of one more.

Explicit vs. Redundant

Before I hear "explicit is better than implicit" one more time, there's a difference between making something clear and making it redundant. We already have a language that forces you to jump through lots of hoops for reasons that must have seemed good at the time but have since worn thin: it's called Java.

If we just want to be explicit about absolutely everything, we can use C or assembler or some language that spells out exactly what's happening inside the machine all the time and doesn't abstract away from those details.

Forcing programmers to put self in the method argument list doesn't honor explicitness; it's just redundant forced behavior. It doesn't add to the expression of programming (we already know it's a method; we don't need self in the argument list to remind us), it's just mechanical, and thus, I argue, non-pythonic.


Dan Takk

Posts: 1
Nickname: dantakk
Registered: Sep, 2008

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 23, 2008 5:05 PM
Reply to this message Reply
I agree the error message is confusing but I think there are more details to be worked out. e.g With class methods, the first "self" argument is modified by a decorator that changes its semantics. So we usually change the name of the first argument to "cls", like:


class C(object):
@classmethod
def m(cls):
print type(cls)


I think reusing the self keyword in this context would be confusing.

Would improving the error message be a reasonable alternative?

Rodrigo Pimentel

Posts: 7
Nickname: rbp
Registered: Sep, 2008

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 23, 2008 5:50 PM
Reply to this message Reply
[These are just ramblings, I don't mind typing "self" so much, but I do think it's ugly and non-symmetrical).

I'm not sure how feasible that is, but I'd suggest making "self" a implicit kwarg ("implicit" here means mirroring the was it's implicit in the call). So these two methods would be equivalent:


class C(object):
def m1(arg1, arg2): pass
def m2(arg1, arg2, self=self): pass


Thus, every method gets a "self" kwarg automatically, and you could plug a function into a class or an object, to me used as a method, by having it accept a "self" kwarg. No need to make self a keyword per se.

Dan, maybe the decorator could define a "cls" variable as receiving self? Since we'd be sticking with the word "self", we might as well stick with "cls".

This would also work when passing an instance explicitly:

SomeClass.method(arg1, arg1, self=some_object)

BTW, Bruce, in py3k all classes are "new style", meaning you don't need to explicitly inherit from "object" (meaning your class automatically will).

-- rbp

Attila Vágvölgyi

Posts: 3
Nickname: wigy
Registered: Sep, 2008

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 2:51 AM
Reply to this message Reply
I also agree that this inconsistency is one of the hardest to learn and to teach in Python. When teaching, usually we make a small lie that obj.blah(foo, bar) is just converted automatically to C1.blah(obj, foo, bar), where C1 is the class of obj. This is nice because it teaches another possibility to call a method.

On the other hand, life is much more difficult in Python, and the hooks for syntax beautifying (metaclass programming) makes Bruce's suggestion difficult to implement without breaking other features of the language:

- decorators
- metaclasses
- lambda functions
- instance-only callables: obj.blah = lambda self, foo, bar: None
- virtual members implemented by obj.__getattr__
- .im_self and .im_func members of the method object builtin class.

Athough Guido makes a good job constantly improving this language, I also do not like this inconsistency in the syntax. As a user of a language I do not want to understand the whole complexity of metaclass programming and the implementation details of the interpreter.

If I can throw in my idea, I would also prefer to introduce self as a a syntax like


class C1:

def self.blah(foo, bar):
pass

@classmethod
def classblah(cls, foo):
pass


which would hide this problem from the novice developers, and the surprise would come only when they are starting to do some "tricks" with metaprogramming, but until then they would already now enough from the object model.

Rodrigo Pimentel

Posts: 7
Nickname: rbp
Registered: Sep, 2008

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 6:46 AM
Reply to this message Reply
I think the main issue, Bruce, is that your proposal (or anyone else's I've seen, including mine above) doesn't address all, or even most, of the uses of self: explicitly passing a different object, decorators, renaming ("self" to "cls" or anything else), turning regular functions into methods etc.

At least, not in a way that doesn't actually make it worse (A "self_variable=self" kwarg crossed my mind for the renaming problem, but just for a second ;)).

I think the "explicit is better than implicit" argument, on this particular discussion, is just a short excuse which would be dropped if someone could find solutions to all of these issues.

Eli Courtwright

Posts: 14
Nickname: eliandrewc
Registered: Jan, 2006

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 6:48 AM
Reply to this message Reply
I mostly agree; I like self.x but dislike self in method headers. However, if self was a keyword, then could you say

def f(self, y):
return self.x + y
SomeClass.f = f

And still have it work? We'd also need to figure out how to make the @staticmethod and @classmethod decorators work properly.

Unfortunately, this seems too ambitious for Python 3.1 due to the huge amount of code that would break. I think we'll need to wait another 10 years for Python 4 to even have a shot at this.

Folke Behrens

Posts: 2
Nickname: messi
Registered: Sep, 2006

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 7:20 AM
Reply to this message Reply
> We already have a language that forces you to jump
> through lots of hoops for reasons that must have seemed
> good at the time but have since worn thin:
> it's called Java.

Are you just looking for sympathy from the Python crowd or did you actually become another troll with a blog, Bruce Eckel?

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 10:39 AM
Reply to this message Reply
> I mostly agree; I like self.x but dislike self in method
> headers. However, if self was a keyword, then could you
> say
>

> def f(self, y):
> return self.x + y
> SomeClass.f = f
>

> And still have it work? We'd also need to figure out how
> to make the @staticmethod and @classmethod decorators work
> properly.

If I understand what Bruce is suggesting then that would still work. The semantics of the call would not change, just the syntax of the method declaration.

The question I have is how would a call such as from responses above look with this change:

C2.method(obj, arg1, arg2)

The other thing is on occasion the ability to use a different name for self has helped with local classes (sorry if that's the wrong term). How would I refer to the self from the enclosing method from within a method in a nested class of that method?

Of course, I'm a novice to intermediate python programmer using an old version of the language so these might not be real issues.

Kevin Teague

Posts: 15
Nickname: wheat
Registered: Mar, 2006

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 11:08 AM
Reply to this message Reply
Well, you can't say you don't want to hear "explicit is better than implicit" anymore, and then use the terms pythonic and un-pythonic in your proposal. Both phrases get bandied about a bit too much I think.

Rodrigo Pimentel

Posts: 7
Nickname: rbp
Registered: Sep, 2008

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 11:14 AM
Reply to this message Reply
Kevin, I think what he means is that "explicit is better than implicit" doesn't really apply, here, as self is already implicit in the call (or at least in the most common way of calling, i.e., as an object's regular method). It doesn't mean that he doesn't want to hear it ever again :)

Michael Hobbs

Posts: 51
Nickname: hobb0001
Registered: Dec, 2004

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 12:23 PM
Reply to this message Reply
You're pointing at a larger issue that's always nagged me about Python: you must explicitly set attributes on self, but not methods. Having experience with functional programming, this dichotomy feels unnecessary. For example, if methods were defined the same as attributes, instead of

class Foo():
def __init__(self):
self.bar = 12

def baz(self, x):
return self.bar + x

You'd have something like this instead

def baz(self, x):
return self.bar + x

class Foo():
def __init__(self):
self.bar = 12
self.baz = baz

In fact, if Python introduced currying, the mechanism could be rather clean:

def baz(self, x):
return self.bar + x

class Foo():
def __init__(self):
self.bar = 12
self.baz = baz(self, ...) # partial function call

Michael Hobbs

Posts: 51
Nickname: hobb0001
Registered: Dec, 2004

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 12:41 PM
Reply to this message Reply
Hmm... thinking through this scenario some more, if Python had a full lambda syntax, the concept of classes would be less necessary. So instead of the Foo class above, you'd have a Foo function instead:

def Foo():
self = object()
self.bar = 12
# Pythonic lambda syntax:
self.baz = def(x):
return self.bar + x
return self

That is starting to a lot like JavaScript. I'm not sure if that's good or bad.

Kay Schluehr

Posts: 302
Nickname: schluehk
Registered: Jan, 2005

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 12:46 PM
Reply to this message Reply
> On the other hand, life is much more difficult in Python,
> and the hooks for syntax beautifying (metaclass
> programming) makes Bruce's suggestion difficult to
> implement without breaking other features of the
> language:
>
> - decorators
> - metaclasses
> - lambda functions
> - instance-only callables: obj.blah = lambda self,
> foo, bar: None

> - virtual members implemented by
> obj.__getattr__
> - .im_self and .im_func members
> of the method object builtin class.

+ nested class definitions where the inner class can refer to the self of the outer class.

One has to do a lot more work to turn this proposition into a PEP.

Rodrigo Pimentel

Posts: 7
Nickname: rbp
Registered: Sep, 2008

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 1:04 PM
Reply to this message Reply
Michael, you *can* use a partial function call:


from functools import partial

def baz(self, x):
return self.bar + x

class Foo():
def __init__(self):
self.bar = 12
self.baz = partial(baz, self)

f = Foo()
print f.baz(1) # This prints 13

Daniel Serodio

Posts: 13
Nickname: dserodio
Registered: Apr, 2006

Re: Self in the Argument List: Redundant is not Explicit Posted: Sep 24, 2008 3:05 PM
Reply to this message Reply
I wholeheartedly agree , this is my pet peeve with Python. It makes OOP "feel like" it's been hammered into (onto?) Python instead of being designed. When I first heard about p3k I hoped it would be fixed, but unfortunately, it seems Guido won't capitulate on this...

The misleading error message only makes it worse...

Flat View: This topic has 43 replies on 3 pages [ 1  2  3 | » ]
Topic: Some Insights From Europe Previous Topic   Next Topic Topic:

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use