Unification of Methods and Functions

David MacQuigg dmq at gain.com
Thu May 6 19:00:16 EDT 2004


On 6 May 2004 08:37:50 -0700, moughanj at tcd.ie (James Moughan) wrote:

> David MacQuigg wrote:
>>Have you read the explanations of instance variables at the end
>> of http://ece.arizona.edu/~edatools/Python/PrototypeSyntax.htm
>> Does this change your thinking?
>> 
>> Explanation of Simplified Instance Variables
>> --------------------------------------------
>> """ Some of the variables inside the functions in a prototype have a
>> leading dot.  This is to distinguish local variables in the function
>> from "instance variables".  When a function is called from an instance
>> ( cat1.talk() ) a special global variable __self__ is automatically
>> assigned to that instance ( __self__ = cat1 )  Then when the function
>> needs an instance variable ( .sound ) it uses __self__ just as if you
>> had typed it in front of the dot ( __self__.sound )  The leading dot
>> is just an abbreviation to avoid typing __self__ everywhere.  """
>
>The changes would go beyond a simple change of syntax; it would break
>the python functional object model, e.g. as you couldn't write a
>global function and assign it to a class at runtime.  (I'm not saying
>this is a good thing to do :) I'm  saying that this is not a trivial
>matter of syntax.)

I don't want to argue implementation details, as I am no expert, but I
think you are saying something is wrong at the user level, and that
puzzles me.

A global function, if I understand your terminology correctly, is one
defined at the module level, outside of any class.  Such a function
cannot have instance variables.  If you were to reference that
function from within a class, it would just act as a normal function
(a static method in Python terminology).  I can't see the problem.

>>> def global_func(x): print x

>>> class Cat:
	f = global_func
	f = staticmethod(f)
	
>>> Cat.f('hello')
hello

The difference in the proposed syntax is that it doesn't need the
staticmethod wrapper to tell the interpreter -- don't expect a special
first argument.  In the new syntax all functions/methods will have the
same calling sequence.

>> Python is clearly superior to C++ and Java for what I need ( teaching
>> EE students and professional engineers ).  Still, it isn't perfect.  I
>> believe a good presentation of OOP could be done in 50 pages ( about
>> half of what is now in Learning Python, 2nd ed.)  
>
>I believe a good working introduction could be done in 10, at most. 
>OOP is not complex.  It's even simple enough for managers to (think
>they) understand, which leads the slightly bizzare state of
>programming today.

I've looked at a few introductions to Python, and in my opinion
Learning Python, 2nd ed, by Mark Lutz and David Ascher is the best.
It strikes a good balance between the minimal presentation that
tersely covers the essentials for an experienced programmer vs the
long, windy introductions that put you to sleep with analogies to car
parts and other "objects".  Lutz takes 95 pages to cover OOP.  I think
I could do a little better, maybe 70 pages, but that may be just my
ego :>)

When you say ten pages, you must be making some very different
assumptions about the students or their prior background, or the
desired level of proficiency.  The least I can imagine is about 30
pages, if we include exercises and examples.  And that 30 assumes we
get rid of all the unneccesary complexity (static methods, lambdas,
etc.) that currently fills the pages of Learning Python.

>> The key to this simplification is not having to discuss static methods
>> or any other method form.  All methods are called just like normal
>> functions, which the students already understand at this point in the
>> course.
>
>They are already called like normal functions, though. You can
>copy-paste a method as a global function and it will still work.  Your
>syntax introduces a special case which makes them distinct, by use of
>a specific method-only dot notation.

Wow!! This is the complete opposite of what I am seeing.  I see
functions and methods *not* having the same calling sequence.  You
need to add the special first argument with most methods.  You
*cannot* just copy and paste a global function into a class without
adding that special first argument, or the staticmethod wrapper.

>> I think the learning process you describe above is quite common.  I
>> went through the same initial steps.  At first I was puzzled by the
>> strange 'self' first argument, and annoyed at typing 'self' in so many
>> places.  Then I understood the magic first argument, and got used to
>> the extra typing.  It did not occur to me that there was some
>> unnecessary complexity yet to come.  I had not yet seen how 'self' is
>> handled in Ruby and in Prothon.  I did not learn about static methods
>> and other forms until much later, and 'lambdas' were something weird
>> related to "lambda calculus".  
>
>There are static methods in Python? :)  In my coding the major reason
>for static methods is for data encapsulation for singleton-style
>elements.  Python has no data encapsulation worth anything, so static
>methods don't do much that's useful.

We have the usual dose of terminology problems here.  The term 'static
method' in Python may be different than in other languages.  In Python
it just means a method that has no instance variables, no special
first argument, and an extra 'staticmethod' line, to tell the
interpreter not to expect a special first argument.

