473,387 Members | 1,529 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Unification of Methods and Functions

I'm not getting any feedback on the most important benefit in my
proposed "Ideas for Python 3" thread - the unification of methods and
functions. Perhaps it was buried among too many other less important
changes, so in this thread I would like to focus on that issue alone.

I have edited the Proposed Syntax example below to take out the
changes unecessary to this discussion. I left in the change of
"instance variable" syntax ( self.sound --> .sound ) because that is
necessary for the unification of all method forms. ( Compare the
forms of the 'show' and 'talk' methods below.)

I believe these changes in syntax will make teaching OOP in Python
much easier. See "Prototypes.doc" at
http://ece.arizona.edu/~edatools/Python/ The first eight pages are a
basic, but complete presentation of the new OOP syntax. I expect this
to expand to about 30 pages with more examples and exercises. This
compares to about 60 pages in Learning Python 2nd ed.

If we measure complexity by the number of pages needed for a "textbook
explanation" of OOP, then I believe the new syntax has some real
benefits. At this point in the learning process, students already know
functions, modules, and global variables. The concept of using a
global variable __self__ is no surprise at all. The only thing new in
a class, compared to a module, is the instance variables, and they can
be explained in one paragraph. All methods look just like normal
functions. There is no need to explain "static methods" or any other
form of method. In fact, I use the term "function" rather than
"method" to emphasize the similarity.

I'm especially interested in feedback from users who are now learning
or have recently learned Python. I already know these changes seem
trivial to many experts. I've also heard plenty from the people who
think Python is so complex that we need to start a whole new language
( www.prothon.org ). I'm looking for a middle ground. I believe it
is possible to adopt what is good about Prothon, and not lose ten
years of software and community development.

======= Syntax Examples =============

## Proposed Syntax:
class Cat(Feline):
numCats = 0
def __init__( n = "unknown", s = "Meow" ):
Feline.__init__()
Cat.numCats += 1
.name = n # Set instance variables.
.sound = s
def show(): # Define a "static method".
Feline.show()
print " Cats:", Cat.numCats
def talk():
print "My name is ...", .name
print "I am a %s from %s" % (.genus, .home)
Mammal.talk() # Call an unbound function.
print __self__ ### Diagnostic check.

cat1 = Cat() # Create instance.
bf = cat1.talk # Make a bound function.
## Equivalent Python:
class Cat(Feline):
numCats = 0
def __init__(self, n = "unknown", s = "Meow" ):
Feline.__init__(self)
Cat.numCats += 1
self.name = n
self.sound = s
def show():
Feline.show()
print " Cats:", Cat.numCats
show = staticmethod(show)
def talk(self):
print "My name is ...", self.name
print "I am a %s from %s" % (self.genus, self.home)
Mammal.talk(self)
print self

cat1 = Cat() # Create instance.
bf = cat1.talk # Make a bound function.

========= End of Examples =======

Thanks for your help.

-- Dave

Jul 18 '05
99 5795
On Thu, 13 May 2004 10:56:58 -0400, "Terry Reedy" <tj*****@udel.edu>
wrote:
"Antoon Pardon" <ap*****@forel.vub.ac.be> wrote in message
news:sl********************@trout.vub.ac.be...
One could argue that all forms of methods and functions are unified.
It is just that python does some magic so that the method you
access from an object is not the actual function but the curried
function with the object.


My view is similar: in Python, a method is a dressed up (wrapped) function.
'Unification of methods and functions' reads to me like 'unification of
dressed-up bodies and naked bodies'. What would that mean? One thing I
like about Python is that there is only function-body syntax and not a
separate, slightly different method-body syntax. To me, having only one
type of code body *is* unification. So it is hard for me to see what is
being proposed. Introducing a syntax like '.var' that would only be
meaningful in a method and not a function would be dis-unification.


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?

-- Dave

Jul 18 '05 #51
Quoth David MacQuigg <dm*@gain.com>:
| 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?

I wouldn't. I would say

"Classes allow you to create objects with their own functions,
called methods, that you write. Each function takes `self'
as its first parameter."

"Here's a class:"
class A:
def __init__(self):
self.data = 'spud'
def hello(self):
print 'Hello, I am a class A', self.data

"Classes can inherit functions from other classes:"
class B(A):
def __init__(self):
self.data = 'gerbil'

"The actual object - a class `instance' - is created by invoking
the class name, applying arguments which will be passed to __init__."

Then I would go over that, showing what happens and why, until the
concepts introduced above seem to be clear for everyone. That would
conclude my treatment of classes. As an elementary language, there
are some slightly hard things to learn about Python, but this isn't
going to be one of them unless you make it hard.

Donn
Jul 18 '05 #52
David MacQuigg <dm*@gain.com> wrote in message news:<9h********************************@4ax.com>. ..
On 19 May 2004 23:26:38 -0700, mo******@tcd.ie (James Moughan) wrote:
David MacQuigg wrote:
I've made your program, Animals_JM.py at
http://ece.arizona.edu/~edatools/Python/Exercises/ the next example
*after* Animals_2. The topic of techniques to make a program robust
and maintainable is worth a whole chapter, but it would be a
distraction in the introductory chapter.

I would still like to see a way to gain the benefits of both Animals_2
and Animals_JM in one program. My attempts to follow up on
suggestions in this discussion have only added complexity, not
improved the program.
Simple method - choose a different example. However, you do not
appear to be open to this suggestion.


If I were not open to suggestions, I would not be spending all this
time patiently extracting the good suggestions from this long thread,
and putting up with dogmatic statements and personal attacks. I could
repond by saying most of what I'm reading is hot air, but that would
be equally provocative. Let's see if we can bring this to a better
conclusion.

I like your example, but not as a *substitute* for Animals_2. It's
just too complex for non-CIS students at this point in the course. I
think I understand your concerns about Animals_2. I think the best
way to deal with those concerns is not by complicating the example, or
by taking out everything that could lead to problems, but rather by
pointing out the problems, and showing subsequent examples that fix
those problems, even at the expense of more complexity.

If you have a simple all-in-one alternative to Animals_2, show me.


Again, clearly I have not communicated myself well - I mean a
*completely* different example to the entire Animals approach. The
difficulty with writing a good Animals-type example comes from the
things which it is trying to do, which aren't especially well
expressed by a class-heirarchy.

Why not just take one of your earlier program examples, show the
students what it looks like when object-oriented, then extend the
class(es)?

As I've mentioned, I don't like my example *at all* for your teaching
purposes, and I'm not suggesting you use it. It was simply to
illustrate that there is another method of doing things, and what the
original problems were. (A good solution to the Animals 'problem'
would be simple, it just wouldn't demonstrate any of the things you
want to show.)

We also need to make sure we include *all* children of Reptile in the
new numReptiles function.

class Reptile(Animal):
-numReptiles = 0
def numReptiles():
return ( Reptile._numReptiles +
Snake.numSnakes() + Lizard.numLizards() )

Oops. We forgot Geckos !!

To avoid these errors in programming, we may need a function that
automatically searches for subclasses, and calls their num functions.
I'm not sure how to do this without making it excessively complex.
Suggestions will be appreciated.

-- Dave


Hmm, I think perhaps I like your original example better than this.
:-\ It's a bit like treating a cut throat with a tourniquet.

Searching the subclasses will AFAIK still require some kind of
metaprogramming, which is not too suitable for a 4-hour beginner
course on OO.
Jul 18 '05 #53
On Sat, 22 May 2004 18:28:33 -0000, "Donn Cave" <do**@drizzle.com>
wrote:
Quoth David MacQuigg <dm*@gain.com>:
| 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?

I wouldn't. I would say

"Classes allow you to create objects with their own functions,
called methods, that you write. Each function takes `self'
as its first parameter."

"Here's a class:"
class A:
def __init__(self):
self.data = 'spud'
def hello(self):
print 'Hello, I am a class A', self.data

"Classes can inherit functions from other classes:"
class B(A):
def __init__(self):
self.data = 'gerbil'

"The actual object - a class `instance' - is created by invoking
the class name, applying arguments which will be passed to __init__."
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.
Then I would go over that, showing what happens and why, until the
concepts introduced above seem to be clear for everyone. That would
conclude my treatment of classes. As an elementary language, there
are some slightly hard things to learn about Python, but this isn't
going to be one of them unless you make it hard.


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.

The example I showed is not intended to explain method binding, and I
would not use it in an introduction to OOP. It probably won't even be
"stumbled upon" in a normal program. I posted it only to show that
even experts can get confused by Python's binding syntax. Are you not
confused by this example?

-- Dave

Jul 18 '05 #54
David MacQuigg wrote:
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).
But the above explanation misses one very important point: one is used 99.9% of
the time, the other 0.1% of the time, if that. Mentioning them side by side
like you do implies that they are both equially common, which is not remotely
the case.
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.
I don't see how this is at all related to static methods. A method is some
piece of functionality that is specific to a particular class. If you have some
function already lying around, why would you want it as a method, much less a
static method? (I can think of a couple of rather contrived examples, but
nothing compelling or common in a normal application - help me out here)
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: [snip example that IMO doesn't reflect any sensical use case] How would you explain this to non-CIS students in a class on circuit
design, where there is very little time to discuss programming?


What kind of an instructor would bring this up in an introductory programming
course? If you're short on time, there are oodles and oodles of more commonly
used topics to cover.

I find the current distinction between methods and functions as one that makes
quite a bit of sense. It doesn't really cause problems, and I've yet to see a
proposal that is cleaner while still making as much sense (IOW, perhaps it IS
imperfect, but I can't think of anything better, and apparently nobody else can
either).

Most importantly, I've yet to see it cause any real or lasting problems for
beginners - either (1) nobody cares unless you point it out and make an issue
out of it, or (2) they ask, you take 30 seconds to explain it, and they say,
"oh, ok" and move on. Occasionally someone particularly bright (and/or with
experience in certain other languages) will really grasp the 'why' behind the
difference, and you'll see the light go on as they begin to understand the
power available to them.

-Dave
Jul 18 '05 #55
On Sat, 22 May 2004 12:10:51 -0600, "Dave Brueck"
<da**@pythonapocrypha.com> wrote:
David MacQuigg wrote:
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).
But the above explanation misses one very important point: one is used 99.9% of
the time, the other 0.1% of the time, if that. Mentioning them side by side
like you do implies that they are both equially common, which is not remotely
the case.


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.
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.


I don't see how this is at all related to static methods. A method is some
piece of functionality that is specific to a particular class. If you have some
function already lying around, why would you want it as a method, much less a
static method? (I can think of a couple of rather contrived examples, but
nothing compelling or common in a normal application - help me out here)


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.

See the thread "classes vs dicts" and the discussion following my post
on 5/13 for more on statefiles and Bags. See also
http://www.ece.arizona.edu/~edatools/Python/Statefiles for the latest
on our solution to the statefile problem (how to handle thousands of
deeply-nested setup parameters).
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:

