Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Why the 'self' argument?

Reply
Thread Tools

Why the 'self' argument?

 
 
Terry Reedy
Guest
Posts: n/a
 
      09-06-2003

"Isaac To" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> class foo:
> def __init__(msg):
> self.msg = str(msg)
> def f(arg):
> print self.msg + ', ' + str(arg)
> v = foo('hello')
> v.f('world') # equivalent to foo.f(v, 'world')


I think this equivalence, being an answer to the subject sentence,
needs more emphasis. An instance method is a wrapped function and a
*class* attribute. The 'proper' way to call such functions,
consistent with all other function calls, is klass.meth(inst,
*rest_of_args), with inst as an explicit first arg matching the
explicit first parameter in the definition. To me, having an explicit
arg match an implicit param would be a warty inconsistency.

From this viewpoint, inst.meth(*rest_of_args) is a conveinient
abbreviation that works because of the attribute inheritance and
lookup mechanism. Of course, beyond being just syntactic sugar, it
adds the very important flexibility of the programmer not having to
know precisely which base class will provide the method. I think the
long form of method call should be taught first, and then the
abbreviation and behavioral reason for its existence. (Perhaps then,
we would have fewer threads on this topic

If an ad hoc 'self'-rule were added, the inconsistency would have to
be consistently applied to all function definitions. Python attaches
little special importance to the presence of a def within or without a
class suite.
Absent a metaclass override that affects function wrapping only for
those in the .__new__() dict arg but not when later assigned,

class k(object): # or no object
def f(self): pass

nicely abbreviates

def f(self): pass
class k(object): pass
k.f = f
del f

Terry J. Reedy




 
Reply With Quote
 
 
 
 
Terry Reedy
Guest
Posts: n/a
 
      09-06-2003

"Harri Pesonen" <(E-Mail Removed)> wrote in message
news:Ucp6b.3992$(E-Mail Removed).. .
> I agree, it's not logical.


Do my previous two responses today make the logic any clearer?

> I'm learning Python at the moment, and like it very much.


Try learning this. Class K method attribute f with params (s, *rest)
can be called as K.f(Kinst, *rest), consistent with all other function
calls.

Abbreviation Kinst.f(*rest) makes the call look inconsistent by making
K inplicit (and moving Kinst), but the same inplicitness enables
runtime method lookup and superclass inheritance. I think the
benefits that following are worth the minor bump in one's learning
curve.

Terry J. Reedy


 
Reply With Quote
 
 
 
 
Harri Pesonen
Guest
Posts: n/a
 
      09-06-2003
Grant Edwards wrote:

> In article <Ucp6b.3992$(E-Mail Removed)>, Harri Pesonen wrote:
>
>>I agree, it's not logical. I'm learning Python at the moment, and like
>>it very much. This "self" thing seems to be the only odd feature,

>
> It seemed quite natural to me, but perhaps that's because I'd
> used other languages that worked the same way. Coming from
> Modula-3 and Smalltalk, the way classes worked in Python seemed
> quite intuitive.
>
> OTOH, C++ seems like a real non-intuitive mess to me.
>
>>it feels like the whole class feature was added later.

>
> Why?


Because everything else in Python seems to be very compact, there are no
variable type declarations, or variable declarations, or anything else
unnecessary that can be omitted. I would like to have self omitted, it
would make the class syntax more beautiful and compact. On the other
hand, I would like to have real private methods.

Also I think that the class members should be explicitly declared. In
general, it would be nice to have an option (like Option Explicit in
Visual Basic) so that you can't assign to variables that have not been
declared. It would probably make Python less error prone. Also if
variable declarations could have the type, again some errors could be
detected at compile time.

I have not written any real Python applications yet, so I'm not expert,
these are just my thoughts at this point.

Harri

 
Reply With Quote
 
Bengt Richter
Guest
Posts: n/a
 
      09-06-2003
On Sat, 6 Sep 2003 14:45:19 -0400, "John Roth" <(E-Mail Removed)> wrote:

>
>"Bengt Richter" <(E-Mail Removed)> wrote in message
>news:bjd20a$sf6$0@216.39.172.122...
>> On Fri, 5 Sep 2003 20:15:00 -0400, "John Roth" <(E-Mail Removed)>

>wrote:
>>
>> >
>> >"Grant Edwards" <(E-Mail Removed)> wrote in message
>> >news:3f591d28$0$175$(E-Mail Removed). ..
>> >> In article <(E-Mail Removed)>, John Roth wrote:
>> >>
>> >> >> So that there's no difference between a function and a method.
>> >> >>
>> >> >> Simplicity and orthogonality are good things -- despite what
>> >> >> C++ proponents thing.
>> >> >>
>> >> >> > Hence my comment that requiring it is more complex than not
>> >> >> > requiring it.
>> >> >>
>> >> >> No, it's more complex the Java/Ruby way, since you have to have
>> >> >> two sets of rules for what a name means depending on whether
>> >> >> you're inside a "normal" function or a method. In Python
>> >> >> there's just one set of rules -- mostly.
>> >> >
>> >> > As I said earlier, it's quite possible to define it so that there
>> >> > is always an instance of some kind; whether that's an instance
>> >> > a class or the module itself.
>> >>
>> >> I don't follow. You're talking about defining a keyword that
>> >> always refers to the first parameter passed to a function? And
>> >> the declared parameters would refer to the 2nd through Nth
>> >> parameters? What if the keyword isn't used in the function
>> >> definition, then do the delcared parameters refer to the 1st
>> >> through Nth?
>> >
>> >When Python invokes a function, it binds the operands in the
>> >function call to the identifiers named in the function / method
>> >header. If this is a method, it binds the instance (which is not
>> >in the invocation parameter list, btw.) to the first
>> >parameter in the method header.
>> >
>> >If you make "self" a reserved word, then all it has to do
>> >is bind the instance to "self," rather than the first identifier
>> >in the parameter list.
>> >
>> >In current python, there are two classes of functions (module
>> >level and embedded) and three classes of methods (instance,
>> >class and static.) Instance methods get the current instance,
>> >class methods get the class object as the instance, and the other
>> >three categories get nothing.
>> >
>> >As a separate suggestion, I'd have Python bind the module
>> >object to "self" for module functions and static methods. I
>> >haven't figured out what I want done with embedded methods
>> >and unbound methods yet. Notice that this eliminates the
>> >need for the global statement for module functions - all
>> >identifiers are accessible for rebinding through "self."
>> >
>> >> > I think my comments have shown that you can reduce the amount
>> >> > of scoping / name space rules noticably.
>> >>
>> >> Compared to what? It sure sounds like you're introducing more
>> >> rules than there are now. How would you propose reducing the
>> >> number of rules?
>> >
>> >If you don't have to write "self" as the first parameter of a method,
>> >that reduces the complexity. Everything else remains the same.

>>
>> Will this still be possible?
>>
>> >>> def foo(*args): print args

>> ...
>> >>> class A(object): pass

>> ...
>> >>> class B(A): pass

>> ...
>> >>> a = A()
>> >>> b = B()
>> >>> A.bar = foo
>> >>> b.bar('howdy')

>> (<__main__.B object at 0x00906E70>, 'howdy')
>> >>> a.bar('howdy')

>> (<__main__.A object at 0x00907170>, 'howdy')
>> >>> foo('howdy')

>> ('howdy',)
>>
>> >>> A.bar('hello')

>> Traceback (most recent call last):
>> File "<stdin>", line 1, in ?
>> TypeError: unbound method foo() must be called with A instance as first

>argument (got str instan
>> ce instead)
>> >>> A.__dict__['bar']('hello')

>> ('hello',)
>>
>> I.e., the method-vs-function distinction is a matter of how you access the

>function dynamically,
>> not how you define it. There is no static distinction in functionality,

>AFAIK (though I guess
>> there could possibly be some speculative optimizations).

>
>It certainly needs to be. One of the reasons I haven't written a PEP is
>that providing an instance to an unbound method is a case I don't have
>a clear and simple answer to at the moment.
>
>>

> (The above doesn't even get into the multiple name issues I alluded to).
>
>I don't think the multiple name issues are relevant - that has to do with
>how the functions/methods are invoked, rather than what's in the header.)
>

I think we may be thinking of different things. Here is an admittedly artificial
example:

>>> class A(object):

... def foo(a_self, *args):
... class B(object):
... def bar(b_self, *args):
... return 'This uses\na_self=%r and\nb_self=%r' % (a_self, b_self)
... return B
...
>>> a = A()
>>> B = a.foo()
>>> b = B()
>>> print b.bar()

This uses
a_self=<__main__.A object at 0x008F9BF0> and
b_self=<__main__.B object at 0x008F9FF0>
>>> b2 = B()
>>> print b2.bar()

This uses
a_self=<__main__.A object at 0x008F9BF0> and
b_self=<__main__.B object at 0x00903110>

If there were only one "self" keyword to use, you'd have to alias it explicitly
in the outer scope at least (a_self = self before the class B definition in the above).

Hm, I guess that part wouldn't be so bad, actually

Every function would be an unbound method with a potential undeclared local "self" binding,
and ordinary functions would of course not normally access "self", which would be a local
name error if it did so without a binding (though that brings up another issue: if functions
were to be instances of a function class -- how would you distinguish the function instance
"self" from object instance "self" if the function were playing the function role of a bound method?)

One problem would be breakage in code written with (*args) for parameters, expecting
args[0] to be "self" in bound method context.

For passing an instance to a function to make a bound method call, you wouldn't use
the fist slot in the parameter list, you'd have to use a mechanism like what is already
available, modified to bind to the implicit self instead of the first arg list parameter.
I.e., we now have:

>>> def foo(x, y): print 'x=%r, y=%r, x*y=%r'%(x,y, x*y)

...
>>> foo(2,3)

x=2, y=3, x*y=6
>>> foo(2,'3')

x=2, y='3', x*y='33'

>>> bmeth = foo.__get__(2)
>>> bmeth(7)

x=2, y=7, x*y=14
>>> bmeth('7')

x=2, y='7', x*y='77'

>>> foo.__get__(5)('X')

x=5, y='X', x*y='XXXXX'

So presumably foo.__get__(instance)(argx) would be the way to pass an instance to
an unbound method/function defined as, e.g., def foo(x): print 'self=%r, x=%r' % (self, x).

There'd be an awful lot of code to change though ;-/

Regards,
Bengt Richter
 
Reply With Quote
 
Jonathan Aquino
Guest
Posts: n/a
 
      09-07-2003
(Paul Foley replied to my e-mail directly. Below are his remarks,
which I was interested to read. At the end is my reply.)


>> 1) I abhor redundancy. My first impression on seeing self as the

first
>> parameter of all method declarations is that it seems redundant --

it
>> probably isn't technically, but it looks redundant: (self, (self,
>> (self, (self, ...


PF> Of course it's not redundant -- no more than the "x" is redundant
in

PF> def ln(x):
PF> ...

PF> def sin(x):
PF> ...

PF> def cos(x):
PF> ...

PF> def tan(x):
PF> ...

PF> def cosh(x):
PF> ...

PF> def sinh(x):
PF> ...

PF> etc., etc. Gee, look: (x, (x, (x, (x, (x, ...

>> 2) The number of parameters in the method call is one less than

the
>> number of parameters in the method declaration.


PF> No it isn't. The first argument is just in a strange place:

PF> x.foo(y,z)
PF> ^ ^ ^
PF> 1 2 3

PF> x.foo is really just weird syntax for curry(foo, x); i.e.,

PF> q = x.foo

PF> is essentially

PF> q = lambda *a: foo(x, *a)

PF> (but in a different namespace), so

PF> x.foo(y,z) is q(y,z) is (lambda *a: foo(x, *a))(y,z)

PF> and there are exactly as many args in the call as in the
definition
PF> (as, of course, there must be!)


PF> Of course, it would be infinitely better to write foo(x,y,z),
opening
PF> the way to _real_ OO (with multiple dispatch), but x.foo(y,z) is
what
PF> Python supports...


I was interested to read your response.
I think you and I are looking through different lenses. Perhaps
influenced by my Java/Smalltalk background, I'm simply uncomfortable
when I see (1) the first parameter on all method declarations being
the object (didn't have to do this before) and (2) the number of
things
between the parentheses being different for the method declaration and
the method call.

On the other hand, when I read your response it's clear to me that (1)
you are comfortable looking through the lens of functional
programming, so that passing the object in as the first parameter
makes perfect sense to you, and (2) the mismatch in the number of
things
between the parentheses is not a big deal to you (though "strange",
you admit) because as an experienced Python programmer you know what's
going on under the covers.

My opinions are the frank opinions of a Java/Smalltalk programmer
learning Python. And I'm not the only newbie who thinks this seems
strange: the original newbie poster also opined that this is "odd".

Out of the mouths of babes ...
 
Reply With Quote
 
Terry Reedy
Guest
Posts: n/a
 
      09-07-2003

"Jonathan Aquino" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> , I'm simply uncomfortable when I see(2) the number of
> things between the parentheses being different for the method
> declaration and the method call.


If this bothers you enough, and you have a simple class without
inheritance, you *can* write the call in its full form
'class.meth(inst, a, b, ...)' so that you *do* have the same number of
things in declaration and call. Then revert to the shorter form when
comfortable. I am beginning to think methods calls should be taught
this way.

Terry J. Reedy


 
Reply With Quote
 
Alex Martelli
Guest
Posts: n/a
 
      09-07-2003
Terry Reedy wrote:

> "Jonathan Aquino" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) om...
>> , I'm simply uncomfortable when I see(2) the number of
>> things between the parentheses being different for the method
>> declaration and the method call.

>
> If this bothers you enough, and you have a simple class without
> inheritance, you *can* write the call in its full form
> 'class.meth(inst, a, b, ...)' so that you *do* have the same number of
> things in declaration and call. Then revert to the shorter form when
> comfortable. I am beginning to think methods calls should be taught
> this way.


The constraint of "a simple class without inheritance" is too strong.

As long as you know the class of inst, theclass.meth(inst, a, b) will
work no matter how complicated theclass is or how many other
classes it inherits from. The problem is rather one of a loss of
polymorphism when you DON'T know the class of inst. THAT one
you can overcome with type(inst).meth(inst, a, b) [except where
inst is an instance of an _old-style_ class] -- now, this only leaves
you the problem of inst having a _per-instance_ override of name
'meth'... in that peculiar case, inst.meth would pick it up but
type(inst).meth wouldn't.


Alex

 
Reply With Quote
 
Neil Padgen
Guest
Posts: n/a
 
      09-08-2003
On Saturday 06 September 2003 20:58, Harri Pesonen wrote:
>
> Also I think that the class members should be explicitly declared.
> In general, it would be nice to have an option (like Option Explicit
> in Visual Basic) so that you can't assign to variables that have not
> been declared. It would probably make Python less error prone. Also
> if variable declarations could have the type, again some errors
> could be detected at compile time.
>


Is this what you mean?

>>> class A(object):

.... __slots__ = ['a', 'b', 'c']
....
>>> foo = A()
>>> foo.a = 1
>>> foo.b = 2
>>> foo.c = 3
>>> foo.d = 4

Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'A' object has no attribute 'd'

-- Neil

--
 
Reply With Quote
 
John Roth
Guest
Posts: n/a
 
      09-08-2003

"Harri Pesonen" <(E-Mail Removed)> wrote in message
news:TRr6b.4056$(E-Mail Removed).. .
> Grant Edwards wrote:
>
> > In article <Ucp6b.3992$(E-Mail Removed)>, Harri Pesonen

wrote:
> >
> >>I agree, it's not logical. I'm learning Python at the moment, and like
> >>it very much. This "self" thing seems to be the only odd feature,

> >
> > It seemed quite natural to me, but perhaps that's because I'd
> > used other languages that worked the same way. Coming from
> > Modula-3 and Smalltalk, the way classes worked in Python seemed
> > quite intuitive.
> >
> > OTOH, C++ seems like a real non-intuitive mess to me.
> >
> >>it feels like the whole class feature was added later.

> >
> > Why?

>
> Because everything else in Python seems to be very compact, there are no
> variable type declarations, or variable declarations, or anything else
> unnecessary that can be omitted. I would like to have self omitted, it
> would make the class syntax more beautiful and compact. On the other
> hand, I would like to have real private methods.
>
> Also I think that the class members should be explicitly declared. In
> general, it would be nice to have an option (like Option Explicit in
> Visual Basic) so that you can't assign to variables that have not been
> declared. It would probably make Python less error prone.


I believe that is what __slots__ is for. That's run time rather than
compile time, but at least it gives you the error on the statement
that attempts to do an invalid assignment.

> Also if
> variable declarations could have the type, again some errors could be
> detected at compile time.


It's quite possible to add run time type checking to Python, at a
significant cost in performance. See the descriptors material.

There's been quite a bit of work on a compile time type checking
system over the years, but it has never resulted in a proposal that could
be agreed on.

My own personal opinion is that I like the type check system in
the ML family of languages: it stays out of your way unless you need it.
How that would fit in Python is another question, though.
At this time, it looks like an issue for Python 3.0, which seems to
keep receeding into the distance.

John Roth

> I have not written any real Python applications yet, so I'm not expert,
> these are just my thoughts at this point.
>
> Harri
>



 
Reply With Quote
 
Harri Pesonen
Guest
Posts: n/a
 
      09-08-2003
John Roth wrote:

> "Harri Pesonen" <(E-Mail Removed)> wrote in message
> news:TRr6b.4056$(E-Mail Removed).. .
>
>>Grant Edwards wrote:
>>
>>>In article <Ucp6b.3992$(E-Mail Removed)>, Harri Pesonen

>
>>>>I agree, it's not logical. I'm learning Python at the moment, and like
>>>>it very much. This "self" thing seems to be the only odd feature,
>>>
>>>It seemed quite natural to me, but perhaps that's because I'd
>>>used other languages that worked the same way. Coming from
>>>Modula-3 and Smalltalk, the way classes worked in Python seemed
>>>quite intuitive.
>>>
>>>OTOH, C++ seems like a real non-intuitive mess to me.
>>>
>>>>it feels like the whole class feature was added later.
>>>
>>>Why?

>>
>>Because everything else in Python seems to be very compact, there are no
>>variable type declarations, or variable declarations, or anything else
>>unnecessary that can be omitted. I would like to have self omitted, it
>>would make the class syntax more beautiful and compact. On the other
>>hand, I would like to have real private methods.
>>
>>Also I think that the class members should be explicitly declared. In
>>general, it would be nice to have an option (like Option Explicit in
>>Visual Basic) so that you can't assign to variables that have not been
>>declared. It would probably make Python less error prone.

>
> I believe that is what __slots__ is for. That's run time rather than
> compile time, but at least it gives you the error on the statement
> that attempts to do an invalid assignment.


Thanks guys, I hadn't heard of __slots__ before. Perhaps I am reading a
too old book. Of course, a compile time check would be better...

>>Also if
>>variable declarations could have the type, again some errors could be
>>detected at compile time.

>
> It's quite possible to add run time type checking to Python, at a
> significant cost in performance. See the descriptors material.


I think that Python already has run time type checking. It does not
allow "a" + 1, for example.

> There's been quite a bit of work on a compile time type checking
> system over the years, but it has never resulted in a proposal that could
> be agreed on.


It would be quite simple to have "option explicit" like in Visual Basic,
I believe. Like the following:

option explicit
var a = "asdf"
b = 1 # error at compile time
a = 123
(var b, var c, var d) = (1, 2, 3)
e = "asdf" # error at compile time

Always have "var" keyword before first assignment. Just a proposal. You
don't need __slots__ (which sounds like a hack):

class A(object):
var a, var b, var c
# instead of __slots__ = ['a', 'b', 'c']

foo = A()
foo.a = 1
foo.b = 2
foo.c = 3
foo.d = 4 # error at compile time

> My own personal opinion is that I like the type check system in
> the ML family of languages: it stays out of your way unless you need it.
> How that would fit in Python is another question, though.
> At this time, it looks like an issue for Python 3.0, which seems to
> keep receeding into the distance.


I think that the type checking is not so important, but you could have
it as well:

var a as str = "asdf"
var b as int = 123
var c as float = 123.4
a = 123 # error at compile time
# also at run time if not detected earlier
var d = "asdf"
d = 123 # ok, because no type was defined

Harri

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
why why why why why Mr. SweatyFinger ASP .Net 4 12-21-2006 01:15 PM
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
Cisco 2611 and Cisco 1721 : Why , why , why ????? sam@nospam.org Cisco 10 05-01-2005 08:49 AM
Why, why, why??? =?Utf-8?B?VGltOjouLg==?= ASP .Net 6 01-27-2005 03:35 PM
Why Why Why You HAVE NO IDEA MCSE 31 04-24-2004 06:40 PM



Advertisments