Python does have "encapsulation" but does not have "hiding", by my
understanding of these words.  The idea is that __private variables
are easily identified to avoid accidents, but there is no attempt to
stop deliberate access to such variables.  This is a design philosophy
that I like.

>> The second problem with the "avoidance/denial" strategy is that it
>> involves moving the troublesome functions outside of the class
>> definition.  This results in a less-than-optimal structure for your
>> program.  Look at the show() methods in Animals_2.py  They must be
>> callable without any specific instance.  Moving them outside the
>> appropriate classes is not good programming.  When you want to change
>> a class later, you will need to remember to look in some other place
>> for any "static methods" associated with the class.
>> 
>> If you could do me one more favor, please take a look at the
>> Animals_2.py example starting on page 7 of the Prototypes document at
>> http://ece.arizona.edu/~edatools/Python  Can you write this in Python?
>> Give it a try, and let me know if you had any difficulties.  Were
>> there any parts you had to stop and think, or look up in a manual?
>> 
>
>I am not copy-pasting the whole thing, but I think this demonstrates
>the functionality you want.  It ain't pretty, but I'll discuss that in
>a second.
>
>class static:
>    def __init__(self, fun):
>        self.__call__ = fun
>
>class Mammal:
>
>    numMammals = 0
>
>    def __init__(self):
>        Mammal.numMammals += 1
>
>    def show():
>        print "Inventory:"
>        print " Mammals:", Mammal.numMammals
>
>    show = static(show)
>
>class Feline(Mammal):
>
>    numFelines = 0
>
>    def __init__(self):
>        Feline.numFelines += 1
>        Mammal.__init__(self)
>
>
>    def show():
>        Mammal.show()
>        print " Felines:", Feline.numFelines
>
>    show = static(show)
>
>
>m = Mammal()
>f = Feline()
>print Mammal.numMammals, Feline.numFelines, '\n'
>
>Feline.show()
>
>
>I must note that Animals_2 is a total abuse of OOP techniques.  You
>continuously define classes to do the same thing, repeat the same code
>in each, then give them slightly different names.

This is a textbook introduction, not a real program.  The purpose of
the example is to show a complete OOP hierarchy in a small example,
with a good selection of the method styles most needed in a real
program.  The similarity between the show() methods in different
classes would not be so tempting to reduce to one global function if I
had made a larger example, with more radically different outputs from
each show function.  I thought that just changing one string in each
function would be enough to say "This function is different."

You are not the only one who had this reaction.  See my reply to Don
Cave above.  I guess I need to thow in a little more "meat", so that
experienced programmers don't get distracted by the possibility of
making the whole program simpler by taking advantage of its
regularities.  This is the same problem I've seen in many texts on
OOP.  You really can't see the advantages of OOP in a short example if
you look at it with the attitude -- I can do that much more easily
without classes.  It's when you get to really big complex hierarchies
that the advantages of OOP become clear.

>Also, your show method is IMO more than dubious.  show does not
>logically belong to Feline.  As a result you are using a class to
>display data about other classes to which it is not connected.  This
>is not OOP.

I thought this part was pretty clear.  The show() method at each level
calls the show() method one level up, then adds its own stuff at the
end.  Feline.show() calls Mammal.show(), which prints lots of stuff
characteristic of mammals, all in a format unique to the Mammal class.
Mammal.show() in turn calls Animal.show().  At each level we have some
unique display of characteristics.  The purpose is to have a call at a
particular level show all characteristics of the animal from that
level up.

>If I were teaching someone and they produced this structure then I'd
>go over the rationale with them and try to figure out where they went
>wrong in their planning of the program, and maybe go back and tutor
>them on the basic ideas of OOP.  I would not change the language to
>make it easier to do in future.  :)

Both responses I have on this are basically experts saying -- you can
solve this particular problem more easily by restructuring it.  I
should have been more clear.  Imagine that each of these classes and
methods is fully expanded with lots of parameters to make each one
unique.  Don't even think about re-structuring, unless you are trying
to tell me that the whole idea of having these structures in any
program is wrong.  That would surprise me, since this "animals"
example is a common illustration of OOP.

What I'm looking for is not clever re-structuring, but just a
straightforward translation, and some comments along the way -- oh
yes, that is a little awkward having to use a staticmethod here.  Wow,
you mean staticmethods aren't fundamentally necessary, just a bandaid
to make up for Python's deficiencies?  That was my reaction when I
first saw Prothon.

Thanks again for your feedback.

-- Dave




More information about the Python-list mailing list