[snip example that IMO doesn't reflect any sensical use case]
How would you explain this to non-CIS students in a class on circuit
design, where there is very little time to discuss programming?


What kind of an instructor would bring this up in an introductory programming
course? If you're short on time, there are oodles and oodles of more commonly
used topics to cover.


Seems like my challenging statement was misleading. I have no
intention of bringing up strange binding problems in an introductory
class. This was a challenge to those who think that Python's binding
syntax is simple. Even an example as strange as this would be no
problem for a student if the new syntax were adopted.
I find the current distinction between methods and functions as one that makes
quite a bit of sense. It doesn't really cause problems, and I've yet to see a
proposal that is cleaner while still making as much sense (IOW, perhaps it IS
imperfect, but I can't think of anything better, and apparently nobody else can
either).
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.
Most importantly, I've yet to see it cause any real or lasting problems for
beginners - either (1) nobody cares unless you point it out and make an issue
out of it, or (2) they ask, you take 30 seconds to explain it, and they say,
"oh, ok" and move on. Occasionally someone particularly bright (and/or with
experience in certain other languages) will really grasp the 'why' behind the
difference, and you'll see the light go on as they begin to understand the
power available to them.


I think there is a tendency to assume that whatever you have learned
is just the way things have to be. I was assuming that about Python
until someone prodded me to look at Ruby. That got me interested in
other languages, like Prothon. It wasn't until I looked at Prothon
that the light came on regarding this unification issue. Until that
time, I was assuming, like everyone else, that static methods, lambda
functions, and lots of other warts were fundamentally necessary.

The best introductory text on Python is Mark Lutz' Learning Python,
2nd ed. He takes 96 pages to cover OOP, and he doesn't waste time on
unnecessary topics like metaclasses. I believe an improvement in
Python's syntax could make it possible to cut the number of pages in
half, and still reach the same level of proficiency in solving
real-world problems. Why is it we can see there is clutter in Perl,
but we can't see it in Python?

-- Dave

Jul 18 '05 #56
On 22 May 2004 11:50:18 -0700, mo******@tcd.ie (James Moughan) wrote:
David MacQuigg <dm*@gain.com> wrote in message news:<9h********************************@4ax.com>. ..
On 19 May 2004 23:26:38 -0700, mo******@tcd.ie (James Moughan) wrote:
>David MacQuigg wrote:
I like your example, but not as a *substitute* for Animals_2. It's
just too complex for non-CIS students at this point in the course. I
think I understand your concerns about Animals_2. I think the best
way to deal with those concerns is not by complicating the example, or
by taking out everything that could lead to problems, but rather by
pointing out the problems, and showing subsequent examples that fix
those problems, even at the expense of more complexity.

If you have a simple all-in-one alternative to Animals_2, show me.

Again, clearly I have not communicated myself well - I mean a
*completely* different example to the entire Animals approach. The
difficulty with writing a good Animals-type example comes from the
things which it is trying to do, which aren't especially well
expressed by a class-heirarchy.


What I am trying to do in Animals_2 is provide the simplest, most
learnable example of Python OOP, which has at least one of every basic
structure the students will encounter in a real program. So I include
bound, unbound, and static methods, but not metaclasses or
descriptors.

Creating a good example like this is turning out to be more of a
challenge than I expected. I'm fairly happy with Animals_2, but I
appreciate the "maintainability" problems you have pointed out, and
have added footnotes accordingly. The examples in Learning Python are
too spread out in little pieces, and of course, no attention to the
issues you are concerned about. If you know of another place I can
look for a good all-in-one teaching example, I am interested.
Why not just take one of your earlier program examples, show the
students what it looks like when object-oriented, then extend the
class(es)?

As I've mentioned, I don't like my example *at all* for your teaching
purposes, and I'm not suggesting you use it. It was simply to
illustrate that there is another method of doing things, and what the
original problems were. (A good solution to the Animals 'problem'
would be simple, it just wouldn't demonstrate any of the things you
want to show.)


Then it wouldn't be a good solution. What I want to show is at least
one of every structure needed in a real program.

I've made your example one of the exercises. It solves a particular
problem, and it is worth showing.
We also need to make sure we include *all* children of Reptile in the
new numReptiles function.

class Reptile(Animal):
-numReptiles = 0
def numReptiles():
return ( Reptile._numReptiles +
Snake.numSnakes() + Lizard.numLizards() )

Oops. We forgot Geckos !!

To avoid these errors in programming, we may need a function that
automatically searches for subclasses, and calls their num functions.
I'm not sure how to do this without making it excessively complex.
Suggestions will be appreciated.

-- Dave


Hmm, I think perhaps I like your original example better than this.
:-\ It's a bit like treating a cut throat with a tourniquet.

Searching the subclasses will AFAIK still require some kind of
metaprogramming, which is not too suitable for a 4-hour beginner
course on OO.


Most likely, we will not cover the solutions to the maintainability
problems, but we will mention them so students are aware. Electronic
design engineers are good at structured, hierarchical, robust design,
so I won't have to spend a lot of time on encapsulation, modularity,
maintainability, etc. They are well aware of the need for protection
circuits on all inputs. Pointing out the problems in a simplified
program example should be sufficient.

-- Dave

Jul 18 '05 #57
David MacQuigg wrote:
But the above explanation misses one very important point: one is used 99.9% of
the time, the other 0.1% of the time, if that. Mentioning them side by side
like you do implies that they are both equially common, which is not remotelythe case.
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.


All I'm saying is that for most programs, the bound method form is way, way,
way more commonly used than is the unbound calling form.
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.
I don't disagree that they are necessary to make the language complete, but
over and over again you have posted examples of the form "here's a bound method
example, here's an unbound method example. They're different". Yes, they're
different, but presenting them that way makes it sound like you normally have
an equal mix of bound and unbound method calls, and that the difference is so
subtle that confusion abounds. Neither is true in practice.
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.


I don't see how this is at all related to static methods. A method is some
piece of functionality that is specific to a particular class. If you have somefunction already lying around, why would you want it as a method, much less astatic method? (I can think of a couple of rather contrived examples, but
nothing compelling or common in a normal application - help me out here)


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.


<sigh> I know what static methods are _for_, but I don't see what is
necessarily complex about them, nor how your proposed unification would help -
in fact, ISTM that it would make it much more confusing because both the
implementor and caller of the code would never be quite sure if the method was
a static one or not, and that's something that needs to be known by both
parties.

Perhaps we both dislike the current staticmethod syntax of Python, but IMO
making a static method look the same as a non-static method seems like a very
wrong thing to do. They are quite different in purpose and construction, so to
me it doesn't make sense that they should look the same in implementation OR in
usage. See, to me it makes sense that there's no 'self' in a static method -
since there's no instance for it to refer to. Likewise, it makes sense to me
that there _is_ a self in a bound method, else member variable lookup would be
magical (certainly more magical than the fact that a bound method knows what
instance it belongs to).
See the thread "classes vs dicts" and the discussion following my post
on 5/13 for more on statefiles and Bags. See also
http://www.ece.arizona.edu/~edatools/Python/Statefiles for the latest
on our solution to the statefile problem (how to handle thousands of
deeply-nested setup parameters).
Yes - I suggested the basis for your current solution. :)
What kind of an instructor would bring this up in an introductory programmingcourse? If you're short on time, there are oodles and oodles of more commonlyused topics to cover.


Seems like my challenging statement was misleading. I have no
intention of bringing up strange binding problems in an introductory
class. This was a challenge to those who think that Python's binding
syntax is simple.


I'd say that first and foremost, it's powerful, and then simple. The example
IMO shows an abuse of the power without a good reason to do so (my reaction to
the example as "you're doing something odd for no good reason, and you get odd
behavior, so what?"). The proposed unification does not seem to take into
account the benefits of the current design - whether by choice or ignorance I
don't know.
Have you read the proposal at
http://www.ece.arizona.edu/~edatools/Python ??
Yep.
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.
Yes it has some value, but more than that: it fits the brain quite well. IMO it
adheres to the principle of least surprise, if you are really thinking about
what is going on (and this is why I haven't found it to be a problem for
newbies, because they usually _aren't_ that interested in precisely what is
going on). And if you're not really thinking about what is going on, it places
a pretty minimal burden on you - there's only a handful of rules a blissfully
ignorant programmer needs to adhere to, and that's pretty amazing. But once you
do understand what is going on, then you can do some pretty powerful things
that you can't do in e.g. Java (at least not directly and not without a lot of
work).
Most importantly, I've yet to see it cause any real or lasting problems for
beginners - either (1) nobody cares unless you point it out and make an issueout of it, or (2) they ask, you take 30 seconds to explain it, and they say,
"oh, ok" and move on. Occasionally someone particularly bright (and/or with
experience in certain other languages) will really grasp the 'why' behind thedifference, and you'll see the light go on as they begin to understand the
power available to them.


I think there is a tendency to assume that whatever you have learned
is just the way things have to be.


Maybe, but I'm not arguing that the way things are is the way things have to
be - I'm arguing that (1) the current way is better than all other proposals to
date and (2) the specific proposal you've put forward introduces more problems
than it solves and possibly results in a less powerful language (but I'm not
sure because I haven't seen examples of how all calling use cases would be
affected).
The best introductory text on Python is Mark Lutz' Learning Python,
2nd ed. He takes 96 pages to cover OOP, and he doesn't waste time on
unnecessary topics like metaclasses. I believe an improvement in
Python's syntax could make it possible to cut the number of pages in
half, and still reach the same level of proficiency in solving real-world problems

But has Mark told you that his goal was brevity? I bet you could cut the pages
in half without ANY changes to the language, not because he did a poor job (he
obviously didn't) but because you have different goals in mind.
Why is it we can see there is clutter in Perl, but we can't see it in Python?


Nobody is taking that stance, as far as I can tell.

-Dave
Jul 18 '05 #58
On Sat, 22 May 2004 14:56:29 -0600, "Dave Brueck"
<da**@pythonapocrypha.com> wrote:
David MacQuigg wrote:
>But the above explanation misses one very important point: one is used 99.9%of >the time, the other 0.1% of the time, if that. Mentioning them side by side
>like you do implies that they are both equially common, which is notremotely >the case.
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.


All I'm saying is that for most programs, the bound method form is way, way,
way more commonly used than is the unbound calling form.


I would agree if you cut out two of the "ways" in this sentence. :>)
Still this is like saying names that start with the letter 'q' are way
less common than all other names, so it is OK if we have a special
form for functions with such names. To take this analogy a step
further, I would say that the "no-q" programmers have somehow gotten
used to this restriction, and work around it without even thinking,
while new users find it annoying to have to go back and fix a few
functions because they didn't remember the "no-q" rule.
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.


I don't disagree that they are necessary to make the language complete, but
over and over again you have posted examples of the form "here's a bound method
example, here's an unbound method example. They're different". Yes, they're
different, but presenting them that way makes it sound like you normally have
an equal mix of bound and unbound method calls, and that the difference is so
subtle that confusion abounds. Neither is true in practice.


I've never stated or implied that unbound methods are as common as
bound methods. Nor would I say that confusion abounds. The different
calling sequences are just an unnecessary complexity that trips up
some new users, especially those that don't have experience in some
other OOP language.
>> 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.
>
>I don't see how this is at all related to static methods. A method is some
>piece of functionality that is specific to a particular class. If you havesome >function already lying around, why would you want it as a method, much lessa >static method? (I can think of a couple of rather contrived examples, but
>nothing compelling or common in a normal application - help me out here)


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.


<sigh> I know what static methods are _for_, but I don't see what is
necessarily complex about them, nor how your proposed unification would help -
in fact, ISTM that it would make it much more confusing because both the
implementor and caller of the code would never be quite sure if the method was
a static one or not, and that's something that needs to be known by both
parties.


I think you have not understood the proposal. It is *not* necessary
in the new syntax to know the difference between a static and
non-static method. There *is* no difference. A "static method" (a
function without instance variables) simply ignores __self__.
Perhaps we both dislike the current staticmethod syntax of Python, but IMO
making a static method look the same as a non-static method seems like a very
wrong thing to do. They are quite different in purpose and construction, so to
me it doesn't make sense that they should look the same in implementation OR in
usage. See, to me it makes sense that there's no 'self' in a static method -
since there's no instance for it to refer to. Likewise, it makes sense to me
that there _is_ a self in a bound method, else member variable lookup would be
magical (certainly more magical than the fact that a bound method knows what
instance it belongs to).
The differences are an artifact of the syntax, not any fundamental
difference in purpose. Normal methods have a special first argument.
Static methods do not. That's all there is to it. That's the way I
think when I write a program, and the way I will minimize the
complexity for my students. I still don't know what "static" means in
this context, but it doesn't matter. It's just a wart I need to add
after I've written a method definition, if it happens that the method
needs to be called without 'self'.

If there is were some fundamental purpose to static methods, there
would be something they can do that can't be done with the proposed
simpler syntax? Can you think of any example?
See the thread "classes vs dicts" and the discussion following my post
on 5/13 for more on statefiles and Bags. See also
http://www.ece.arizona.edu/~edatools/Python/Statefiles for the latest
on our solution to the statefile problem (how to handle thousands of
deeply-nested setup parameters).


Yes - I suggested the basis for your current solution. :)


And I greatly appreciate that suggestion. The statefile format is now
readable enough that we will avoid having to write our own parser. By
the way, I wasn't the only one who missed the obvious solution. An
experienced Python programmer was going down the wrong path with me.
>What kind of an instructor would bring this up in an introductoryprogramming >course? If you're short on time, there are oodles and oodles of morecommonly >used topics to cover.


