Unification of Methods and Functions

D

David MacQuigg

The only time you really need to deal with unbound methods
is when making super calls, and that accounts for maybe
1% or less of all method calls in the code I write.

I haven't seen what Learning Python says about unbound
methods, but if it puts any more emphasis on them than
this, it's putting too much emphasis on them.

It's about 2% if you just count pages. The problem with just counting
pages or number of calls is that doesn't tell you whether those few
calls are really important, or just a little sugar for something that
could be done with more normal methods. If you want to count
something, I would say the percentage of programs which make use of a
particular feature is more meaningful than the number of times it is
used in the program. You still have the problem of finding a
representative sample of programs. Even the Python libraries would
give you skewed stats if you are looking at a new feature.

The number of 'global' statements is probably less than 1% of all
lines of code ( just guessing ), but I don't think anyone would assume
they are unimportant.
The Pythonic way to handle this is to create a module
to hold the Bag class and any functions related to it,
e.g.

# module bags

class Bag:
...

def load(infile):
...

# in some other module
import bags
my_bag = bags.load("my_settings.ini")

I would rather not use modules to package individual classes just
because we are trying to avoid static methods. I'm using modules for
a much larger grouping of classes and data (e.g. everything related to
a particular simulator or display tool). Much easier to just add the
staticmethod line wherever needed, and be done with it.
But seeing as your example did something you're not meant to
be doing in the first place, I don't see how any conclusions
can be drawn from it about simplicity or complexity in
everyday programming.

How can we say that this little snippet wasn't distilled from a larger
program in which the structure makes sense? I've posted this question
in the thread from which the example came, since this appears to be an
important question to many in this thread, and only the OP knows for
sure if it was something real or just an attempt to throw a curve ball
using Python's binding syntax.

My only conclusion is that even wierd examples like this are no
problem with a simpler syntax. A good language has a simple syntax
that is so versatile, you can put things together in many
unanticipated ways, and they work exactly as you would expect.

In my original solution to the statefile problem, I had classes nested
ten levels deep -- no methods, just "bags" of data. It started the
expert I was working with, but it worked surprisingly well. Simple,
versatile building blocks is what I like about Python. I can figure
out the high-level stuff myself. I don't need somebody's "design
pattern".

-- Dave
 
D

David MacQuigg

But why would he need such a method, as opposed to
a plain function?

It may be that the method/function he has written fits most naturally
in a particular class. This is for the programmer to decide, and we
should assume he knows his program structure better than we do.

class Bag:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)

def load(infile):
strng = infile.read()
exec( 'bag = Bag(\n' + strng + ')' )
return bag
load = staticmethod(load)

The load method is unique to Bags, and it belongs
in the Bag class. To me this is a more fundamental consideration than
whether or not the method uses instance variables.

Distinguishing methods by whether or not they use instance variables
seems about like distinguishing them by whether or not they use global
variables. We wouldn't want to move all "global methods" outside
their classes, just because of some quirk in the syntax required it.

-- Dave
 
G

Greg Ewing

David said:
My perspective may be different, because I have not yet absorbed the
Python traditions, and I don't have any instictive avoidance of static
methods.

Are you coming at this from a Java perspective? In Java
(and in C++ until recently) you're forced to use static
methods, because the class is the only kind of namespace
available.

But Python has modules for use as general-purpose
namespaces. Classes are thus relieved of the burden
of performing this double duty, leaving them free to
concentrate on what they do best, which is defining
the behaviour of a collection of objects.

I really recommend that you *use* Python for long
enough to get a good feel for it, before attempting
to revise it. Trying to reform something that you
don't thoroughly understand is fraught with danger.
 
G

Greg Ewing

David said:
The load method is unique to Bags, and it belongs
in the Bag class. To me this is a more fundamental consideration than
whether or not the method uses instance variables.

Giving the function a name such as load_bag would be
just as good in my opinion, if you don't want to dedicate
a whole module to the Bag class.

But then again, I don't see that dedicating a module
to it would be such a bad thing, either.

Python has what is termed a "package", which is
a module containing other modules. You can use a
package to group together modules which encapsulate
related classes. If you have various collection
classes, e.g., you might have a hierarchy of names
like

collections.bags.Bag # class
collections.bags.load # function
collections.sets.Set
collections.sets.load

