Why do class methods always need 'self' as the first parameter?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Tue Sep 6 06:31:25 CEST 2011


On Tue, 6 Sep 2011 11:10 am Chris Torek wrote:

>>>     black_knight = K()
>>>     black_knight.spam()
>>>     black_knight.eggs()
>>>
>>> the first parameters ... are magic, and invisible.
>>>
>>> Thus, Python is using the "explicit is better than implicit" rule
>>> in the definition, but not at the call site. ...
> 
> In article <m2wrdnf53u.fsf at cochabamba.vanoostrum.org>
> Piet van Oostrum  <piet at vanoostrum.org> wrote:
>>It *is* explicit also at the call site. It only is written at the left
>>of the dot rather than at the right of the parenthesis.
> 
> It cannot possibly be explicit.  The first parameter to one of the
> method functions is black_knight, but the first parameter to the
> other method is black_knight.__class__.


I think you are expecting more explicitness than actually required. There
are degrees of explicitness:

- The current President of the United States is a black man.

- On 6th September 2011, the duly constituted President of the United 
  States of America is a black man.

- On 6th September 2011, the duly constituted government official with 
  the title of President of the nation known as the United States of 
  America is an individual member of the species Homo sapiens with XY
  chromosomes and of recent African ancestry.

As opposed to implicit:

- He is a black guy.


There is no requirement for every last gory detail to be overtly specified
in full. I quote from WordNet:

explicit
     adj 1: precisely and clearly expressed or readily observable;
            leaving nothing to implication; "explicit
            instructions"; "she made her wishes explicit";
            "explicit sexual scenes" [syn: expressed] [ant: implicit]
     2: in accordance with fact or the primary meaning of a term
        [syn: denotative]

Note the second definition in particular: in accordance with the primary
meaning of a term: the primary meaning of "class method" is that it
receives the class rather than the instance as first argument.

The "explicit is better than implicit" Zen should, in my opinion, be best
understood as a recommendation that code should, in general, avoid getting
input from context. In general, functions should avoid trying to decide 
which behaviour is wanted according to context or the environment:

def func(x):
    if running_in_a_terminal():
        print "The answer is", (x+1)/2
    else:
        printer = find_a_printer()
        if printer is not None:
            printer.send((x+1)/2, header="func(%r)"%x, footer="Page 1")
        else:
            # Try sending email to the current user, the default user,
            # postmaster or root in that order.
            msg = make_email("The answer is", (x+1)/2)
            for user in [get_current_user(), DEFAULT_USER, 
                         "root at localhost.localdomain", ...]:
                result = send_mail(msg, to=user)
                if result == 0: break
             else:
                # Fall back on beeping the speakers in Morse code
                ... 

(what if I want to beep the speakers from the terminal?), but not as a
prohibition against code like this:

def factorial(x):
    # Return the factorial of the integer part of x.
    n = int(x)
    if n <= 1: return 1
    return n*factorial(n-1)


There's no need to require the user to explicitly call int(x) before calling
factorial just to satisfy the Zen.

A function is free to process arguments as required, even to throw out
information (e.g. float -> int, instance -> class). What it shouldn't do is
*add* information implied by context (or at least, it should be very
cautious in doing so, and document it carefully, and preferably allow the
caller to easily override such implied data).


> Which one is which?  Is spam() the instance method and eggs() the
> class method, or is spam() the class method and eggs the instance
> method?  (One does not, and should not, have to *care*, which is
> kind of the point here. :-) )

You can't tell just from the syntax used to call them:

function(arg)
bound_method(arg)
builtin_function_or_method(arg)
callable_instance(arg)
type(arg)

all use the same syntax. There is no requirement that you should be able to
tell *everything* about a line of code just from the syntax used. If you
want to know whether black_knight.spam is an instance method or a class
method, or something else, use introspection to find out.

> By "that" I assume you mean the name "black_knight" here.  But the
> name is not required to make the call; see the last line of the
> following code fragment:
> 
>     funclist = []
>     ...
>     black_knight = K()
>     funclist.append(black_knight.spam)
>     funclist.append(black_knight.eggs)
>     ...
>     # At this point, let's say len(funclist) > 2,
>     # and some number of funclist[i] entries are ordinary
>     # functions that have no special first parameter.
>     random.choice(funclist)()

Irrelevant. The instance used for the bound method is explicitly specified
when you create it. But there's no requirement that you need to explicitly
specify the instance every single time you *use* the bound method. The
instance is part of the bound method, it isn't implied by context or
history or guessed from the environment.

Contrast what Python actually does with a hypothetical language where bound
methods' instances are implicitly assigned according to the most recent
instance created:

black_knight = Knight()
funclist.append(spam)  # refers to black_knight.spam
white_knight = Knight()
funclist.append(spam)  # refers to white_knight.spam
baldrick = Knave()
funclist.append(eggs)  # oops, Knaves don't have an eggs attribute



-- 
Steven




More information about the Python-list mailing list