Seems like my challenging statement was misleading. I have no
intention of bringing up strange binding problems in an introductory
class. This was a challenge to those who think that Python's binding
syntax is simple.


I'd say that first and foremost, it's powerful, and then simple. The example
IMO shows an abuse of the power without a good reason to do so (my reaction to
the example as "you're doing something odd for no good reason, and you get odd
behavior, so what?"). The proposed unification does not seem to take into
account the benefits of the current design - whether by choice or ignorance I
don't know.


I may be wrong, but it looks to me like there *are* no benefits of the
current binding syntax over the proposed syntax.

I don't know the reason behind the "Method Binding Confusion" example,
so I would hesitate to tell someone they don't need to do that. I
assume it was distilled from a much larger program. It does look
simple enough that I can imagine someone stumbling upon it in the
course of writing an ordinary program. In any case, the proposed
syntax can do this without any special effort.

What are the benefits of the current design? What can you do in the
current syntax that can't be done more easily in the proposed syntax?
Show me some code, and I will show you the equivalent in "Python 3".
Have you read the proposal at
http://www.ece.arizona.edu/~edatools/Python ??


Yep.
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.


Yes it has some value, but more than that: it fits the brain quite well. IMO it
adheres to the principle of least surprise,


The Principle of Least Surprise has always been one of my favorites.
It's a shame this principle offers us so little guidance in resolving
a simple issue like this unification question. It seems to be leading
us in opposite directions. I think the difference may be in our
backgrounds. You seem quite comfortable with Java, so I would guess
these different method forms fit with what you have learned there.

I'm coming at it from a different direction -- no CIS background at
all. I see more beauty, more simplicity, and less surprise in having
just one form of function/method -- unless there is something these
various method forms can do, that I can't do with a simpler syntax,
then I would change my mind, and *highlight* the differences with
keywords like "staticmethod" and "lambda". With the new syntax, I
wouldn't even use the word "method".
if you are really thinking about
what is going on (and this is why I haven't found it to be a problem for
newbies, because they usually _aren't_ that interested in precisely what is
going on). And if you're not really thinking about what is going on, it places
a pretty minimal burden on you - there's only a handful of rules a blissfully
ignorant programmer needs to adhere to, and that's pretty amazing. But once you
do understand what is going on, then you can do some pretty powerful things
that you can't do in e.g. Java (at least not directly and not without a lot of
work).


I need to feel like I understand what is going on. I'm not
comfortable with a bunch of arbitrary rules, especially if I
frequently run into cases where forgetting the rules can cause a
problem. With the proposed syntax, I understand binding completely.
I don't even see any wierd little edge cases, like the example from
the "binding confusion" thread. In that example, it should not matter
if we are calling a normal function, a built-in function, a normal
method, or a static method. If the function contains instance
variables ( with a leading dot ), it will look for __self__. If that
variable is not set, you will get an exception. That's all there is
to binding. It doesn't even matter if the function is defined inside
a class, or at the module level. That choice can be determined by
whatever is the best organization of the program.
>Most importantly, I've yet to see it cause any real or lasting problems for
>beginners - either (1) nobody cares unless you point it out and make anissue >out of it, or (2) they ask, you take 30 seconds to explain it, and they say,
>"oh, ok" and move on. Occasionally someone particularly bright (and/or with
>experience in certain other languages) will really grasp the 'why' behindthe >difference, and you'll see the light go on as they begin to understand the
>power available to them.


I think there is a tendency to assume that whatever you have learned
is just the way things have to be.


Maybe, but I'm not arguing that the way things are is the way things have to
be - I'm arguing that (1) the current way is better than all other proposals to
date and (2) the specific proposal you've put forward introduces more problems
than it solves and possibly results in a less powerful language (but I'm not
sure because I haven't seen examples of how all calling use cases would be
affected).


I need specific examples of problems introduced by the new syntax, or
of something the old syntax can do better. We can argue general
principles forever, but one good example will settle this question.

Some of the highly-touted benefits of Prothon, I have concluded are
bunk, and I have eliminated them from my proposal. The total
elimination of all class-like behavior (getting rid of the "two-tier"
class/instance object model) is a case in point. In most programs,
two tiers are very useful. Nobody has even offered a use-case for the
'one-tier" object model of Prothon. As far as I can tell, none of the
"one-tier" advocates have even looked at Michele Simionato's
implementation of prototypes in Python. (comp.lang.python 4/28/04).

In spite of the bunk, we should not dismiss all the ideas in Prothon.
In my opinion, this unification of methods and functions is the one
gem we can distill from the mess. We can learn a lot by looking at
how languages designed *after* Python have tried to improve on it.
The best introductory text on Python is Mark Lutz' Learning Python,
2nd ed. He takes 96 pages to cover OOP, and he doesn't waste time on
unnecessary topics like metaclasses. I believe an improvement in
Python's syntax could make it possible to cut the number of pages in
half, and still reach the same level of proficiency in solving real-world

problems

But has Mark told you that his goal was brevity? I bet you could cut the pages
in half without ANY changes to the language, not because he did a poor job (he
obviously didn't) but because you have different goals in mind.


I assume his goal, like mine, is to teach basic Python with the
minimum time and effort. Brevity is not a goal in itself. There is
an optimum number of pages to explain a given set of topics, and I
think Learning Python is pretty close to that optimum. The reduction
in pages has to come from a reduction in the number of topics.
Why is it we can see there is clutter in Perl, but we can't see it in Python?


Nobody is taking that stance, as far as I can tell.


Nobody seems to understand that lambda functions, static methods, etc.
are clutter.

-- Dave

Jul 18 '05 #59
David MacQuigg <dm*@gain.com> wrote in message news:<pi********************************@4ax.com>. ..
On 23 May 2004 06:18:54 -0700, mo******@tcd.ie (James Moughan) wrote:
David MacQuigg <dm*@gain.com> wrote in message news:<pn********************************@4ax.com>. ..
On 22 May 2004 11:50:18 -0700, mo******@tcd.ie (James Moughan) wrote:

>David MacQuigg <dm*@gain.com> wrote in message news:<9h********************************@4ax.com>. ..
>> On 19 May 2004 23:26:38 -0700, mo******@tcd.ie (James Moughan) wrote:
>> >David MacQuigg wrote:> I like your example, but not as a *substitute* for Animals_2. It's
>> just too complex for non-CIS students at this point in the course. I
>> think I understand your concerns about Animals_2. I think the best
>> way to deal with those concerns is not by complicating the example, or
>> by taking out everything that could lead to problems, but rather by
>> pointing out the problems, and showing subsequent examples that fix
>> those problems, even at the expense of more complexity.
>>
>> If you have a simple all-in-one alternative to Animals_2, show me.
>>
>
>Again, clearly I have not communicated myself well - I mean a
>*completely* different example to the entire Animals approach. The
>difficulty with writing a good Animals-type example comes from the
>things which it is trying to do, which aren't especially well
>expressed by a class-heirarchy.

What I am trying to do in Animals_2 is provide the simplest, most
learnable example of Python OOP, which has at least one of every basic
structure the students will encounter in a real program. So I include
bound, unbound, and static methods, but not metaclasses or
descriptors.

Creating a good example like this is turning out to be more of a
challenge than I expected. I'm fairly happy with Animals_2, but I
appreciate the "maintainability" problems you have pointed out, and
have added footnotes accordingly. The examples in Learning Python are
too spread out in little pieces, and of course, no attention to the
issues you are concerned about. If you know of another place I can
look for a good all-in-one teaching example, I am interested.


Just for the sake of example, this is one of the programs which I
always write while learning a language, written in a way I'd use to
demonstrate OO; all it does is read in a wordlist, then print out
synonyms for user-inputed words. Handy for crosswords. ;-)


<snip examples>

I've posted these examples on our webpage at
http://ece.arizona.edu/~edatools/Python/Examples Let me know if I
should make any changes. These will be very helpful for students to
see alternative styles in programming.

-- Dave


*Shakes head* OK, one change; please change the word synonyms to
anagrams in the text of the programs as well. :) When I write a
program which can algorithmically detect synonyms it'll be really
something...
Jul 18 '05 #60
On Fri, 21 May 2004 05:08:20 -0700, David MacQuigg <dm*@gain.com> wrote:
On Fri, 21 May 2004 13:45:52 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:
I'm still waiting for that one simple example that you say will do it
all, and do it right.


I don't think you should be trying to cram all the features
of OOP into a single example.


I agree. Digestible chunks is the right approach. Animals_1.py is
the first example of classes, including data, methods, instance
variables, and inheritance. Thats a pretty large chunk, but what
makes it digestible is the student's prior knowledge of modules,
functions, and all forms of data.

Animals_2a1.py (the current version) adds more levels to the
hierarchy, a special method __init__, static methods, bound and
unbound methods, the odd scoping rule for class variables, and
_private variables. This is all the basics that students will need if
they will be writing their own classes.

There probably won't be an Animals_3, but instead, "level 3" will be a
bunch of examples to illustrate various techniques, like the robust
programming that JM has been pushing, and maybe some topics from
chapters 21 - 23 of Learning Python.
Also, I worry that the zoo topic will seem contrived. Why
not base your examples on some real problems from your
audience's subject area?


Given the goals of the level one and two examples ( cover all the
basic features in two simple examples ) I think any example will be
contrived. The level 3 examples will be the right place to introduce
real circuit design problems.

If you take some wood and saw off pieces to make a box
with some fasteners, and then you put the leftover pieces
of wood *in* the box, you have pieces of wood with two different
kinds of relationship to the box.

I suspect reflecting on this distinction in terms of your examples
might be fruitful.

I can't spend the time to participate more than stolen moments right now,
so I haven't seen all of the thread. Sorry if I am rehashing something.

Regards,
Bengt Richter
Jul 18 '05 #61
On Sun, 23 May 2004 21:23:43 -0600, "Dave Brueck"
<da**@pythonapocrypha.com> wrote:
David MacQuigg wrote:
>> 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.
>
>All I'm saying is that for most programs, the bound method form is way, way,
>way more commonly used than is the unbound calling form.
I would agree if you cut out two of the "ways" in this sentence. :>)


Well, for kicks I looked at the standard Python library, since I figured it
would have the greatest concentration of unbound method use (my reasoning was
that since it was a library more than a consumer of a library, you'd have lots
of class hierarchies and therefore more occurences of unbound method calls to
super classes. Even in this situation it appears that unbound method calls are
less than 2% of all method calls. The real point is simply that unbound method
calls are pretty rare.


I appreciate your taking the time to actually research this question.
The 2% number for unbound functions doesn't surprise me. It would be
interesting if we could get similar statistics on static methods, but
I suspect the numbers would not be meaningful, given that the
staticmethod syntax is relatively new, and there is a long tradition
in Python of using various alternatives to static methods. New users
tend to copy traditions, which is OK, except that learning those
traditions is time-consuming.

To me, the real question is how often will my kind of users (no prior
experience with Python traditions or OOP, just writing what "comes
natural") - how often will they need a static method? That depends on
the size and complexity of the programs they are working with. My CDP
program will be fairly large, and I am using static methods without
hesitation. I would guess half the programs they will encounter would
have a static method here and there.
Still this is like saying names that start with the letter 'q' are way
less common than all other names, so it is OK if we have a special
form for functions with such names.


Not at all - that's a flawed analogy because variable names can be pretty
arbitrary and interchangable. The different types of function calls, method
invocations, whatever, are neither arbitrary nor interchangable.


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)
I've never stated or implied that unbound methods are as common as
bound methods. Nor would I say that confusion abounds. The different
calling sequences are just an unnecessary complexity that trips up
some new users, especially those that don't have experience in some
other OOP language.


I'm beginning to understand the real root of the disagreement - you see no
value in the differences and therefore see the existence of the differences as
a flaw. But that's just the problem: these are not merely syntactic
differences, but they are semantic - they are different in purpose and in use,
so your suggestion to get rid of them seems very unappealing: from my
perspective you are removing something useful from the language to solve a
"problem" that I've yet to encounter, or seen anyone else encounter (including
new users of the language).
><sigh> I know what static methods are _for_, but I don't see what is
>necessarily complex about them, nor how your proposed unification wouldhelp - >in fact, ISTM that it would make it much more confusing because both the
>implementor and caller of the code would never be quite sure if the methodwas >a static one or not, and that's something that needs to be known by both
>parties.