etc.

By the way, when I start writing a new Python program,
often I'm tempted to put several classes in a module, only
to regret it later as those classes grow and I end up
with a huge source file that's hard to navigate around
in. I'm coming to the view that it may be better to
plan on one-class-per-module from the beginning.
 
M

Mark Hahn

Greg said:
Giving the function a name such as load_bag would be
just as good in my opinion, if you don't want to dedicate
a whole module to the Bag class.

But then again, I don't see that dedicating a module
to it would be such a bad thing, either.

Python has what is termed a "package", which is
a module containing other modules. You can use a
package to group together modules which encapsulate
related classes. If you have various collection
classes, e.g., you might have a hierarchy of names
like

collections.bags.Bag # class
collections.bags.load # function
collections.sets.Set
collections.sets.load

etc.

By the way, when I start writing a new Python program,
often I'm tempted to put several classes in a module, only
to regret it later as those classes grow and I end up
with a huge source file that's hard to navigate around
in. I'm coming to the view that it may be better to
plan on one-class-per-module from the beginning.
 
M

Mark Hahn

Greg said:
By the way, when I start writing a new Python program,
often I'm tempted to put several classes in a module, only
to regret it later as those classes grow and I end up
with a huge source file that's hard to navigate around
in. I'm coming to the view that it may be better to
plan on one-class-per-module from the beginning.

I'm toying with the idea of supporting more than one module per file. That
would allow you to start with one module per class when classes are small
and fit many per file. Then they could expand to one class-module per file.
 
A

Antoon Pardon

Op 2004-05-22 said:
There seems to be a lot of misunderstanding on the question of "magic"
in Python's method binding syntax vs the proposed syntax. I see
students having difficulty learning the current syntax. Python
experts say its real easy, and point to the explicit "self" as an
advantage of the current syntax, vs the "magic" of setting a global
__self__ variable. All of this is missing the problem.

If Python were consistent, and *always* used a special first argument,
there wouldn't be a problem. The magic first argument would be no
more difficult than magically setting a global variable. The problem
is that some methods require a magic first argument, and others
require that it *not* be there. In one case you call cat1.talk() and
in another it is Cat.talk(cat1). I know this is not terribly
difficult to understand -- one is a bound method, the other unbound.
Still it is a problem for beginners, and it leads to unecessary
complexities like static methods.

The recent discussion on "Method binding confusion" 5/2/04 shows that
even experts can get confused. Here is the example, reduced to its
simplest terms:

import math

def mypow(x, y):
return x**y

class MathA:
pow = math.pow

class MathB:
pow = mypow

ma = MathA()
mb = MathB()

print ma.pow(2,4) #=>
16.0
print mb.pow(2,4) #=>
# TypeError: mypow() takes exactly 2 arguments (3 given)

How would you explain this to non-CIS students in a class on circuit
design, where there is very little time to discuss programming?

For as far as it is necessary to explain this, I would explain it as
a bug. IMO this is a bug because the behaviour seems to differ depending
on whether the function is implemented in C or python. Users of a module
shouldn't be concerned how something is implemted.
 
A

Antoon Pardon

Op 2004-05-22 said:
This is OK for the first example. I would leave the __init__ methods
to the second example, but either way it will take about 8 pages to
comfortably explain OOP ( maybe ten if I include the "robust
programming" examples that JM says I must ). I would like students to
understand Python at the level they can follow what is going on in a
real program, and maybe write a few classes themselves.


If you are saying we can totally ignore the different method forms, I
think you are wrong. Bound and unbound methods, for example, will be
needed in almost any sizable program. The need for static methods
will arise when the student first writes a method that needs to work
without a current instance.

He doesn't need a method for that. He can just write a function.

Why do you want to write a method in circumstances that call for
a function?
 
A

Antoon Pardon

Op 2004-05-22 said:
I can't comment on the usage statistics you cite, but it seems to me
that unbound methods are more important than these statistics would
imply. They are necessary to make the language complete, so you can
do things that would otherwise require creating an artificial instance
just to call a method. Learning Python also treats unbound methods as
much more "normal" than your argument would imply.


Here is an example from our CDP ( Circuit Design Platform ):

class Bag:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)

