Why the 'self' argument?

Bengt Richter bokr at oz.net
Thu Sep 11 10:55:36 EDT 2003


On Thu, 11 Sep 2003 11:33:38 +0000 (UTC), Grzegorz Staniak <gstaniak at inka.zagiel.pl> wrote:
[...]
>To sum up what I've learnt here and from the FAQ: 'self' could actually be 
>any string (it is 'self' by convention), as its role is only to serve as 
>the first argument of methods in order to facilitate the process of
>associating method calls with their context. It would be possible (even if
>not obviously desirable) to implement method definitions in such a way
>as to avoid the first argument completely, i.e.
>
>	def something():
>		...
>
>so actually it's just a question of implementation. Having little
>experience with object-oriented programming, I won't try to relate to
>pro and contra arguments that have been given in the discussion, I just
>have one more question: isn't it a little superfulous to have to use the
>'classmethod()' builtin to declare class methods? I'd think giving a
>class object name as the first argument should suffice?
>
I think you may have misunderstood classmethod. Rebinding a class attribute
with the result of classmethod makes a method that
works differently from an ordinary method. It means that the class itself will
be bound to the first argument, even if the method is called as an attribute
of an instance of the class. E.g.,

 >>> class A(object):
 ...     def cm(*args): return args
 ...     cm = classmethod(cm)
 ...     def m(*args): return args
 ...
 >>> class B(A): pass
 ...
 >>> a= A()
 >>> b= B()
 >>> a.cm()
 (<class '__main__.A'>,)
 >>> a.m()
 (<__main__.A object at 0x00902350>,)
 >>> b.cm()
 (<class '__main__.B'>,)
 >>> b.m()
 (<__main__.B object at 0x008F9690>,)

and note:

 >>> A.cm()
 (<class '__main__.A'>,)
 >>> B.cm()
 (<class '__main__.B'>,)

but:
 >>> A.m()
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: unbound method m() must be called with A instance as first argument (got nothing instead)
 >>> B.m()
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: unbound method m() must be called with B instance as first argument (got nothing instead)

also, you don't have to do it inside the class definition, and it's not about a specific
attribute name -- i.e. you don't have to write xxx = classmethod(xxx) as is conventional,
unless the following is fooling me.

 >>> def bar(*args): return 'bar %r'%args
 ...
 >>> class C(B): pass
 ...
 >>> C.cmbar = classmethod(bar)
 >>> c=C()
 >>> c.cmbar()
 "bar <class '__main__.C'>"
 >>> C.cmbar()
 "bar <class '__main__.C'>"
 >>> c.cm()
 (<class '__main__.C'>,)
 >>> c.m()
 (<__main__.C object at 0x00902170>,)

Of course the result is not *identical*, since you can see the original function name
(note that you get a *bound* method either way with a classmethod, vs the ordinary C.m/c.m)

 >>> C.cmbar
 <bound method type.bar of <class '__main__.C'>>
 >>> c.cmbar
 <bound method type.bar of <class '__main__.C'>>
 >>> C.cm
 <bound method type.cm of <class '__main__.C'>>
 >>> c.cm
 <bound method type.cm of <class '__main__.C'>>
 >>> C.m
 <unbound method C.m>
 >>> c.m
 <bound method C.m of <__main__.C object at 0x00902170>>

Regards,
Bengt Richter




More information about the Python-list mailing list