I think you have not understood the proposal. It is *not* necessary
in the new syntax to know the difference between a static and
non-static method. There *is* no difference. A "static method" (a
function without instance variables) simply ignores __self__.


And this is why the proposal seems so lousy: the difference between a static
and a non-static method is _not_ just a syntactic difference, their existance
is not _caused by_ the syntax. The syntax merely reflects that they are
different things to begin with. They are different tools, different features -
you use them for different things, so making them appear identical to the
maintainer of the code and the caller of the code seems like a really bad
idea - a maintenance nightmare. If you remove any syntactic difference, then
that information is lost from the code itself. But since that info is useful,
people will instead track that info in comments or something - yuck.
The differences are an artifact of the syntax, not any fundamental
difference in purpose. Normal methods have a special first argument.
Static methods do not. That's all there is to it.


No, no, no - they are different tools, plain and simple. The difference just
isn't skin deep - changing the syntax won't make them go away, it'll instead
make the language more ambiguous. Without meaning to be offensive, I must ask:
how much have you actually used any of these features you're interesting in
consolidating? (static method, unbound methods, bound methods, etc.)


I'm new to Python and object-oriented programming. I make no claim of
language expertise or vast programming experience. I'm simply
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.
If there is were some fundamental purpose to static methods, there
would be something they can do that can't be done with the proposed
simpler syntax?


That's just my point: after consolidating the syntax, static methods will still
exist, but there will be no way of knowing which ones are static and which ones
aren't _without reading every line of the code_ - there will be no syntactic
way to express the idea. Egads!
I may be wrong, but it looks to me like there *are* no benefits of the
current binding syntax over the proposed syntax.


Yes, I understand that it looks that way to you, but why is it that so many
people who have used the language for a long time disagree with you? Is it
because everyone else has blinders on? Could it be _possible_ that these
features have value and/or that the solution you propose is worse than what
currently exists?


Saying everyone has blinders is too harsh. It's more like the
particular group of users in this discussion are more advanced than
the users I am concerned about, and the lack of unity in
function/method syntax is a minor issue they have "sailed past"
without even thinking.

I have a similar reaction to problems that bother less technical
users, like the need for a special operator to indicate "floor
division" or the problems with storing decimal fractions in a binary
floating-point number. These all seem pretty obvious to me, yet I
appreciate that Python makes an effort to accomodate these "naive"
users.
Again, how much did you use the language before coming to the
conclusion that you have? see above
What are the benefits of the current design?


I guess my real gripe with the proposal is that it takes what is currently
clear and makes sense and combines it in such a way to make it ambiguous to
everyone involved with the code. The features you propose consolidating really
are different in real programs, and making them all look the same just for the
heck of it doesn't seem to make much sense.
What can you do in the current syntax that can't be done more easily in the

proposed syntax?

Understand my code 6 months from now. Modify the code with less risk.
Understand the level of intent in someone else's code I'm using.


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.

I can see this as a fundamental advantage of the current syntax, but I
would still question the value of this advantage, assuming that static
methods are rare. I would still opt for the unified syntax, and
accept the burden on rare occasions of having to scan the body of a
method (not "read every line") looking for the presence of instance
variables. Perhaps this is why Ruby highlights them with @. I think a
bare leading dot is pretty obvious, but now we're getting down to
personal preference.

If the need to quickly determine if a method is "static" is really an
issue, I would say, don't muck with the standard calling sequence, but
put a special "decorator" on the header line. I think that is being
proposed in PEP 318. Having this decorator could provide the same
fundamental benefit as the statement myMethod =
staticmethod(myMethod), and this does not require a special first
argument.
Show me some code, and I will show you the equivalent in "Python 3".


No, that burden is on your shoulders, as everyone not in favor of your
suggestions can let the thread die off and nothing will change. <0.5 wink> In


You left out a piece of the prior discussion. You said that I was
either ignorant or choosing to ignore the benefits of the current
syntax. My response was "show me" such a benefit. Now you seem to be
saying the burden is on me to show I have thought of everything.
Obviously, I can't do that. Equally obvious is that you could show me
one example of what you are talking about and prove your point.

I think if we both forget about trying to win an argument, and dig for
the facts wherever they may lead, we can avoid these deadlocks.
another thread I suggested you take the time to learn what the 2 or 3 most
common uses are for each of the features that will be affected, and show both
the implementation and use in current Python and after your proposed changes.
Not only will doing this give a clear example to everyone, it'll also show that
you are at least aware of how the different function/method forms are used
today in _real programs_ and not contrived examples - after re-reading some of
your comments I have my doubts.
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?

Again, we can avoid deadlock by focusing on the facts in front of us
and avoiding the argument "I'm a better expert than you, so I win."
We'll either get to the bottom of an issue, or agree that its a matter
of personal preference.
>> 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.
>
>Yes it has some value, but more than that: it fits the brain quite well. IMOit >adheres to the principle of least surprise,


The Principle of Least Surprise has always been one of my favorites.
It's a shame this principle offers us so little guidance in resolving
a simple issue like this unification question.


All of those guiding principles are subjective, but IMO it's pretty clear here
:)

Equally clear from my perspective.
us in opposite directions. I think the difference may be in our
backgrounds. You seem quite comfortable with Java, so I would guess
these different method forms fit with what you have learned there.


I abhor Java, actually, and I'm not even sure how to do the bound method form
in Java (or C++, which is where my background lies more than Java).
I need to feel like I understand what is going on. I'm not
comfortable with a bunch of arbitrary rules


Please understand that these are not arbitrary. The fact that you think they
are arbitrary makes me wonder if you really understand them. Don't be offended!


Again, you deleted the context. This is in response to your statement
that there are only a handful of rules a beginner needs to adhere to.
I do understand most of these rules (all but the strange example
earlier in this thread). However, I would like to eliminate *some* of
them, and keep just one: If you call a function from an insstance, you
get a bound function. Otherwise all references to the function are
unbound. Even the strange example will do exactly what you expect.

Prothon, by the way, eliminates even this rule, following a little too
rigidly the dictum "explicit is better". Their so-called explicit
binding syntax is a mess. I much prefer Python's implicit syntax.
"Practicality beats purity."
What I like about the current syntax, is that you don't really need to memorize
any rules because how you call them is pretty obvious, unless of course you're
not thinking about what you're doing, in which case there are bigger problems
at hand. For example, when I learned Python I never came across some tutorial
showing how to do an unbound method call - I got to the point where I needed
it, I tried the most obvious thing, and it worked. Likewise, the first time I
needed to get a reference to a bound method, I was impressed that the first
thing I tried worked (impressed with the language, not with myself :) ).


It didn't go quite as smoothly for me, probably because I was rushed
on my other projects, and also because I had no prior experience with
OOP. I learned about bound and unbound methods by reading Learning
Python, but it didn't really sink in until I started using them. I
don't expect my students to learn these topics in the short time we
have in class. Most of them will not be writing complete programs, so
I don't expect them to pick it up later, either. Most of them will be
modifying scripts that have been written by someone with more
expertise in Python. A working knowledge of Python up to, but not
including, the OOP chapters is sufficient for most.

My interest in OOP is not only for what it can do in my own programs,
but I see Python OOP as beautiful and elegant (but not perfect), and
something that EE's could really benefit from over their entire
careers. I will be using it heavily in my own programming, but not
expecting my students to learn it. It's right at the edge of what
they need to know to run the circuit design tools. That's why I'm so
interested in simplified OOP, and uninterested in floor division or
metaclasses.
I need specific examples of problems introduced by the new syntax, or
of something the old syntax can do better. We can argue general
principles forever, but one good example will settle this question.


Like I said, if you really are interested in making headway with your proposal,
*you* need to demonstrate through some non-contrived examples that you
understand how things work today. I've read the pages on your site and either
they don't show all cases that will be affected, or the examples are too buried
by other changes so I missed them. So, show a few examples of how bound methods
are implemented and used today in Python, and how they'd be used and
implemented the new way. Show a few examples of how unbound methods are
implemented and used today, etc. Just showing one example and stating that
everything will be like that glosses over the fact that these things are all
used in very different ways today, and leaves the reader wondering if you have
really thought things through.


I think I've done my part on this. The best examples are in
Prototypes.doc at http://ece.arizona.edu/~edatools/Python/
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.)

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.

I think the gap in our perceptions can be bridged by focusing on
examples. I have to do a lot of work to extract from general
criticism and dogmatic statements, anything that I can translate into
a specific example. Anything you can do to clarify your statements
with examples will be greatly appreciated. The 'bag' example was
perfect.
We can learn a lot by looking at
how languages designed *after* Python have tried to improve on it.


Look at the changes to Python, especially over the past few years - many of the
features are publicly credited as having come from other languages.


Yes, and that is one of the things I like about Python. GvR is not
hesitant to make changes when those changes improve the language. I'm
also impressed with the attention to beginners concerns, like the
integer division problem. GvR has a remarkable combination of
language genius and understanding of beginners' problems.

-- Dave

Jul 18 '05 #62
On Mon, 24 May 2004 14:39:11 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:
Nobody seems to understand that lambda functions, static methods, etc.
are clutter.
On the contrary, lambda has long been regarded as a wart
for various reasons. The best way to fix it is probably
to just drop it altogether. Nothing essential would be
lost.


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.
We don't see static methods as clutter, because for the
most part we don't see them (i.e. we don't normally use
them). It would be no great loss if they were dropped,
too.
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.
In neither case is it necessary to fundamentally
redesign the language to fix these, even if
they are regarded as problems.


The proposed change are minimal, and could be done in the next
non-backward compatible upgrade (Python 3?). Unlike Prothon, I am
very concerned about the ability to automatically migrate existing
Python programs to the new syntax. I believe that is possible with
the proposed syntax.

I believe the changes will make it easier for beginners to learn
Python OOP, and at worst, be a minor and temporary annoyance for
experts. I would expect learning the simpler syntax would take an
expert two hours at the most.

-- Dave

Jul 18 '05 #63
On 24 May 2004 03:01:17 -0700, mo******@tcd.ie (James Moughan) wrote:
David MacQuigg <dm*@gain.com> wrote in message news:<pi********************************@4ax.com>. ..

I've posted these examples on our webpage at
http://ece.arizona.edu/~edatools/Python/Examples Let me know if I
should make any changes. These will be very helpful for students to
see alternative styles in programming.

-- Dave


*Shakes head* OK, one change; please change the word synonyms to
anagrams in the text of the programs as well. :) When I write a
program which can algorithmically detect synonyms it'll be really
something...


Done. You can send me an email for little stuff like this that might
not interest the group.

-- Dav
Jul 18 '05 #64
On 24 May 2004 19:44:32 GMT, bo**@oz.net (Bengt Richter) wrote:
On Fri, 21 May 2004 05:08:20 -0700, David MacQuigg <dm*@gain.com> wrote:
On Fri, 21 May 2004 13:45:52 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:
I'm still waiting for that one simple example that you say will do it
all, and do it right.

I don't think you should be trying to cram all the features
of OOP into a single example.
I agree. Digestible chunks is the right approach. Animals_1.py is
the first example of classes, including data, methods, instance
variables, and inheritance. Thats a pretty large chunk, but what
makes it digestible is the student's prior knowledge of modules,
functions, and all forms of data.

Animals_2a1.py (the current version) adds more levels to the
hierarchy, a special method __init__, static methods, bound and
unbound methods, the odd scoping rule for class variables, and
_private variables. This is all the basics that students will need if
they will be writing their own classes.

There probably won't be an Animals_3, but instead, "level 3" will be a
bunch of examples to illustrate various techniques, like the robust
programming that JM has been pushing, and maybe some topics from
chapters 21 - 23 of Learning Python.
Also, I worry that the zoo topic will seem contrived. Why
not base your examples on some real problems from your
audience's subject area?


Given the goals of the level one and two examples ( cover all the
basic features in two simple examples ) I think any example will be
contrived. The level 3 examples will be the right place to introduce
real circuit design problems.

If you take some wood and saw off pieces to make a box
with some fasteners, and then you put the leftover pieces
of wood *in* the box, you have pieces of wood with two different
kinds of relationship to the box.


Spoken like a Zen Master :>)
I suspect reflecting on this distinction in terms of your examples
might be fruitful.