def load(infile):
strng = infile.read()
exec( 'bag = Bag(\n' + strng + ')' )
return bag
load = staticmethod(load)

We need to load a "statefile" with a deeply nested hierarchy of
parameters, which will then be represented by a "Bag" of parameters at
each level of the hierarchy. The load method needs to be called
before any Bag exists, so we add the magic "staticmethod" line, and
don't worry about 'self'. Sure, we could move the load function
outside of the Bag class, but that would disrupt the natural structure
of the program. The load function is unique to Bags, and it belongs
in the Bag class.

I don't agree it belongs in the Bag class. The fact that it is unique
to Bags is not an argument for that. I would agree that they belong in the
same module.

IMO you try to cram too much into the class. It seems you want to
put everything in the class that is related to the class. But
sometimes things are related without being a part of it. Writing
a seperate function in the same module makes more sense in that case.
Have you read the proposal at
http://www.ece.arizona.edu/~edatools/Python ?? The folks at
prothon.org also think they have a better solution. There are some
good ideas amongst all the crud. Unification of methods and functions
is one. It remains to be seen if they can do this without introducing
other equally bad complexities. Smooth the carpet in one place, and
the wrinkles pop up somewhere else.

When you say the distinction between methods and functions makes
sense, I assume you mean it has some value to the user. I would like
to hear more about this, because I am assuming just the opposite. In
my OOP chapter, I rely on the fact that students already understand
functions. I use the term "method" only when it is necessary to make
a distinction. Otherwise, everything is just a function, and there is
only one kind.

Well one possible view is that methods are just functions. The
difference being that it is not exactly the function as it
is defined in the class but as related function. Now I don't
know if trying to explain methods from this point of view
would be easier for students to understand and it may cause
confusions of its own. But I think this approach deserves
more attention you seem willing to give it.
 
A

Antoon Pardon

Op 2004-05-24 said:
If "lambda functions" were nothing but functions with the name left
off, they would serve their current purpose, and they would not be
such a problem that there is talk of actually taking them *out* of the
language. They aren't essential, but they do serve a purpose which
some feel is important.

The only "importance" is that you are not obligated to write
down a proper function definition when you only want to
provide an expression as a function argument.
I would see it as a loss. The next best alternative is to move the
static method outside of the class, and that puts an arbitrary
restriction on how I can structure my programs. If the person writing
the program feels that the function belongs in the class, let's not
say it can't be done because either a) The syntax doesn't allow it. or
b) We assume he is wrong in thinking his function belongs inside his
class.

My perspective may be different, because I have not yet absorbed the
Python traditions, and I don't have any instictive avoidance of static
methods.

I never felt the need for static methods, and I still don't think
of my self as having absorbed the python traditions. Maybe the
questions is, where do you get your instinct from to use static
methods?
 
D

David MacQuigg

I don't agree it belongs in the Bag class. The fact that it is unique
to Bags is not an argument for that. I would agree that they belong in the
same module.

I think we need to trust the programmer who wrote the class as to the
right place to put the load function. He is the only one who can
organize the best overall structure of modules and classes in the
context of his entire system.
IMO you try to cram too much into the class. It seems you want to
put everything in the class that is related to the class. But
sometimes things are related without being a part of it. Writing
a seperate function in the same module makes more sense in that case.

In this case there is only one other method in the class ( save ), and
it forms a neat, self-contained package. Moving load to the module
level just so we can avoid the staticmethod line may put it in a
namespace that is already crowded with a bunch of other similar
things. We also need tricks like adding "bag" to the function name,
or putting the load function right next to the Bag class, so future
programmers will notice that the function is for Bags only.
Well one possible view is that methods are just functions. The
difference being that it is not exactly the function as it
is defined in the class but as related function. Now I don't
know if trying to explain methods from this point of view
would be easier for students to understand and it may cause
confusions of its own. But I think this approach deserves
more attention you seem willing to give it.

I don't feel I can make much improvement on Learning Python, 2nd ed.
I think this is the same approach that you are talking about -
functions first, then methods, one variation at a time.

-- Dave
 
D

David MacQuigg

I never felt the need for static methods, and I still don't think
of my self as having absorbed the python traditions. Maybe the
questions is, where do you get your instinct from to use static
methods?