I can't spend the time to participate more than stolen moments right now,
so I haven't seen all of the thread. Sorry if I am rehashing something.


No need for appologies. I appreciate any and all suggestions. Even
better -- a sample program that you think would be right for
introducing students to Python OOP. This can be a piece to add to the
existing box, or even an alternative box. There is room for both.

-- Dave

Jul 18 '05 #65
On Mon, 24 May 2004 13:59:55 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:
Given the goals of the level one and two examples ( cover all the
basic features in two simple examples ) I think any example will be
contrived.


But I don't think you should be trying to cover all the
features of OOP before showing any real examples. That
approach seems almost guaranteed to lose people's interest,
the way you criticised supplier-part examples for.

Wouldn't it be better to do things the other way around?
Pick some (simplified if need be) examples based on
real-world problems, and, one by one, show how the
features of OOP can be used to solve them.


There are lots of ways to write a book. The way I've chosen is
following a pattern which I really liked in Introduction to Quantum
Theory by David Park. He has a brief, but thorough presentation of
all the basics, supplemented by many examples in a second section of
the book. Read a few pages of theory, then read the examples and work
the exercises. The first time through, it takes a while. Then
reviewing the course later is a pleasure.

I think it is possible to present the basics of OOP in 8 pages.
Supplementary topics like robust programming techniques might add a
few more. Examples and exercises could bring the total to 30, maybe
50 pages. We're not planning any discussion of design patterns, which
could fill a whole book. This is basic syntax only.

All of this depends on the students already understanding the topics
prior to Chapter 19, e.g. functions, modules, and global variables.

-- Dave

Jul 18 '05 #66
On Mon, 24 May 2004 14:28:28 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:
On Sat, 22 May 2004 12:10:51 -0600, "Dave Brueck"
But the above explanation misses one very important point: one is used 99.9% of
the time, the other 0.1% of the time, if that.


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. ... Learning Python also treats unbound methods as
much more "normal" than your argument would imply.


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.
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.


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.
Seems like my challenging statement was misleading. I have no
intention of bringing up strange binding problems in an introductory
class. This was a challenge to those who think that Python's binding
syntax is simple.


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

Jul 18 '05 #67
On Mon, 24 May 2004 14:10:44 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:
The need for static methods
will arise when the student first writes a method that needs to work
without a current instance.


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

Jul 18 '05 #68
David MacQuigg wrote:
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.

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Jul 18 '05 #69
David MacQuigg wrote:
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.

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Jul 18 '05 #70
Greg Ewing wrote:
David MacQuigg wrote:
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.

Jul 18 '05 #71
Greg Ewing wrote:
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.
Jul 18 '05 #72
Op 2004-05-22, David MacQuigg schreef <dm*@gain.com>:
On Sat, 22 May 2004 18:28:33 -0000, "Donn Cave" <do**@drizzle.com>
wrote:

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.
Then I would go over that, showing what happens and why, until the
concepts introduced above seem to be clear for everyone. That would
conclude my treatment of classes. As an elementary language, there
are some slightly hard things to learn about Python, but this isn't
going to be one of them unless you make it hard.


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?

--
Antoon Pardon
Jul 18 '05 #73
Op 2004-05-22, David MacQuigg schreef <dm*@gain.com>:
On Thu, 13 May 2004 10:56:58 -0400, "Terry Reedy" <tj*****@udel.edu>
wrote:
"Antoon Pardon" <ap*****@forel.vub.ac.be> wrote in message
news:sl********************@trout.vub.ac.be...
One could argue that all forms of methods and functions are unified.
It is just that python does some magic so that the method you
access from an object is not the actual function but the curried
function with the object.


My view is similar: in Python, a method is a dressed up (wrapped) function.
'Unification of methods and functions' reads to me like 'unification of
dressed-up bodies and naked bodies'. What would that mean? One thing I
like about Python is that there is only function-body syntax and not a
separate, slightly different method-body syntax. To me, having only one
type of code body *is* unification. So it is hard for me to see what is
being proposed. Introducing a syntax like '.var' that would only be
meaningful in a method and not a function would be dis-unification.


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.

--
Antoon Pardon
Jul 18 '05 #74
Op 2004-05-22, David MacQuigg schreef <dm*@gain.com>:
On Sat, 22 May 2004 12:10:51 -0600, "Dave Brueck"
<da**@pythonapocrypha.com> wrote:
David MacQuigg wrote:
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).


But the above explanation misses one very important point: one is used 99.9% of
the time, the other 0.1% of the time, if that. Mentioning them side by side
like you do implies that they are both equially common, which is not remotely
the case.


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.
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.


I don't see how this is at all related to static methods. A method is some
piece of functionality that is specific to a particular class. If you have some
function already lying around, why would you want it as a method, much less a
static method? (I can think of a couple of rather contrived examples, but
nothing compelling or common in a normal application - help me out here)


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.
I find the current distinction between methods and functions as one that makes
quite a bit of sense. It doesn't really cause problems, and I've yet to see a
proposal that is cleaner while still making as much sense (IOW, perhaps it IS
imperfect, but I can't think of anything better, and apparently nobody else can
either).


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.

--
Antoon Pardon
Jul 18 '05 #75
Op 2004-05-24, David MacQuigg schreef <dm*@gain.com>:
On Mon, 24 May 2004 14:39:11 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:
Nobody seems to understand that lambda functions, static methods, etc.
are clutter.


On the contrary, lambda has long been regarded as a wart
for various reasons. The best way to fix it is probably
to just drop it altogether. Nothing essential would be
lost.


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.
We don't see static methods as clutter, because for the
most part we don't see them (i.e. we don't normally use
them). It would be no great loss if they were dropped,
too.


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?

--
Antoon Pardon
Jul 18 '05 #76
On 25 May 2004 07:39:49 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:
Op 2004-05-22, David MacQuigg schreef <dm*@gain.com>:
On Sat, 22 May 2004 12:10:51 -0600, "Dave Brueck"
<da**@pythonapocrypha.com> wrote: <snip>
I don't see how this is at all related to static methods. A method is some
piece of functionality that is specific to a particular class. If you have some
function already lying around, why would you want it as a method, much less a
static method? (I can think of a couple of rather contrived examples, but
nothing compelling or common in a normal application - help me out here)
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.


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.
I find the current distinction between methods and functions as one that makes
quite a bit of sense. It doesn't really cause problems, and I've yet to see a
proposal that is cleaner while still making as much sense (IOW, perhaps it IS
imperfect, but I can't think of anything better, and apparently nobody else can
either).


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.


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

Jul 18 '05 #77
On 25 May 2004 09:46:46 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:
Op 2004-05-24, David MacQuigg schreef <dm*@gain.com>:
On Mon, 24 May 2004 14:39:11 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
We don't see static methods as clutter, because for the
most part we don't see them (i.e. we don't normally use
them). It would be no great loss if they were dropped,
too.


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?


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

Jul 18 '05 #78
On Tue, 25 May 2004 15:31:49 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:
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.


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

Jul 18 '05 #79
Op 2004-05-25, David MacQuigg schreef <dm*@gain.com>:
On 25 May 2004 07:39:49 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:

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.


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.

--
Antoon Pardon
Jul 18 '05 #80
On 25 May 2004 07:08:37 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:
Op 2004-05-22, David MacQuigg schreef <dm*@gain.com>:

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?


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

Jul 18 '05 #81
On 25 May 2004 10:30:03 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:
Op 2004-05-25, David MacQuigg schreef <dm*@gain.com>:
On 25 May 2004 07:39:49 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:

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.


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

Jul 18 '05 #82
Op 2004-05-25, David MacQuigg schreef <dm*@gain.com>:
On 25 May 2004 10:30:03 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:
Op 2004-05-25, David MacQuigg schreef <dm*@gain.com>:
On 25 May 2004 07:39:49 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:

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.


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.


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.

--
Antoon Pardon
Jul 18 '05 #83

David MacQuigg wrote:
On Tue, 25 May 2004 15:31:49 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
David MacQuigg wrote:

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.

<snip>

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.

<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 : be**@cenix-bioscience.com
Cenix Website : http://www.cenix-bioscience.com
Jul 18 '05 #84
David MacQuigg wrote:
Still this is like saying names that start with the letter 'q' are way
less common than all other names, so it is OK if we have a special
form for functions with such names.
Not at all - that's a flawed analogy because variable names can be pretty
arbitrary and interchangable. The different types of function calls, method
invocations, whatever, are neither arbitrary nor interchangable.


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.
What can you do in the current syntax that can't be done more easily in
theproposed syntax?

Understand my code 6 months from now. Modify the code with less risk.
Understand the level of intent in someone else's code I'm using.


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.
another thread I suggested you take the time to learn what the 2 or 3 most
common uses are for each of the features that will be affected, and show boththe implementation and use in current Python and after your proposed changes.Not only will doing this give a clear example to everyone, it'll also show thatyou are at least aware of how the different function/method forms are used
today in _real programs_ and not contrived examples - after re-reading some ofyour comments I have my doubts.


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
Jul 18 '05 #85
On Tue, 25 May 2004 07:17:35 -0600, "Dave Brueck"
<da**@pythonapocrypha.com> wrote:
David MacQuigg wrote:
>> Still this is like saying names that start with the letter 'q' are way
>> less common than all other names, so it is OK if we have a special
>> form for functions with such names.
>
>Not at all - that's a flawed analogy because variable names can be pretty
>arbitrary and interchangable. The different types of function calls, method
>invocations, whatever, are neither arbitrary nor interchangable.
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.


OK, but this issue is definitely not settled.
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.


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.
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.


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.
>> What can you do in the current syntax that can't be done more easily inthe >proposed syntax?
>
>Understand my code 6 months from now. Modify the code with less risk.
>Understand the level of intent in someone else's code I'm using.


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.


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.
>another thread I suggested you take the time to learn what the 2 or 3 most
>common uses are for each of the features that will be affected, and showboth >the implementation and use in current Python and after your proposedchanges. >Not only will doing this give a clear example to everyone, it'll also showthat >you are at least aware of how the different function/method forms are used
>today in _real programs_ and not contrived examples - after re-reading someof >your comments I have my doubts.


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).


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".
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.


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.
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.


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

Jul 18 '05 #86
On Tue, 25 May 2004 07:17:35 -0600, "Dave Brueck"
<da**@pythonapocrypha.com> wrote:
David MacQuigg wrote:

>another thread I suggested you take the time to learn what the 2 or 3 most
>common uses are for each of the features that will be affected, and show both
>the implementation and use in current Python and after your proposed changes.
>Not only will doing this give a clear example to everyone, it'll also show that
>you are at least aware of how the different function/method forms are used
>today in _real programs_ and not contrived examples - after re-reading some of
>your comments I have my doubts.


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).


I've put some simple examples comparing Python 2 to the proposed
Unified Function Syntax at http://ece.arizona.edu/~edatools/Python
These are all pretty simple, and show just the changes necessary to
unify functions and methods. More examples are welcome. Send me
anything you think will be difficult to translate to the new syntax.

I've also moved the Appendix 1: Translating Python Classes from
Prototypes.doc to PrototypeSyntax.doc. These are "edge cases".
Unlike the simple examples above, the purpose is to show that all the
existing classes in Python can be migrated to the proposed syntax.

-- Dave
Jul 18 '05 #87
Neil Benn wrote:
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.


I don't see it that way. To me, using a module namespace is
an alternative way of expressing the same link. A naming
convention for functions (make_dodo, first_dodo,
extinctify_dodos) would be a third way of expressing the
link.

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Jul 18 '05 #88
Op 2004-05-25, Antoon Pardon schreef <ap*****@forel.vub.ac.be>:
Op 2004-05-25, David MacQuigg schreef <dm*@gain.com>:
On 25 May 2004 10:30:03 GMT, Antoon Pardon <ap*****@forel.vub.ac.be>
wrote:
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


Now any normal function can be turned into a higher
order function with a related functionality. Supose
we have a function with the following signature in
python

def func(a1, a2, a3):
We can then write the higher order function as
follows:

def Hfunc(a1):

def Ifunc(a2, a3):

return func(a1, a2, a3)

return Ifunc
Now transforming a function to a higher order
equivallent is called currying and currying is
again a higher order function. In python we
write it as follows

def curry(f):