When I write methods in a class, some of them have instance variables,
and some do not. Some have global variables. Some have both globals
and instance variables. The methods without instance variables are
"static methods". I have no instinct acquired from Java or some other
language. I just write whatever method is needed for the task at
hand. Saying I should avoid static methods seems to me like an
arbitrary restriction.

Class methods are a little different. I've never felt the need for
one, although I just received a contribution from one of the readers
of this thread - a program using class methods to solve the inventory
problem in Animals_2. It seems to me that class methods provide
syntax sugar for a very special need, while static methods provide a
way to implement *any* method that doesn't require an instance
variable. I may be not fully understanding the need for class
methods.

-- Dave
 
A

Antoon Pardon

Op 2004-05-25 said:
I don't feel I can make much improvement on Learning Python, 2nd ed.
I think this is the same approach that you are talking about -
functions first, then methods, one variation at a time.

I don't think so. The apprach I'm thinking of would
be about the following.

1) functions
2) bare classes (no methods)
3) higher order functions
4) show how higher order functions
can result in method like beheviour
5) methods and show the connection with
higher order functions.
 
D

David MacQuigg

Are you coming at this from a Java perspective? In Java
(and in C++ until recently) you're forced to use static
methods, because the class is the only kind of namespace
available.

I studied Java a little bit two years ago, but not enough to absorb
any bias toward static methods.
But Python has modules for use as general-purpose
namespaces. Classes are thus relieved of the burden
of performing this double duty, leaving them free to
concentrate on what they do best, which is defining
the behaviour of a collection of objects.

I hesitiate to waste a whole level of packaging on just tying static
methods to their classes. A distribution of our circuit-design
platform might have a bunch of classes in a module for netlisting.
That module might be part of a complete package for a particular
simulator. I suppose I could subdivide the module into smaller
packages, but it seems awkward. Maybe if we could have more than one
module per file. Files would then be one more level in the packaging
hierarchy.

I still prefer to just add the staticmethod line and leave the method
where I first put it - in the class to which it applies.
I really recommend that you *use* Python for long
enough to get a good feel for it, before attempting
to revise it. Trying to reform something that you
don't thoroughly understand is fraught with danger.

OK with me. Looks like there is no rush on Python 3. In about three
months I should have double the experience with Python I have now.

-- Dave
 
D

David MacQuigg

Op 2004-05-22, David MacQuigg schreef <[email protected]>:

He doesn't need a method for that. He can just write a function.

Why do you want to write a method in circumstances that call for
a function?

See my reply to Greg Ewing on Mon, 24 May 2004 16:17:59 -0700
 
D

David MacQuigg

I don't think so. The apprach I'm thinking of would
be about the following.

1) functions
2) bare classes (no methods)
3) higher order functions
4) show how higher order functions
can result in method like beheviour
5) methods and show the connection with
higher order functions.

I've started a section on my webpage at
http://ece.arizona.edu/~edatools/Python/Examples
for those that feel we need a completely different approach to
introducing OOP. If you put together some examples of what you mean
by the above, I'll add them to my webpage.

-- Dave
 
N

Neil Benn

<snip>

The point is that a static method defined in a class _is_ a part of the
object model. There are many, many object models where you would have a
static method that _belongs_ to the class.

For a dummy example :

--

A dodo class which has a method to return a new dodo when it is born.

A dodo class with a static method to return the first ever dodo (the
uber-dodo!), this is a static method - making the constructor return the
same dodo each time is counter intuitive.

ALSO

A dodo class static method of Dodo.makeExtinct(), this applies to the
Dodo class (species) and not to the individual dodo (animal).

--

In addition, when returning a singleton, that should live in with
the class as the fact that a class in only available as a singleton is a
factor of the design of the class and should not be linked to another
namespace.

I am a ex-Java/.NET programmer so I admit I'm biased but the problem
is not language specific, it's design specific. I do understand that in
Python this is only syntatic sugar but using a module namespace to
acheive these needs removes what is a link in the design.

Cheers,

Neil

--

Neil Benn
Senior Automation Engineer
Cenix BioScience
BioInnovations Zentrum
Tatzberg 46
D-01307
Dresden
Germany

Tel : +49 (0)351 4173 154
e-mail : (e-mail address removed)
Cenix Website : http://www.cenix-bioscience.com
 