def Hf(a1):

def If(*ta):

la = (a1,) + ta
return apply(f, la)

return If

return Hf
So from now on if we have a function we can turn it
into its curried version as follows:

Hfunc = curry(func)
So now we have all we need for object oriented programming.
To illustrate I'll make a stack pseudo class. We start
with the assumption that we have the following class.

class Bare:
pass
First approach
def Stack():

st = Bare()
st.lst = []
return st
def Empty(st):

return len(st.lst) == 0
def Pop(st):

result = st.lst[-1]
del st.lst[-1]
return result
def Push(st, el):

st.lst.append(el)

stack = Stack()
Push(stack, 4)
Push(stack, 'hallo')
El = Pop(stack)
This is a strickt procedural approach. It has the disadvantages that the
procedures Empty, Pop and Push aren't very tied to the stack and that
we therefore prohibit other structures the use of the same name
We can eliminate these disadvantages as follows:
Second approach
def Stack():

def Empty(st):

return len(st.lst) == 0
def Pop(st):

result = st.lst[-1]
del st.lst[-1]
return result
def Push(st, el):

st.lst.append(el)
st = Bare()
st.lst = []
st.Empty = Empty
st.Pop = Pop
st.Push = Push
return st
stack = Stack()
stack.Push(stack, 4)
stack.Push(stack, 'hallo')
El = stack.Pop(stack)
This looks already somewhat object oriented. The problem here
is that you are essentially obligated to allways provide the
first argument twice. To eliminate this cumbersome repetition
we work with applied curried functions as methods.
Third approach

def Stack():

def Empty(st):

return len(st.lst) == 0
def Pop(st):

result = st.lst[-1]
del st.lst[-1]
return result
def Push(st, el):

st.lst.append(el)
st = Bare()
st.lst = []
st.Empty = curry(Empty)(st)
st.Pop = curry(Pop)(st)
st.Push = curry(Push)(st)
return st
stack = Stack()
stack.Push(4)
stack.Push('hallo')
El = stack.Pop()
And we now have standard python method calls. We will just
make some cosmetic changes here to have it resemble python
class conventions more.
Fourth approach

def Stack():

def __init__(self):

self.lst = []

def Empty(self):

return len(self.lst) == 0
def Pop(self):

result = self.lst[-1]
del self.lst[-1]
return result
def Push(self, el):

self.lst.append(el)
self = Bare()
__init__(self)
self.Empty = curry(Empty)(self)
self.Pop = curry(Pop)(self)
self.Push = curry(Push)(self)
return self
stack = Stack()
stack.Push(4)
stack.Push('hallo')
El = stack.Pop()
And this is more or less equivallent to:
class Stack():

def __init__(self):

self.lst = []

def Empty(self):

return len(self.lst) == 0
def Pop(self):

result = self.lst[-1]
del self.lst[-1]
return result
def Push(self, el):

self.lst.append(el)
stack = Stack()
stack.Push(4)
stack.Push('hallo')
El = stack.Pop()
--
Antoon Pardon
Jul 18 '05 #89
On Wed, 26 May 2004 13:59:33 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
Neil Benn wrote:
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.


I don't see it that way. To me, using a module namespace is
an alternative way of expressing the same link. A naming
convention for functions (make_dodo, first_dodo,
extinctify_dodos) would be a third way of expressing the
link.


To summarize our discussion on static methods, we have four ways to
accomplish the purpose of making a method callable without an
instance.

1) Add the staticmethod wrapper.
2) Create a dummy instance, and use it to call the method.
3) Move the method outside of the class, and if that disturbs the
modular structure of the program, make the class and its external
function a new module with its own namespace.
4) Move the method outside of the class, but make sure it is still
"associated" with the class by giving it a special name.

Is there any reason we *should not* use solution #1?

-- Dave

Jul 18 '05 #90
David MacQuigg <dm*@gain.com> wrote in
news:eu********************************@4ax.com:
To summarize our discussion on static methods, we have four ways to
accomplish the purpose of making a method callable without an
instance.

1) Add the staticmethod wrapper.
2) Create a dummy instance, and use it to call the method.
3) Move the method outside of the class, and if that disturbs the
modular structure of the program, make the class and its external
function a new module with its own namespace.
4) Move the method outside of the class, but make sure it is still
"associated" with the class by giving it a special name.

Is there any reason we *should not* use solution #1?


You missed 5) Use a classmethod wrapper.

The commonest reason I know of for wanting to a method callable without an
instance is to provide the class with factory functions, and in that case
you definitely don't want to use solution #1 as solution #5 gives you
support for subclassing at no extra charge.

Jul 18 '05 #91
On 28 May 2004 08:10:46 GMT, Duncan Booth <me@privacy.net> wrote:
David MacQuigg <dm*@gain.com> wrote in
news:eu********************************@4ax.com :
To summarize our discussion on static methods, we have four ways to
accomplish the purpose of making a method callable without an
instance.

1) Add the staticmethod wrapper.
2) Create a dummy instance, and use it to call the method.
3) Move the method outside of the class, and if that disturbs the
modular structure of the program, make the class and its external
function a new module with its own namespace.
4) Move the method outside of the class, but make sure it is still
"associated" with the class by giving it a special name.

Is there any reason we *should not* use solution #1?


You missed 5) Use a classmethod wrapper.

The commonest reason I know of for wanting to a method callable without an
instance is to provide the class with factory functions, and in that case
you definitely don't want to use solution #1 as solution #5 gives you
support for subclassing at no extra charge.


I haven't added any classmethod examples to my OOP chapter, because
until now I've thought of them as very specialized. I'm searching for
a good textbook example, but all I can find is trivially replacable
with an instance method or a static method. If you have an instance
already, the class can be resolved via self.__class__. If you don't
have an instance, the desired class can be passed as an argument to a
static method.

I sounds like you may have a good use case for classmethods. Could
you give us an example, and a brief explanation of what it does that
can't be done as easily with other method forms? Your help will be
greatly appreciated.

-- Dave

Jul 18 '05 #92
David MacQuigg <dm*@gain.com> wrote in
news:o1********************************@4ax.com:
I haven't added any classmethod examples to my OOP chapter, because
until now I've thought of them as very specialized. I'm searching for
a good textbook example, but all I can find is trivially replacable
with an instance method or a static method. If you have an instance
already, the class can be resolved via self.__class__. If you don't
have an instance, the desired class can be passed as an argument to a
static method.
I find that slightly surprising. You say that if you have a static method
you can pass the class as a parameter, but since you already specify the
class somewhere to access the static method surely you are duplicating
information unneccessarily? You could equally say that static methods
aren't needed because you can always use a class method and just ignore the
class parameter if you don't need it.

I sounds like you may have a good use case for classmethods. Could
you give us an example, and a brief explanation of what it does that
can't be done as easily with other method forms? Your help will be
greatly appreciated.


Ok, I'll try and give you a couple of examples, feel free to tear them
apart. The most obvious one is to write factory methods:

-------- begin cut ---------------
class Shape(object):
def __init__(self):
super(Shape, self).__init__()
self.moveTo(0, 0)
self.resize(10, 10)

def __repr__(self):
return "<%s instance at %s x=%s y=%s width=%s height=%s>" % (
self.__class__.__name__, id(self),
self.x, self.y, self.width, self.height)

def moveTo(self, x, y):
self.x, self.y = x, y

def resize(self, width, height):
self.width, self.height = width, height

# Factory methods
def fromCenterAndSize(cls, cx, cy, width, height):
self = cls()
self.moveTo(cx, cy)
self.resize(width, height)
return self
fromCenterAndSize = classmethod(fromCenterAndSize)

def fromTLBR(cls, top, left, bottom, right):
self = cls()
self.moveTo((left+right)/2., (top+bottom)/2.)
self.resize(right-left, top-bottom)
return self
fromTLBR = classmethod(fromTLBR)

class Rectangle(Shape): pass
class Ellipse(Shape): pass

print Rectangle.fromCenterAndSize(10, 10, 3, 4)
print Ellipse.fromTLBR(20, 0, 0, 30)
squares = [ Rectangle.fromCenterAndSize(i, j, 1, 1)
for i in range(2) for j in range(2) ]
print squares
-------- end cut ------------
Running this code gives something like:

<Rectangle instance at 9322032 x=10 y=10 width=3 height=4>
<Ellipse instance at 9322032 x=15.0 y=10.0 width=30 height=20>
[<Rectangle instance at 9321072 x=0 y=0 width=1 height=1>, <Rectangle
instance at 9320016 x=0 y=1 width=1 height=1>, <Rectangle instance at
9321200 x=1 y=0 width=1 height=1>, <Rectangle instance at 9321168 x=1 y=1
width=1 height=1>]

The important point is that the factory methods create objects of the
correct type.

The shape class has two factory methods here. Either one of them could
actually be moved into the initialiser, but since they both take the same
number and type of parameters any attempt to move them both into the
initialiser would be confusing at best. the factory methods give me two
clear ways to create a Shape, and it is obvious from the call which one I
am using.

Shape is clearly intended to be a base class, so I created a couple of
derived classes. Each derived class inherits the factory methods, or can
override them if it needs. Instance methods won't do here, as you want a
single call to create and initialise the objects. Static methods won't do
as unless you duplicated the class in the call you can't create an object
of the appropriate type.

My second example carries on from the first. Sometimes you want to count or
even find all existing objects of a particular class. You can do this
easily enough for a single class using weak references and a static method
to retrieve the count or the objects, but if you want to do it for several
classes, and want to avoid duplicating the code, class methods make the job
fairly easy.
--------- begin cut -------------
from weakref import WeakValueDictionary

class TrackLifetimeMixin(object):
def __init__(self):
cls = self.__class__
if '_TrackLifetimeMixin__instances' not in cls.__dict__:
cls.__instances = WeakValueDictionary()
cls.__instancecount = 0
cls.__instances[id(self)] = self
cls.__instancecount += 1

def __getInstances(cls):
return cls.__dict__.get('_TrackLifetimeMixin__instances' , {})
__getInstances = classmethod(__getInstances)

def getLiveInstances(cls):
instances = cls.__getInstances().values()
for k in cls.__subclasses__():
instances.extend(k.getLiveInstances())
return instances
getLiveInstances = classmethod(getLiveInstances)

def getLiveInstanceCount(cls):
count = len(cls.__getInstances())
for k in cls.__subclasses__():
count += k.getLiveInstanceCount()
return count
getLiveInstanceCount = classmethod(getLiveInstanceCount)

def getTotalInstanceCount(cls):
count = cls.__dict__.get('_TrackLifetimeMixin__instancecou nt' , 0)
for k in cls.__subclasses__():
count += k.getTotalInstanceCount()
return count
getTotalInstanceCount = classmethod(getTotalInstanceCount)
class Shape(TrackLifetimeMixin, object):
def __init__(self):
super(Shape, self).__init__()
self.moveTo(0, 0)
self.resize(10, 10)

def __repr__(self):
return "<%s instance at %s x=%s y=%s width=%s height=%s>" % (
self.__class__.__name__, id(self),
self.x, self.y, self.width, self.height)

def moveTo(self, x, y):
self.x, self.y = x, y

def resize(self, width, height):
self.width, self.height = width, height

# Factory methods
def fromCenterAndSize(cls, cx, cy, width, height):
self = cls()
self.moveTo(cx, cy)
self.resize(width, height)
return self
fromCenterAndSize = classmethod(fromCenterAndSize)

def fromTLBR(cls, top, left, bottom, right):
self = cls()
self.moveTo((left+right)/2., (top+bottom)/2.)
self.resize(right-left, top-bottom)
return self
fromTLBR = classmethod(fromTLBR)

class Rectangle(Shape): pass
class Ellipse(Shape): pass

print Rectangle.fromCenterAndSize(10, 10, 3, 4)
print Ellipse.fromTLBR(20, 0, 0, 30)
squares = [ Rectangle.fromCenterAndSize(i, j, 1, 1) for i in range(2) for j
in range(2) ]

print Shape.getLiveInstances()
for cls in Shape, Rectangle, Ellipse:
print cls.__name__, "instances:", cls.getLiveInstanceCount(), \
"now, ", cls.getTotalInstanceCount(), "total"
--------- end cut -------------