A

Antoon Pardon

Op 2004-05-25 said:
I've started a section on my webpage at
http://ece.arizona.edu/~edatools/Python/Examples
for those that feel we need a completely different approach to
introducing OOP. If you put together some examples of what you mean
by the above, I'll add them to my webpage.

First of all. I don't know if a completly different approach
is usefull. I don't claim my approach will be helpfull for
anyone. I just hope this approach can clear things up for
people who are confused by other approaches.

Now I'm not going to explain functions and bare classes
since I don't think there are any problems with those
concepts.

3) Higher order functions. These are functions that
whose arguments and/or return values can be again
functions.

The typical example is a sorting function that takes
as an argument a function that decides which of two
elements is the smaller. By providing different
functions (one that looks at names or one that
looks at Id number) the same function can be used
to sort people alphabetical or Numerical by Id.

Now to go a step further. Suppose we have a lot
of functions Fi: Each of these functions is
defined as follows Fi(x) = i + x. Now we
can have an other function S. S is defined as
follows: S(a) = Fa. Now we can use S to add
two numbers. Suppose we want to add 2 and 5.
First we call S(2), this will result in F2.
Then we call F2(5) which will result in 7.
Or more directly we could call S(2)(5).

Now python allows to define higher order functions.
S would be defined as follows in python:

def S(i):

def Fi(x):

return i + x

return Fi


The rest will be for future posts. If you have
questions or remarks don't hesitate.
 
D

Dave Brueck

David said:
Here is a better analogy than my "no-q" functions. I will use the
term "global method" to mean any method containing a global variable.
We now have "normal methods", "static methods", "global methods", and
a few others. There is no difference in the calling sequence or the
header line between a global method and a normal method. Yet we don't
seem to have any need for a statement like
myMethod = globalmethod(myMethod)

Ugh, I'm sorry but this analogy seems as bad as the no-q analogy. That's like
saying methods that contain for-loops should be declared differently - but in
neither case is the thing that matters to the caller - the interface (both the
explict means by which the function is used as well as the explicit or implicit
contract and purpose of the function) - affected. Let's move on.
I'm new to Python and object-oriented programming. I make no claim of
language expertise or vast programming experience.

Doesn't it give you pause that many other people, both with and without that
background, have encouraged you to give the current feature set a chance? As
in, use these features for awhile, get some more experience with them, and in
time you'll come to understand the 'why' behind them? Again, I'm not asserting
that the current language is perfect, just that the way things are might have a
purpose and/or the proposal you've come up with has drawbacks worse than what
we already have... If nothing else, waiting until you have a lot of programs
under your belt will let you argue your point from a position of strength.
offering a perspective on Python from a technical professional
(circuit design engineer) who intends to use it as the basis for a new
design platform, and intends to recommend it to students and other
technical professionsls who could benefit greatly, but don't have time
to learn the language as well as they should.

Then what you really ought to do is not cover more advanced topics any sooner
than is needed. Really. Nobody taking an intro-to-programming course needs to
learn about e.g. classmethods. They just don't need to. In your course pass out
a link to a web page of advanced reading for those you want to know more, and
leave it at that. Burdening them with tools they won't use anytime soon won't
be doing them a favor. Instead, teach them how to find answers to their
questions, how to experiment, so that _if_ and when they do come across it then
they can go learn it then.
OK, here is what I can extract from all this: Having a separate
syntax for static methods is beneficial because it tells the
programmer at a glance that he can call a method from a class without
having an instance of that class at hand.

That's part of it, but there's more - a static method is used in different
scenarios and for different purposes. They generally aren't interchangeable
beasts.
I have shown the 4 function/method forms I'm aware of, and how to
translate them to a simpler syntax, in Appendix 1 of Prototypes.doc at
http://ece.arizona.edu/~edatools/Python Have you read that?

Yes, but as I pointed out elsewhere, it may help to write about this in some
other context than your other proposals (the fact that this is buried in
Appendix 1 under a title of "Translating Python Classes to Prototypes" doesn't
lend itself to much reader traffic).

But, it's better than nothing, so here goes:

1. Bound methods - the calling appears to be identical in either version, but
one of the real values of the bound method form is being able to call the bound
method _when you don't have the instance variable handy_ (I'm just trying to
point out why it's useful). Anyway, the fact that the methods don't have a self
variable does make things seem a little magical - with 'self' in the arg list
it makes sense to me how self.foo grabs a variable from the current instance.
Yes, there is some magic in the current implementation in that the self arg
gets passed in, but the alternative is either uglier or more magical, so it
seems like a good compromise between explicitness and practicality.

2. Unbound methods - the example uses an unbound method to "bypass" a subclass
method - that seems like a really unrealistic example. Inserting the superclass
method into the subclass, but with a different name seems equally odd. Thus,
the whole argument in favor of the "Python 3" version is unappealing. What's
downright frightening, however, is that you can write something like '__self__
= c' and get the same behavior (for many reasons, not the least of which is
that two seemingly unrelated statements are completely linked). Wanting to call
a superclass method with the current instance is a much more likely example,
but with either form of the "Python 3" syntax it's quite unclear that that is
what is happening - because it's indistinguishable from the other calls, it's w
ay less clear what the code is doing. Thus, both newbies and experts alike will
have a more difficult time understanding (and maintaining and modifying) the
code.

3. Static methods - your page doesn't list any examples of calling the
functions, but I assume that in both cases it's Mammal.show(). Not much to be
unified here, although I don't like the fact that the "Python 3" version loses
the information that it is a static method (I don't particularly like the fact
that for the current version the staticmethod call happens after the method
body - I like some of the proposals in the related PEP), but in current Python
you actually have two indicators - there's no 'self' parameter. And again, you
have the same problem in the calling code - it's not clear what is happening,
and yet what is happening is a pretty important piece of info. In the "new"
syntax, the call could be to a static method or to a superclass method, but the
reader of the code is left wondering which one it is.

4. Class methods - this example just seems broken, but perhaps I'm misreading
it. In the Python 3 version, a string is getting passed in to the class method,
and the prototype of the *string* is then displayed - makes no sense to me. In
any case, class methods are IMO a pretty advanced topic - since a main point of
yours is that you want to make OO more accessible to the lay programmer, I
don't see how class methods would come up in the discussion at all - they'd be
more relevant to a metaclass or descriptor discussion.
I'm also continually adding new examples under the Examples and
Exercises link on that same page. Many of these are contributed by
readers of this thread, including some who would rather not post here.
(Gentle Request: A little less intolerance from some others on this
thread might encourage more contributions from people they really need
to hear from.)

Equally gentle request: don't be too hasty in assuming that because people
disagree with you, their previous experience has clouded their perceptions or
made them forget what it was like to walk the path you're currently on.
As for a real program, it will be a few months before I have anything
sizable. I showed you the statefile example (in response to your
request), but you seemed to be insulted, like you thought I was
talking down to you, or something.

Not at all, just realize how your message sounds on the receiving end (whether
you intended it to come across this way or not): "Even though I haven't really
used these features much, I think they should be changed. Other people say the
features have a purpose, and that the purpose becomes clear over time, but I
disagree." That, in itself, is hard to take too seriously, although I'm
impresed at how many people apparently took the time to think about your
suggestion.

Best of luck,
Dave
 
D

David MacQuigg

Ugh, I'm sorry but this analogy seems as bad as the no-q analogy. That's like
saying methods that contain for-loops should be declared differently - but in
neither case is the thing that matters to the caller - the interface (both the
explict means by which the function is used as well as the explicit or implicit
contract and purpose of the function) - affected. Let's move on.

OK, but this issue is definitely not settled.
Doesn't it give you pause that many other people, both with and without that
background, have encouraged you to give the current feature set a chance? As
in, use these features for awhile, get some more experience with them, and in
time you'll come to understand the 'why' behind them? Again, I'm not asserting
that the current language is perfect, just that the way things are might have a
purpose and/or the proposal you've come up with has drawbacks worse than what
we already have... If nothing else, waiting until you have a lot of programs
under your belt will let you argue your point from a position of strength.

OK, I will wait until I have earned the right to make such a bold
proposal. If I still feel the same three months from now, I'll post
again, assuming I still have the time and desire to debate the issue.

That is the problem with saying that only experts can propose changes.
Right now the issue is a hot topic for me, because I've just been
through the learning experience. Three months from now, I will
probably feel the same about the technical merits of the proposal, but
won't have the desire to engage in a long debate.