The middle part of this file is unchanged. I've added a new mixin class at
the top, but the class Shape is unchanged except that it now includes the
mixin class in its bases. The last 4 lines are also new and print a few
statistics about the classes Shape, Rectangle, Ellipse:

<Rectangle instance at 9376016 x=10 y=10 width=3 height=4>
<Ellipse instance at 9376016 x=15.0 y=10.0 width=30 height=20>
[<Rectangle instance at 9376240 x=0 y=0 width=1 height=1>, <Rectangle
instance at 9376272 x=0 y=1 width=1 height=1>, <Rectangle instance at
9376336 x=1 y=1 width=1 height=1>, <Rectangle instance at 9376304 x=1 y=0
width=1 height=1>]
Shape instances: 4 now, 6 total
Rectangle instances: 4 now, 5 total
Ellipse instances: 0 now, 1 total

Jul 18 '05 #93
On 29 May 2004 16:31:38 GMT, Duncan Booth <me@privacy.net> wrote:
David MacQuigg <dm*@gain.com> wrote in
news:o1********************************@4ax.com :
I haven't added any classmethod examples to my OOP chapter, because
until now I've thought of them as very specialized. I'm searching for
a good textbook example, but all I can find is trivially replacable
with an instance method or a static method. If you have an instance
already, the class can be resolved via self.__class__. If you don't
have an instance, the desired class can be passed as an argument to a
static method.
I find that slightly surprising. You say that if you have a static method
you can pass the class as a parameter, but since you already specify the
class somewhere to access the static method surely you are duplicating
information unneccessarily? You could equally say that static methods
aren't needed because you can always use a class method and just ignore the
class parameter if you don't need it.


The information is duplicate only if the class we want to pass in is
the always the same as the class in which the method is defined, in
which case, we would just hard-code the class name in the method.

class Mammal(Animal):
def cmeth(cls, *args):
print cls, args
cm = classmethod(cmeth)
def smeth(cls, *args):
print cls, args
sm = staticmethod(smeth)

Using a classmethod:
Mammal.cm() <class '__main__.Mammal'> () Feline.cm() <class '__main__.Feline'> ()

Using a staticmethod: msm = Mammal.sm # type "redundant" info only once
msm(Mammal) <class '__main__.Mammal'> () msm(Feline)
<class '__main__.Feline'> ()

You are right, we could just ignore the cls argument in the
classmethod, and avoid the need to learn staticmethods, but between
the two, I would rather use staticmethod, as it is simpler in most
cases.

What would be nice is if we had a variable like __class__ that would
work in any method form. Then we would not need a special first
argument for classmethods, or any special method form at all for this
purpose.
I sounds like you may have a good use case for classmethods. Could
you give us an example, and a brief explanation of what it does that
can't be done as easily with other method forms? Your help will be
greatly appreciated.


Ok, I'll try and give you a couple of examples, feel free to tear them
apart. The most obvious one is to write factory methods:


I like these examples, and I think they will fit nicely into the
teaching sequence -- Spam and Foo, Animals_1, Animals_2, then some
real programs. I would change the classmethods to staticmethods,
however, and avoid the need to teach classmethods. This would make
your calls look like:

print Shape.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
-- or if you prefer a short alias --
print CS(Rectangle, 10, 10, 3, 4)

-- Dave

-------- begin cut ---------------
class Shape(object):
def __init__(self):
super(Shape, self).__init__()
self.moveTo(0, 0)
self.resize(10, 10)

def __repr__(self):
return "<%s instance at %s x=%s y=%s width=%s height=%s>" % (
self.__class__.__name__, id(self),
self.x, self.y, self.width, self.height)

def moveTo(self, x, y):
self.x, self.y = x, y

def resize(self, width, height):
self.width, self.height = width, height

# Factory methods
def fromCenterAndSize(cls, cx, cy, width, height):
self = cls()
self.moveTo(cx, cy)
self.resize(width, height)
return self
fromCenterAndSize = classmethod(fromCenterAndSize)

def fromTLBR(cls, top, left, bottom, right):
self = cls()
self.moveTo((left+right)/2., (top+bottom)/2.)
self.resize(right-left, top-bottom)
return self
fromTLBR = classmethod(fromTLBR)

class Rectangle(Shape): pass
class Ellipse(Shape): pass

print Rectangle.fromCenterAndSize(10, 10, 3, 4)
print Ellipse.fromTLBR(20, 0, 0, 30)
squares = [ Rectangle.fromCenterAndSize(i, j, 1, 1)
for i in range(2) for j in range(2) ]
print squares
-------- end cut ------------
Running this code gives something like:

<Rectangle instance at 9322032 x=10 y=10 width=3 height=4>
<Ellipse instance at 9322032 x=15.0 y=10.0 width=30 height=20>
[<Rectangle instance at 9321072 x=0 y=0 width=1 height=1>, <Rectangle
instance at 9320016 x=0 y=1 width=1 height=1>, <Rectangle instance at
9321200 x=1 y=0 width=1 height=1>, <Rectangle instance at 9321168 x=1 y=1
width=1 height=1>]

The important point is that the factory methods create objects of the
correct type.

The shape class has two factory methods here. Either one of them could
actually be moved into the initialiser, but since they both take the same
number and type of parameters any attempt to move them both into the
initialiser would be confusing at best. the factory methods give me two
clear ways to create a Shape, and it is obvious from the call which one I
am using.

Shape is clearly intended to be a base class, so I created a couple of
derived classes. Each derived class inherits the factory methods, or can
override them if it needs. Instance methods won't do here, as you want a
single call to create and initialise the objects. Static methods won't do
as unless you duplicated the class in the call you can't create an object
of the appropriate type.

My second example carries on from the first. Sometimes you want to count or
even find all existing objects of a particular class. You can do this
easily enough for a single class using weak references and a static method
to retrieve the count or the objects, but if you want to do it for several
classes, and want to avoid duplicating the code, class methods make the job
fairly easy.
--------- begin cut -------------
from weakref import WeakValueDictionary

class TrackLifetimeMixin(object):
def __init__(self):
cls = self.__class__
if '_TrackLifetimeMixin__instances' not in cls.__dict__:
cls.__instances = WeakValueDictionary()
cls.__instancecount = 0
cls.__instances[id(self)] = self
cls.__instancecount += 1

def __getInstances(cls):
return cls.__dict__.get('_TrackLifetimeMixin__instances' , {})
__getInstances = classmethod(__getInstances)

def getLiveInstances(cls):
instances = cls.__getInstances().values()
for k in cls.__subclasses__():
instances.extend(k.getLiveInstances())
return instances
getLiveInstances = classmethod(getLiveInstances)

def getLiveInstanceCount(cls):
count = len(cls.__getInstances())
for k in cls.__subclasses__():
count += k.getLiveInstanceCount()
return count
getLiveInstanceCount = classmethod(getLiveInstanceCount)

def getTotalInstanceCount(cls):
count = cls.__dict__.get('_TrackLifetimeMixin__instancecou nt' , 0)
for k in cls.__subclasses__():
count += k.getTotalInstanceCount()
return count
getTotalInstanceCount = classmethod(getTotalInstanceCount)
class Shape(TrackLifetimeMixin, object):
def __init__(self):
super(Shape, self).__init__()
self.moveTo(0, 0)
self.resize(10, 10)

def __repr__(self):
return "<%s instance at %s x=%s y=%s width=%s height=%s>" % (
self.__class__.__name__, id(self),
self.x, self.y, self.width, self.height)

def moveTo(self, x, y):
self.x, self.y = x, y

def resize(self, width, height):
self.width, self.height = width, height

# Factory methods
def fromCenterAndSize(cls, cx, cy, width, height):
self = cls()
self.moveTo(cx, cy)
self.resize(width, height)
return self
fromCenterAndSize = classmethod(fromCenterAndSize)

def fromTLBR(cls, top, left, bottom, right):
self = cls()
self.moveTo((left+right)/2., (top+bottom)/2.)
self.resize(right-left, top-bottom)
return self
fromTLBR = classmethod(fromTLBR)

class Rectangle(Shape): pass
class Ellipse(Shape): pass

print Rectangle.fromCenterAndSize(10, 10, 3, 4)
print Ellipse.fromTLBR(20, 0, 0, 30)
squares = [ Rectangle.fromCenterAndSize(i, j, 1, 1) for i in range(2) for j
in range(2) ]

print Shape.getLiveInstances()
for cls in Shape, Rectangle, Ellipse:
print cls.__name__, "instances:", cls.getLiveInstanceCount(), \
"now, ", cls.getTotalInstanceCount(), "total"
--------- end cut -------------

The middle part of this file is unchanged. I've added a new mixin class at
the top, but the class Shape is unchanged except that it now includes the
mixin class in its bases. The last 4 lines are also new and print a few
statistics about the classes Shape, Rectangle, Ellipse:

<Rectangle instance at 9376016 x=10 y=10 width=3 height=4>
<Ellipse instance at 9376016 x=15.0 y=10.0 width=30 height=20>
[<Rectangle instance at 9376240 x=0 y=0 width=1 height=1>, <Rectangle
instance at 9376272 x=0 y=1 width=1 height=1>, <Rectangle instance at
9376336 x=1 y=1 width=1 height=1>, <Rectangle instance at 9376304 x=1 y=0
width=1 height=1>]
Shape instances: 4 now, 6 total
Rectangle instances: 4 now, 5 total
Ellipse instances: 0 now, 1 total


Jul 18 '05 #94
David MacQuigg <dm*@gain.com> wrote in
news:qa********************************@4ax.com:
Ok, I'll try and give you a couple of examples, feel free to tear them
apart. The most obvious one is to write factory methods:


I like these examples, and I think they will fit nicely into the
teaching sequence -- Spam and Foo, Animals_1, Animals_2, then some
real programs. I would change the classmethods to staticmethods,
however, and avoid the need to teach classmethods. This would make
your calls look like:

print Shape.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
-- or if you prefer a short alias --
print CS(Rectangle, 10, 10, 3, 4)


So how do you handle the case where you need to override one of the factory
methods in a subclass?

e.g. Rather contortedly:

class OffsetRectangle(Rectangle):
'''A rectangle where the 'center' is actually half way up
the left edge'''
def fromCenterAndSize(cls, cx, cy, width, height):
self = cls()
self.moveTo(cx+width/2.0, cy)
self.resize(width, height)
return self
fromCenterAndSize = classmethod(fromCenterAndSize)

print OffsetRectangle.fromCenterAndSize(5, 10, 10, 10)
Jul 18 '05 #95
On 30 May 2004 10:51:44 GMT, Duncan Booth <me@privacy.net> wrote:
David MacQuigg <dm*@gain.com> wrote in
news:qa********************************@4ax.com :
Ok, I'll try and give you a couple of examples, feel free to tear them
apart. The most obvious one is to write factory methods:


I like these examples, and I think they will fit nicely into the
teaching sequence -- Spam and Foo, Animals_1, Animals_2, then some
real programs. I would change the classmethods to staticmethods,
however, and avoid the need to teach classmethods. This would make
your calls look like:

print Shape.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
-- or if you prefer a short alias --
print CS(Rectangle, 10, 10, 3, 4)


So how do you handle the case where you need to override one of the factory
methods in a subclass?

e.g. Rather contortedly:


I'm not sure what this modification is intended to do, but assuming it
must work with multiple subclasses of OffsetRectangle, I would write
the example as follows:

class OffsetRectangle(Rectangle):
'''A rectangle where the 'center' is actually half way up
the left edge'''
def fromCenterAndSize(cls, cx, cy, width, height):
self = cls()
self.moveTo(cx+width/2.0, cy)
self.resize(width, height)
return self
## fromCenterAndSize = classmethod(fromCenterAndSize)
frmCenterAndSize = staticmethod(fromCenterAndSize)

class Rect1(OffsetRectangle): pass
class Rect2(OffsetRectangle): pass
class Rect3(OffsetRectangle): pass

for cls in Rect1, Rect2, Rect3, Rectangle:
print OffsetRectangle.fromCenterAndSize(cls, 5, 10, 10, 10)

On the other hand, if you don't want to use the specific method from
OffsetRectangle, but you want the method to be chosen from the same
class as the class being instantiated, the last line would be:

print cls.fromCenterAndSize(cls, 5, 10, 10, 10)

I may be missing your intent. If so, maybe you could show a more
complete example.