It does disturb me that I am the sole advocate for the proposal on
this thread, but I don't consider this to be a reprentative sample of
users either. I think the whole discussion may be a bit intimidating
for the users I am most concerned about.

I guess the best counter to the argument that "Everybody disagrees
with you, recant!" is -- No, I don't think that the folks who
developed Ruby or Prothon would disagree with me. Python is far from
perfect when people feel the need to develop a whole new language that
does basically the same thing.

Just to head off some flames here -- in spite of the few minor faults
I see in Python, it is by far the best language for me.
Then what you really ought to do is not cover more advanced topics any sooner
than is needed. Really. Nobody taking an intro-to-programming course needs to
learn about e.g. classmethods. They just don't need to. In your course pass out
a link to a web page of advanced reading for those you want to know more, and
leave it at that. Burdening them with tools they won't use anytime soon won't
be doing them a favor. Instead, teach them how to find answers to their
questions, how to experiment, so that _if_ and when they do come across it then
they can go learn it then.

Who said I was going to cover class methods? The three forms I see as
important are bound and unbound methods, and static methods. For the
rest, including lambda functions, I'll have a link to python.org/doc
or a reference to the discussion in Learning Python, 2nd ed.
That's part of it, but there's more - a static method is used in different
scenarios and for different purposes. They generally aren't interchangeable
beasts.

It's these mystical qualities of the "more" part that have me
mystified. Whatever those qualities may be, the same can be done with
the new syntax. That leaves the only difference as what I have stated
above -- the visibility of a static method. There is no other
difference in actual use of the two syntaxes.
Yes, but as I pointed out elsewhere, it may help to write about this in some
other context than your other proposals (the fact that this is buried in
Appendix 1 under a title of "Translating Python Classes to Prototypes" doesn't
lend itself to much reader traffic).

I will soon post to my website translations of the programs I have
received, and any others that someone cares to send me.
But, it's better than nothing, so here goes:

1. Bound methods - the calling appears to be identical in either version, but
one of the real values of the bound method form is being able to call the bound
method _when you don't have the instance variable handy_ (I'm just trying to
point out why it's useful).

In either syntax you don't need the instance handy to call the bound
method. It was bound at the time the bound method was created, and it
stays bound even if the instance is deleted. Bound functions in both
syntaxes are immutable.
Anyway, the fact that the methods don't have a self
variable does make things seem a little magical - with 'self' in the arg list
it makes sense to me how self.foo grabs a variable from the current instance.
Yes, there is some magic in the current implementation in that the self arg
gets passed in, but the alternative is either uglier or more magical, so it
seems like a good compromise between explicitness and practicality.

I see the two ways of passing self as equally magical, and the magic
is *insignificant* in either case. In one case we insert a magic
first argument 'self'. In the other we set a magic global variable
__self__. If I had to chose solely on the basis of minumum magic, I
would go with the global variable, because students already understand
global variables at this point. They also understand function
arguments, but the insertion of an argument is a little startling.
Again, the magic in either case is so small that I would say this is
in the realm of personal preference.

By the way, both Ruby and Prothon have decided *not* to pass 'self' in
the first argument, and they were well aware of Python's convention
when these decisions were made.
2. Unbound methods - the example uses an unbound method to "bypass" a subclass
method - that seems like a really unrealistic example. Inserting the superclass
method into the subclass, but with a different name seems equally odd. Thus,
the whole argument in favor of the "Python 3" version is unappealing. What's
downright frightening, however, is that you can write something like '__self__
= c' and get the same behavior (for many reasons, not the least of which is
that two seemingly unrelated statements are completely linked). Wanting to call
a superclass method with the current instance is a much more likely example,
but with either form of the "Python 3" syntax it's quite unclear that that is
what is happening - because it's indistinguishable from the other calls, it's w
ay less clear what the code is doing. Thus, both newbies and experts alike will
have a more difficult time understanding (and maintaining and modifying) the
code.