-- Dave

Jul 18 '05 #96
David MacQuigg <dm*@gain.com> wrote in
news:0d********************************@4ax.com:
I may be missing your intent. If so, maybe you could show a more
complete example.
Ok, let me try to clarify again.

I am suggesting that we write factory methods using classmethod to give
code like:

Rectangle.fromCenterAndSize(10, 10, 3, 4)
Ellipse.fromCenterAndSize(10, 10, 3, 4)
OffsetRectangle.fromCenterAndSize(10, 10, 3, 4)
TextLabel.fromCenterAndSize(10, 10, 3, 4)

and as I understand it, you would prefer to use static methods and
write:

Shape.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
Shape.fromCenterAndSize(Ellipse, 10, 10, 3, 4)
Shape.fromCenterAndSize(OffsetRectangle, 10, 10, 3, 4)
Shape.fromCenterAndSize(TextLabel, 10, 10, 3, 4)

In the hope that I'm right so far, I'll try to list some of the ways
that I believe my code is a better way to implement this sort of scheme.

First off, my classes all implement an interface which I'll call 'shape
factory'. Interfaces in Python aren't declared explicitly, but that
doesn't stop me claiming that I have one. Any class which implements
shape factory can be instanciated in a consistent manner.

Secondly, the implementation is hidden. I might tell you here that
Rectangle and Ellipse have a common base class, OffsetRectangle
subclasses Rectangle, and TextLabel doesn't share the same base class as
the others (perhaps it doesn't have any other methods in common), but
this would just be irrelevant information and any other relationship
between the classes would work just so long as each continued to
implement the shape factory interface.

I'm sure we both know the difference between a base class and an
interface, but, just to check we are communicating, I'm going to spell
out what I think is the important distinction:

An interface lets multiple classes share functionality or services that
they offer. A base class lets multiple classes share common
implementations of code. A base class need not supply any public
interface; indeed a base class might expose a public interface which
derived classes do not expose.

I think this is important, as you rarely want to write code where the
common implementation is the important thing; usually its the common set
of services that are important. Even in languages such as C++ and Java
it is better to write code that accepts objects which implement an
interface rather than code which requires objects to have a specific
base class.

The final point I want to make about my code, and I admit it is less
important, is that the factory methods can be passed around just like
any other method. I could have a dict mapping object name to factory
method and create any of the objects in my system simply by calling the
saved method.

Back to your way of doing things:

Shape.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
Shape.fromCenterAndSize(Ellipse, 10, 10, 3, 4)
Shape.fromCenterAndSize(OffsetRectangle, 10, 10, 3, 4)
Shape.fromCenterAndSize(TextLabel, 10, 10, 3, 4)

I may have some problems communicating my intent here. How do I know
which classes it is valid to pass to Shape.fromCenterAndSize? My classes
no longer have any common interface.

Oops. Did I mention that TextLabel is an unrelated class and doesn't
have the same methods as Shape? Shape.fromCenterAndSize calls the resize
method, but my TextLabel class has a setFont method instead, so that
code is going to throw an AttributeError. Fortunately, that is easily
fixed:

Shape.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
Shape.fromCenterAndSize(Ellipse, 10, 10, 3, 4)
Shape.fromCenterAndSize(OffsetRectangle, 10, 10, 3, 4)
TextLabel.fromCenterAndSize(TextLabel, 10, 10, 3, 4)

Sadly, it looks as though the implementation, which I presume we would like
to hide, is beginning to be significant.

The code may now execute with throwing an exception, but I just spotted
a worse problem. The OffsetRectangle object has its own implementation
of fromCenterAndSize, so while you can construct it through the Shape
class you get the wrong values stored. You can fix that in the same way
as before, but there is still a deadly trap for the unwary: anyone who
accidentally calls the factory method in Shape will silently get the
wrong results:

Shape.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
Shape.fromCenterAndSize(Ellipse, 10, 10, 3, 4)
OffsetRectangle.fromCenterAndSize(OffsetRectangle, 10, 10, 3, 4)
TextLabel.fromCenterAndSize(TextLabel, 10, 10, 3, 4)

Now my problem is the inconsistency of the code, the underlying
implementation has become all important. Why should I be calling
the method on Shape for two of the classes, and on the classes
themselves for the other two? How am I going to remember which is which?
Fortunately there is nothing stopping us from using the derived class
for the call:

Rectangle.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
Ellipse.fromCenterAndSize(Ellipse, 10, 10, 3, 4)
OffsetRectangle.fromCenterAndSize(OffsetRectangle, 10, 10, 3, 4)
TextLabel.fromCenterAndSize(TextLabel, 10, 10, 3, 4)

Now we have a consistent interface again. The only problem with this is
that we have duplication in the call. That is easily fixed though by
switching to class methods and you get back to my code.

One more point. You said in an earlier post:
I would change the classmethods to staticmethods, however, and avoid
the need to teach classmethods.


If you are going to teach your students how to create objects in Python you
will need to explain the __new__ method. __new__ is automatically a class
method, so there is no way you can avoid teaching class methods. You can
however avoid teaching static methods.
Jul 18 '05 #97
On 1 Jun 2004 09:57:28 GMT, Duncan Booth <me@privacy.net> wrote:
David MacQuigg <dm*@gain.com> wrote in
news:0d********************************@4ax.com :
< example assuming the desired method is defined in Shape: >
Shape.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
Shape.fromCenterAndSize(Ellipse, 10, 10, 3, 4)
Shape.fromCenterAndSize(OffsetRectangle, 10, 10, 3, 4)
Shape.fromCenterAndSize(TextLabel, 10, 10, 3, 4)
< snip long discussion showing why this is not a good assumption. >
Rectangle.fromCenterAndSize(Rectangle, 10, 10, 3, 4)
Ellipse.fromCenterAndSize(Ellipse, 10, 10, 3, 4)
OffsetRectangle.fromCenterAndSize(OffsetRectangle, 10, 10, 3, 4)
TextLabel.fromCenterAndSize(TextLabel, 10, 10, 3, 4)

Now we have a consistent interface again. The only problem with this is
that we have duplication in the call. That is easily fixed though by
switching to class methods and you get back to my code.
I can still replace this more easily with:

for cls in Rectangle,Ellipse,OffsetRectangle,Textlabel:
cls.fromCenterAndSize(cls, 10, 10, 3, 4)

However, if you change this example so all the arguments are
different, then you have made your point. Class methods can avoid
much duplication of class names.
One more point. You said in an earlier post:
I would change the classmethods to staticmethods, however, and avoid
the need to teach classmethods.


If you are going to teach your students how to create objects in Python you
will need to explain the __new__ method. __new__ is automatically a class
method, so there is no way you can avoid teaching class methods. You can
however avoid teaching static methods.


Actually, __new__ is a staticmethod. According to GvR in
http://python.org/2.2.3/descrintro.html#__new__
'''
Factoid: __new__ is a static method, not a class method. I initially
thought it would have to be a class method, and that's why I added the
classmethod primitive. Unfortunately, with class methods, upcalls
don't work right in this case, so I had to make it a static method
with an explicit class as its first argument. Ironically, there are
now no known uses for class methods in the Python distribution (other
than in the test suite). However, class methods are still useful in
other places, for example, to program inheritable alternate
constructors.
'''

Static methods are needed whenever you want to call a method without
an instance. True, we could do this with a class method and just
ignore the class, but the strange first argument will need further
explanation, and will seem odd to students seeing lots of static
methods and very few class methods in typical programs.

I will probably leave class methods as they are in Learning Python,
2nd ed - in an "advanced" section toward the end of the OOP chapters.

I haven't yet decided what to do with __new__ and __metaclass__. I've
received a good example of using these to generate classes for the
Animals examples, but the Python documentation is poor, and I think I
can accomplish the purpose of automatically generating classes with
correct attributes, using "factory functions" as your example
illustrates.

-- Dave

Jul 18 '05 #98
Sorry for the late reply on this question. I just now saw this post
in reviewing the thread.

On Fri, 14 May 2004 12:35:48 -0400, Rich Krauter <rm*******@yahoo.com>
wrote:
On Thu, 2004-05-13 at 17:59, David MacQuigg wrote:

Actually, .var could be used in a function outside a class, just as
you can now use self.var in the current function syntax. Before using
a function with .var, the global variable __self__ must be set.


I may be way off here, but I don't see how a global __self__ could work:

<not python>

class B:
def __init__(name,data):
.data = data*5
.name = '***%s***'%name

class A:
def __init__(name,data):
.data = data # __self__ is a?
.obj = B() # __self__ is now the B instance?
.name = name # now what?

a = A()

</not python>


The __self__ variable is set automatically when a function is called
from an instance, and returned to its prior value ( usually None )
when the call returns. So in the example above, we have an implicit
call to __init__ from the new instance a. This makes the first line
of the __init__ function equivalent to a.data = data.

The second line is equivalent to a.obj = B(). When the new instance
of B is constructed, there is a call to its __init__ function from
that new instance. At that moment, __self__ is set to the new
instance (a.obj), and that instance gets two new attributes, data and
name.

On returning from the call to B.__init__, __self__ returns to its
prior value 'a', and we set the final attribute a.name When you are
done, there will be one instance a, with attributes data, name, and
obj. The obj attribute is an instance of B, with attributes data and
name.

It works just like in current Python, except that the current instance
is "passed" by pointing to it with a special variable, rather than
inserting it into the argument sequence. The key difference is that
when you use the first argument for passing an instance, that instance
is *required* in every call, even if it is not used. (Hence the need
for special syntax when we want to avoid this requirement.) If you
use a global variable to pass the current instance, any function that
doesn't require it simply ignores it.

-- Dave

Jul 18 '05 #99
David MacQuigg <dm*@gain.com> wrote in
news:go********************************@4ax.com:
Actually, __new__ is a staticmethod.
Thanks, I'd missed that.

I haven't yet decided what to do with __new__ and __metaclass__. I've
received a good example of using these to generate classes for the
Animals examples, but the Python documentation is poor, and I think I
can accomplish the purpose of automatically generating classes with
correct attributes, using "factory functions" as your example
illustrates.

The main time I've felt a need to use __new__ is to implement flyweight
classes. If the object to be returned is based entirely on the arguments to
the constructor, and the object doesn't contain modifiable state, then you
can cache the objects you have already created and simply return the
appropriate one from the cache instead of creating a new object.

The same argument would apply to singletons except I've never yet found a
good use for a singleton :-)

Jul 18 '05 #100

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Elmar Grandel | last post by:
Can anybody answer me the question if there is any possiblity to increase the 65535byte limitation for Java classes / methods / functions / constructors etc. I am currently researching in the...
3
by: Matik | last post by:
Hi, I alredy tried to search this problem in last posts, but I couldn't find the answer. I try to access via Extended SP the method in a dll. I registered the dll as a ExSP, with a name of...
4
by: Justin | last post by:
I am developing a windows application, which consists of few projects with many methods, functions, events etc., Is there any "tool" available with VS.net to find the total number of times each...
8
by: Shea Martin | last post by:
I have a pure virtual f'n bool SaveData(). This f'n is called by SaveDataWithWarn(). The idea being the implementing class must define how data is saved, but the base class handles GUI operations,...
4
by: MPF | last post by:
When designing a n-tier architecture, what is the preferred method/function accessibility? <Specifically for asp.net apps> A private constructor and shared/static methods & functions? A public...
4
by: qualitynice | last post by:
HELP :-)... I'm creating an embedded activex object in an asp.net page using the HtmlGenericControl class. I'm doing this because when I tried to embed it directly in the aspx page, it stopped...
2
by: DraguVaso | last post by:
Hi, I have a UserControl (MyUserControl) which has a DataGrid (MyDataGrid). I made a new UserControl that Inherits of my first UserControl: I named it MyInheritedUserControl. For some reason...
47
by: Albert | last post by:
So structures are useful to group variables, so you can to refer to a collection as a single entity. Wouldn't it be useful to also have the ability to collect variable and functions? Ask K&R...
10
by: herlands | last post by:
Hi! Given the following example: class Base { public: void doSomething() { //Something...
12
by: thegman | last post by:
Hi all, I'm trying to get list of JavaScript methods/functions in a script file in much the same a good text editor will, the difference being that I need to output it to a file or stdout, or some...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.