I agree the example is unrealistic. Rarely, if ever, will you need to
call an unbound method from the module level, or over-ride the default
binding to __self__. The example merely shows that it can be done, if
you must. I need to show a bunch of simple cases, so people don't
dwell on these extremes. The more common case ( calling an unbound
method from inside another method, keeping the same __self__ as the
bound instance ) looks identical to current Python, except there is no
'self' in the arg list.
3. Static methods - your page doesn't list any examples of calling the
functions, but I assume that in both cases it's Mammal.show(). Not much to be
unified here, although I don't like the fact that the "Python 3" version loses
the information that it is a static method (I don't particularly like the fact
that for the current version the staticmethod call happens after the method
body - I like some of the proposals in the related PEP), but in current Python
you actually have two indicators - there's no 'self' parameter. And again, you
have the same problem in the calling code - it's not clear what is happening,
and yet what is happening is a pretty important piece of info. In the "new"
syntax, the call could be to a static method or to a superclass method, but the
reader of the code is left wondering which one it is.

I wish I could understand why highlighting a method as being a
staticmethod is so important to you. Others have said that
staticmethods are really rare, and could even be deprecated. So if
you really needed to scan a method body, and see if it has any
instance variables, this would be a rare annoyance.

What is the consequence of missing the fact that a method doesn't use
'self'? What if we were to unify the two forms by going the other way
-- All methods use 'self'? If an instance doesn't exist, it is
created, ignored, then deleted.

I know you hate the "globalmethod" analogy, but there is actually
*more* justifation here for having a special form. If you call a
static method from an instance, nothing bad happens. The __self__ is
just ignored. If you miss the fact that a method needs global
variables, all hell could break loose. :>)
4. Class methods - this example just seems broken, but perhaps I'm misreading
it. In the Python 3 version, a string is getting passed in to the class method,
and the prototype of the *string* is then displayed - makes no sense to me. In
any case, class methods are IMO a pretty advanced topic - since a main point of
yours is that you want to make OO more accessible to the lay programmer, I
don't see how class methods would come up in the discussion at all - they'd be
more relevant to a metaclass or descriptor discussion.

Your right. It is broken. I wish I had a "Python 3" interpreter to
check these things. I believe this is the first time anyone has
looked at this section carefully, and I appreciate your effort.

You are also right about classmethods being an advanced topic, and I
won't be covering them in my class. I needed to show this example,
because rare as they are, if there were not an automatic translation
of classmethods to the new syntax, some existing programs would not
survive a migration, and that alone is a cost higher than the value of
any changes I am proposing.

I need to move this appendix out of the introductory chapter and make
it an appendix to the syntax proposal.

The example should have been Mammal.show(tiger), where tiger is an
instance or a class, not a "string".
Equally gentle request: don't be too hasty in assuming that because people
disagree with you, their previous experience has clouded their perceptions or
made them forget what it was like to walk the path you're currently on.

If I have offended anyone with a statement like this, I sincerely
appologize. The intolerance I was talking about was direct personal
attacks, and angry or sarcastic remarks. This group has far less of
it than most other groups I have participated in.
Not at all, just realize how your message sounds on the receiving end (whether
you intended it to come across this way or not): "Even though I haven't really
used these features much, I think they should be changed. Other people say the
features have a purpose, and that the purpose becomes clear over time, but I
disagree." That, in itself, is hard to take too seriously, although I'm
impresed at how many people apparently took the time to think about your
suggestion.

I'm sorry that my "message" comes across as you suggest. I try always
to start with an open mind. If I don't understand the purpose of a
feature, I say "show me". Only after repeated attempts to get
something more concrete, do I tentatively reach a different
conclusion. I'm skeptical, but I think I'm more cautious than most in
not making dogmatic statements without understanding an issue.

I also have no hesitation to acknowledge when I'm wrong. I was
pushing "prototypes" ( as done in Prothon ) until Michele Simionato
showed that they could be done with the existing machinery in Python.
They are still in my proposal, but with a clear statement that they
won't make the next revision unless someone shows that Michele's
"prototype.py" module is missing something important.

On the issue of staticmethods, I use them more freely than most others
on this thread would prefer. I disagree that they have a fundamental
purpose in life, but I respect others' opinions, and I have my
receiver at maximum sensitivity, in case someone were to post an
example that would make me say - Oh cool, now I understand the true
purpose of staticmethods, and the reason they deserve a special
syntax.
Best of luck,
Dave

You too. And again, thanks for the careful review.

-- Dave M
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top