By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,919 Members | 1,903 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,919 IT Pros & Developers. It's quick & easy.

Unexpected Python Behavior

P: n/a
For the first time, I have been bitten by Python. The below code
produces the results:
False
True

when I initially expected the results:
False
False

It took me a while to work out that default keyword argument values
are likely only evaluated once, which caused the empty dict to be
shared across classes...

It certainly something newbie python coders should look out for!

Simon W.

---snip-here---

class X(object):
def __init__(self, d={}):
self.d = d

a = X()
b = X()

print a is b
print a.d is b.d

---snip-here---
Jul 18 '05 #1
Share this Question
Share on Google+
23 Replies


P: n/a
Simon Wittber wrote:
It took me a while to work out that default keyword argument values
are likely only evaluated once, which caused the empty dict to be
shared across classes...
some relevant links:

http://www.python.org/doc/faq/genera...etween-objects
http://docs.python.org/tut/node6.htm...00000000000000
http://docs.python.org/ref/function.html
It certainly something newbie python coders should look out for!


it's a well-known "you'll only do this once" mistake. which is a good thing,
because when you understand why this happens, you have learned a lot about
how "def" and objects work in Python...

</F>

Jul 18 '05 #2

P: n/a

"Fredrik Lundh" <fr*****@pythonware.com> wrote in message >
it's a well-known "you'll only do this once" mistake. which is a good

thing,

"Because of this feature, it is good programming practice to not use mutable
objects as default values." --
http://www.python.org/doc/faq/genera...etween-objects

Has it been discussed whether it would be a good idea to issue a warning in
this case? It strikes me that a warning wouldn't bother veteran programmers,
since it is really easy to avoid using a mutable default value (nearly
trivial to modify code that does use mutable default values). I'd imagine it
makes code more readable too.

David Pokorny
Jul 18 '05 #3

P: n/a
David Pokorny wrote:
"Because of this feature, it is good programming practice to not use mutable
objects as default values." --
http://www.python.org/doc/faq/genera...etween-objects

Has it been discussed whether it would be a good idea to issue a warning in
this case?
It's not.
It strikes me that a warning wouldn't bother veteran programmers,
since it is really easy to avoid using a mutable default value (nearly
trivial to modify code that does use mutable default values). I'd imagine it
makes code more readable too.


I think you're missing the usefulness of this feature. Go back to the
link you included and read the next paragraph, "This feature can be useful."
--
Michael Hoffman
Jul 18 '05 #4

P: n/a
David Pokorny wrote:
Has it been discussed whether it would be a good idea to issue a warning in
this case? It strikes me that a warning wouldn't bother veteran programmers,
since it is really easy to avoid using a mutable default value (nearly
trivial to modify code that does use mutable default values). I'd imagine it
makes code more readable too.


1) you cannot tell if an object is mutable or not

2) there are lots of valid uses for object binding (see the "This feature can
be useful" part in the FAQ for one example)

</F>

Jul 18 '05 #5

P: n/a
David Pokorny wrote:

"Fredrik Lundh" <fr*****@pythonware.com> wrote in message >
it's a well-known "you'll only do this once" mistake. which is a good thing,

"Because of this feature, it is good programming practice to not use
mutable objects as default values." --

http://www.python.org/doc/faq/genera...etween-objects
Has it been discussed whether it would be a good idea to issue a warning
in this case? It strikes me that a warning wouldn't bother veteran
programmers, since it is really easy to avoid using a mutable default
value (nearly trivial to modify code that does use mutable default
values). I'd imagine it makes code more readable too.


You want a warning? There you are:

$ cat mutabledefault.py

def buggy(item, list=[]):
list.append(item)
return list
$ pychecker mutabledefault.py
Processing mutabledefault...

Warnings...

mutabledefault.py:3: Modifying parameter (list) with a default value may
have unexpected consequences

Peter

Jul 18 '05 #6

P: n/a
On Fri, 24 Sep 2004 14:48:37 +0100, Michael Hoffman
<m.*********************************@example.com > wrote:
I think you're missing the usefulness of this feature. Go back to the
link you included and read the next paragraph, "This feature can be useful."


Given that now functions can have attributes, wouldn't be better
stop pushing ugly, risky and cryptic syntax for poor's man static ?
IMO one thing is backward compatibility, another is pushing the
uglyness in the future for no good reasons.

I am talking about the python docs that everywhere are apparently
advocating this approach for local cache implementation. Is this
doing any good for newbies approaching python ?

Or may be this is more pythonic ? If yes... why ?

Andrea
Jul 18 '05 #7

P: n/a
Andrea Griffini <ag****@tin.it> wrote:
On Fri, 24 Sep 2004 14:48:37 +0100, Michael Hoffman
<m.*********************************@example.com > wrote:
I think you're missing the usefulness of this feature. Go back to the
link you included and read the next paragraph, "This feature can be useful."
Given that now functions can have attributes, wouldn't be better
stop pushing ugly, risky and cryptic syntax for poor's man static ?


I think it's in fact very nice syntax:

def f(x, cache=[]):
if x in cache: ...

vs your apparently implied suggestion of:

def f(x):
if x in f.cache: ...
f.cache = []

which among other things suffers from f.cache having to be used in spots
that come lexically before it's defined; or a decorator equivalent:

@ set_function_attributes(cache=[])
def f(x):
if x in f.cache: ...

As for 'risky', both approaches are. The default argument risks the
user mistakenly passing a corresponding actual-argment; the function
attribute risks the user rebinding the name. It just don't work when
the function name aint'a global, as in a closure; nor does it work
equivalently for an overriden method, e.g.:

class base:
def f(self, x, cache=[]):
if x in cache: ...

class derived(base):
def f(self, x, y, cache=[]):
if y not in cache:
return base.f(self, x)

here you get two separate caches, one for base.f and one for derived.f,
no sweat -- and if you want base.f to use derived.f's cache when call
from there, just chance the last call to 'base.f(self, x, cache)' --
obvious, simple, elementary.

See now what happens with the use of 'self.f.cache' or 'base.f.cache':
how do you get two separate caches, or get to share one, as easily as
with the normal approach? You're forcing base's designer to decide for
all derived classes, the normal approach is clearly more flexible.

And good luck in explaining all this to beginners -- while the default
argument approach is really trivial to explain. Simple is better than
complex, and a general technique like using default values for caching
is better than a technique based on attributes which is not general
enough to be just used everywhere.

_Plus_, teaching this use of default values to beginners helps them
understand how default values work in all cases. Explaining the dirty
tricks needed to extend a bit the applicability of using function
attributes for caching offers no such nice "side advantage".

IMO one thing is backward compatibility, another is pushing the
uglyness in the future for no good reasons.
I think there are plenty of good reasons, see above.

In addition, accessing a local name is of course way faster than
accessing a global name and then an attribute thereof. In 2.3, I
repeatably measure 1.75 vs 2.50 usec; in 2.4, 1.25 vs 1.84. If that was
all the local-argument-default advantage, one could quibble, but coming
on top of the above-mentioned arguments, I think it's nice too.

I am talking about the python docs that everywhere are apparently
advocating this approach for local cache implementation. Is this
doing any good for newbies approaching python ?
Yes, it helps them a lot to understand, realize, and remember, that
default values are shared among all of a function's calls.
Or may be this is more pythonic ? If yes... why ?


It's simpler and more general.

If I were to use a decorator, I'd rather have it inject 'static locals'
in some way that doesn't let them be optionally passed as arguments, but
still in local namespace -- less flexible than the plain good old
technique, but avoids "accidental argument-passing" and may be nice when
you need to support *args. I think the implementation of such a
decorator is a bit messy, though, and besides flexibility you lose the
nice educational side effect. So, I prefer the status quo in this case.
Alex
Jul 18 '05 #8

P: n/a
On Sun, 26 Sep 2004 10:39:15 +0200, al*****@yahoo.com (Alex Martelli)
wrote:
vs your apparently implied suggestion of:

def f(x):
if x in f.cache: ...
f.cache = []
I like more...

def f(x):
if not hasattr(f,"cache"):
f.cache = []
...
which among other things suffers from f.cache having to be used in spots
that come lexically before it's defined; or a decorator equivalent:

@ set_function_attributes(cache=[])
def f(x):
if x in f.cache: ...
The best I can think to is something like

def f(x):
static cache = []
...

In other languages (mostly C) there cases in which I found
nice the idea of a local name for a globally living object.
As for 'risky', both approaches are. The default argument risks the
user mistakenly passing a corresponding actual-argment; the function
attribute risks the user rebinding the name.
?

Passing a parameter to a function that, by the way, is declaring
it *wants* it doesn't seem to me the same as messing with
internals of something from the outside.
It just don't work when the function name aint'a global, as in a
closure; nor does it work equivalently for an overriden method, e.g.:
?

def foo(x):
def bar(y):
if not hasattr(bar,"cache"):
bar.cache = []
bar.cache.append(x+y)
return bar.cache
return bar

bar_1 = foo(1)
bar_2 = foo(2)
print bar_1(1),bar_1(2),bar_1(3)
print bar_2(1),bar_2(2),bar_2(3)
here you get two separate caches, one for base.f and one for derived.f,
no sweat -- and if you want base.f to use derived.f's cache when call
from there, just chance the last call to 'base.f(self, x, cache)' --
obvious, simple, elementary.
When you need to mess with the those vars from the "outside" then
it's clear you're not looking for a static; probably you're not
even looking for a function as the interaction with the "state" is
getting too important. IMO in these cases it's *way* better to
use a class instead (may be one implementing the call interface).
And good luck in explaining all this to beginners -- while the default
argument approach is really trivial to explain. Simple is better than
complex, and a general technique like using default values for caching
is better than a technique based on attributes which is not general
enough to be just used everywhere.
Once reading that default were evaluated at function definition
time was enough for me; and I honestly say that I don't remember
ever falling for this trap of modifiable default values (so far).

However this seems happening quite frequently to novices; actually
*very* frequently. So either all the world is wrong or this very
specific part of the language has a problem.
_Plus_, teaching this use of default values to beginners helps them
understand how default values work in all cases. Explaining the dirty
tricks needed to extend a bit the applicability of using function
attributes for caching offers no such nice "side advantage".
Sure there is a plus in clearly understanding that function
definition is an executable statement in python. But using
an unrelated arbitrary fact (that default values are evaluated
at that time instead than at call time) isn't IMO a good example.
A better one I would say is ...

if raw_input("A or B ?") == "A":
def foo(x):
return x * 2
else:
def foo(x):
return x * x

print foo(12)
I think there are plenty of good reasons, see above.
I didn't find any of them *really* good
In addition, accessing a local name is of course way faster than
accessing a global name and then an attribute thereof.
Yeah, static are slower than necessary; and uglier also.

May be the direction could be fixing that instead of just
pushing towards an ugly hack that just happens to work.
Yes, it helps them a lot to understand, realize, and remember, that
default values are shared among all of a function's calls.
That's the wart!
It's simpler and more general.


To me seems an unrelated side-effect of the decision of
when to evaluate default parameters. I'm not questioning
the decision per se (it has pros and cons... for example
you can't use things like "def foo(x,y,z=x+y)") but that
using fake parameters for static is ugly and error prone.
Just my 0.02 euros of (still) fresh eye opinion
Andrea
Jul 18 '05 #9

P: n/a
Andrea Griffini <ag****@tin.it> wrote:
On Sun, 26 Sep 2004 10:39:15 +0200, al*****@yahoo.com (Alex Martelli)
wrote:
vs your apparently implied suggestion of:

def f(x):
if x in f.cache: ...
f.cache = []
I like more...

def f(x):
if not hasattr(f,"cache"):
f.cache = []
...


This means _every_ run of f will be loaded down by this test, just to
make everything less concise...?! Horrible trade-off, IMHO.
The best I can think to is something like

def f(x):
static cache = []
...

In other languages (mostly C) there cases in which I found
nice the idea of a local name for a globally living object.
I don't think you stand a snowball's chance in hell to make this horrid
change become part of Python (thanks be!) -- I suggest you look at other
sort-of-Pythonic languages such as (e.g.) the new Qu, which may be more
open to changes of this nature.
As for 'risky', both approaches are. The default argument risks the
user mistakenly passing a corresponding actual-argment; the function
attribute risks the user rebinding the name.


?


import math

def f(x):
try: return f.cache[x]
except KeyError:
f.cache[x] = result = math.sin(x)
return result
f.cache = {}

def g(x):
try: return g.cache[x]
except KeyError:
g.cache[x] = result = math.cos(x)
return result
g.cache = {}

print f(0.2), g(0.2), f(0.2), g(0.3)

# note: oops coming
f, g = g, f

print f(0.2), g(0.2), f(0.2), g(0.3)
Basically, the idea of having f use f.cache depends on the unstated
assumption that global name 'f' will forevermore refer to the same
object it used to refer to at the time f.cache was initialized and the
first few entries of f.cache were set. You say you consider it "risky"
to use f's default attribute values (which stick to the object, not to
the name), and I reply, _THIS_ inferior idiom you advocate is the truly
risky one -- it relies on a "fixed" name<->object correspondence which
NOTHING in Python guarantees or even suggests.

Passing a parameter to a function that, by the way, is declaring
it *wants* it doesn't seem to me the same as messing with
internals of something from the outside.
If you want to hint that a parameter is really 'internal' name it with a
leading underscore, that's Python's convention.

here you get two separate caches, one for base.f and one for derived.f,
no sweat -- and if you want base.f to use derived.f's cache when call
from there, just chance the last call to 'base.f(self, x, cache)' --
obvious, simple, elementary.


When you need to mess with the those vars from the "outside" then
it's clear you're not looking for a static; probably you're not
even looking for a function as the interaction with the "state" is
getting too important. IMO in these cases it's *way* better to
use a class instead (may be one implementing the call interface).


And go to the huge trouble of simulating method-binding?! Puh-LEEZE.
Using callable classes in lieu of a class's ordinary methods, when such
methods with perfectly normal Python semantics will do, is just plain
silly -- looking for complexity where no need for it exists.

And good luck in explaining all this to beginners -- while the default
argument approach is really trivial to explain. Simple is better than
complex, and a general technique like using default values for caching
is better than a technique based on attributes which is not general
enough to be just used everywhere.


Once reading that default were evaluated at function definition
time was enough for me; and I honestly say that I don't remember
ever falling for this trap of modifiable default values (so far).


Good for you -- I did, a couple of times.
However this seems happening quite frequently to novices; actually
*very* frequently. So either all the world is wrong or this very
specific part of the language has a problem.


Are you not part of this world, if _ALL_ the world is wrong yet you
never had the problem? In my case, the problems were due to previous
experience with C++ -- a traumatic rite of passage which fortunately not
everybody HAS had to go through.

_Plus_, teaching this use of default values to beginners helps them
understand how default values work in all cases. Explaining the dirty
tricks needed to extend a bit the applicability of using function
attributes for caching offers no such nice "side advantage".


Sure there is a plus in clearly understanding that function
definition is an executable statement in python. But using
an unrelated arbitrary fact (that default values are evaluated
at that time instead than at call time) isn't IMO a good example.


Nope, that's not what I said. I said, and I repeat (and expand since
clearly it wasn't clear to you): learning to use default values for a
cache, rather than the no-advantages-whatsoever technique you advocate
of using function attributes for the same purpose, besides all other
advantages, has the one of firmly fixing the concept that default values
are evaluate once, at def time.
In addition, accessing a local name is of course way faster than
accessing a global name and then an attribute thereof.


Yeah, static are slower than necessary; and uglier also.

May be the direction could be fixing that instead of just
pushing towards an ugly hack that just happens to work.


I don't find default values ugly.

Yes, it helps them a lot to understand, realize, and remember, that
default values are shared among all of a function's calls.


That's the wart!


So here's our deep disagreement. I would find it an intolerable wart if
Python did _anything else_ except evaluate expressions when it meets
them, implicitly "saving them away somewhere or other" to be reevaluated
over and over AND over again -- in SOME cases (chosen HOW...?!).

It's simpler and more general.


To me seems an unrelated side-effect of the decision of
when to evaluate default parameters. I'm not questioning
the decision per se (it has pros and cons... for example
you can't use things like "def foo(x,y,z=x+y)") but that
using fake parameters for static is ugly and error prone.


You call the decision "the wart!" and then claim not to be questioning
it?! I've seen hypocrisy in my life, but this ridiculous combination
sure takes the prize!
Alex
Jul 18 '05 #10

P: n/a
On Tue, 28 Sep 2004 19:12:16 +0200, al*****@yahoo.com (Alex Martelli) wrote:
[...]
>As for 'risky', both approaches are. The default argument risks the
>user mistakenly passing a corresponding actual-argment; the function
>attribute risks the user rebinding the name.
?


import math

def f(x):
try: return f.cache[x]
except KeyError:
f.cache[x] = result = math.sin(x)
return result
f.cache = {}

def g(x):
try: return g.cache[x]
except KeyError:
g.cache[x] = result = math.cos(x)
return result
g.cache = {}

print f(0.2), g(0.2), f(0.2), g(0.3)

# note: oops coming
f, g = g, f

print f(0.2), g(0.2), f(0.2), g(0.3)
Basically, the idea of having f use f.cache depends on the unstated
assumption that global name 'f' will forevermore refer to the same
object it used to refer to at the time f.cache was initialized and the
first few entries of f.cache were set. You say you consider it "risky"
to use f's default attribute values (which stick to the object, not to
the name), and I reply, _THIS_ inferior idiom you advocate is the truly
risky one -- it relies on a "fixed" name<->object correspondence which
NOTHING in Python guarantees or even suggests.

Thanks for highlighting this. It is one of my pet peeves that there is
no local "self" reference available for a function or class etc., and
no way (other than one-at-a-time method-self binding) to get a def-time
expression value bound to a locally visible name. Maybe we could have
a triple star in the arg list to delimit syntax and effect like defaults
but which don't become part of the arg count? E.g.,

def f(x, *** cache={}, pi = __import__('math').pi):
try: return cache[x]
...etc

Or arrange it differently, and add comments

def f(x, ***
# presets
cache={}, # XXX lru later ;-)
pi = __import__('math').pi
): # run time
try: return cache[x]
...etc
Passing a parameter to a function that, by the way, is declaring
it *wants* it doesn't seem to me the same as messing with
internals of something from the outside.


If you want to hint that a parameter is really 'internal' name it with a
leading underscore, that's Python's convention.

>here you get two separate caches, one for base.f and one for derived.f,
>no sweat -- and if you want base.f to use derived.f's cache when call
>from there, just chance the last call to 'base.f(self, x, cache)' --
>obvious, simple, elementary.


When you need to mess with the those vars from the "outside" then
it's clear you're not looking for a static; probably you're not
even looking for a function as the interaction with the "state" is
getting too important. IMO in these cases it's *way* better to
use a class instead (may be one implementing the call interface).


And go to the huge trouble of simulating method-binding?! Puh-LEEZE.
Using callable classes in lieu of a class's ordinary methods, when such
methods with perfectly normal Python semantics will do, is just plain
silly -- looking for complexity where no need for it exists.

I'm not sure why you didn't mention the alternative of not simulating
but actually using the mechanism of method binding, e.g.,
import math
def f(cache, x): ... try: return cache[x]
... except KeyError:
... cache[x] = result = math.sin(x)
... return result
... f = f.__get__({}, dict)
f <bound method dict.f of {}> f(math.pi/6.) 0.49999999999999994 f.im_self {0.52359877559829882: 0.49999999999999994} f(0.0) 0.0 f.im_self {0.52359877559829882: 0.49999999999999994, 0.0: 0.0}

And you can't pass extra arguments ...
(BTW, (to OP) note that f sees bound "self" (the cache) as part of the arg count,
the way f the function sees it. This would have been be clearer if I had not rebound 'f')
f({}, 0.0)

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: f() takes exactly 2 arguments (3 given)

Regards,
Bengt Richter
Jul 18 '05 #11

P: n/a
Bengt Richter <bo**@oz.net> wrote:
...
Basically, the idea of having f use f.cache depends on the unstated
assumption that global name 'f' will forevermore refer to the same
object it used to refer to at the time f.cache was initialized and the ...
Thanks for highlighting this. It is one of my pet peeves that there is
no local "self" reference available for a function or class etc., and
no way (other than one-at-a-time method-self binding) to get a def-time
expression value bound to a locally visible name. Maybe we could have
The reason for this is that function attributes are not meant to make
functions into kinda-classes-though-not-quite, so there's no special
interest in having a function refer to its own attributes. Rather,
function attributes were introduced (not all that long ago) to let
metainformation about a function (used by frameworks such as parsers) be
stored more handily than into the docstring (which is what some such
frameworks used to abuse for the purpose).
a triple star in the arg list to delimit syntax and effect like defaults
but which don't become part of the arg count? E.g.,

def f(x, *** cache={}, pi = __import__('math').pi):
try: return cache[x]


I'm sure that if these semantics were accepted, the syntax for them
would inevitably be a decorator:

@ initialized_locals(cache={}, pi=__import__('math').pi)
def f(x):
try: return cache[x]
...etc...

If it was ok to make these "initialized locals" non-rebindable, I think
this decorator could _almost_ be implemented today with a closure like:

def initialized_locals(**kwds):
import new
def wrap_f(f):
_c = f.func_code
_c = new.code(_c.co_argcount, _c.co_nlocals, _c.co_stacksize,
_c.co_flags, _c.co_code, _c.co_consts, _c.co_names,
_c.co_varnames, _c.co_filename, _c.co_name,
_c.co_firstlineno,
_c.co_lnotab, tuple(kwds), _c.co_cellvars)
return new.function(_c, f.func_globals, f.func_name,
f.func_defaults, tuple(kwds.itervalues()))
return wrap_f

@ initialized_locals(a=23, b=45)
def f(c, d=67):
print a, b, c, d

f(41)

The _almost_ is due to the "tuple(kwds.itervalues())" not being QUITE
right -- it should be something like map(_make_cell, kwds.itervalues())
for a hypothetical factory '_make_cell' that's able to make new cell
objects. Unfortunately, the factory is hypothetical because I believe
there is no such thing as a Python-accessible way to make a cell: cells
are only made in ceval.c, specifically PyEval_EvalCodeEx.

Maybe (no time to check this up right now...), all that we need to
enable this particular "extreme sport" is a small C-coded extension
which exposes a _make_cell function to Python. It seems to me that
every other piece is already in place. If so, then we could make this
available for experimentation without it needing to get into the Python
core immediately. Another possibility would be to try and grasp the
_source_ for the function being wrapped, wrap it textually into the
outer function needed for the closure, and do an 'exec' on the resulting
string to make the new function object; however, that one looks
definitely dirty to me, while exposing the ability to make cells doesn't
look any blacker, in black-magic terms, than existing abilities such as
those offered by new.code... Finally, a pragmatic compromise might be
to use 'exec' on a tiny constructed closure just to build and hijack its
f.func_closure, a tuple of cells. This looks both dirty and black
magic, so it might impartially make everybody equally unhappy, but with
a couple hours of experimentation it might already fall into place;-).
IOW: once again, like in another thread going on right now, I'd advise
to focus on the implementation -- syntax can wait. If the
implementation is easy to explain, it could be a good thing...
When you need to mess with the those vars from the "outside" then
it's clear you're not looking for a static; probably you're not
even looking for a function as the interaction with the "state" is
getting too important. IMO in these cases it's *way* better to
use a class instead (may be one implementing the call interface).


And go to the huge trouble of simulating method-binding?! Puh-LEEZE.
Using callable classes in lieu of a class's ordinary methods, when such
methods with perfectly normal Python semantics will do, is just plain
silly -- looking for complexity where no need for it exists.

I'm not sure why you didn't mention the alternative of not simulating
but actually using the mechanism of method binding, e.g.,


Because it's just as unusable in the context we were discussing, i.e.:

class base:
def f(self, x, cache={}): ...

class deriv(base):
def f(self, x, cache={}): ...

the f's one and only "currying [[prebinding]] slot" is needed for the
appropriate self object(s), can't be "wasted" on the cache dict(s).
Alex
Jul 18 '05 #12

P: n/a
Alex Martelli wrote:
I think it's in fact very nice syntax:

def f(x, cache=[]):
if x in cache: ...


No, it's not, because it suggests that cache is
intended to be an optional parameter, whereas it
probably isn't.

This is a hack. Don't do it.

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

Jul 18 '05 #13

P: n/a
Greg Ewing <gr**@cosc.canterbury.ac.nz> writes:
Alex Martelli wrote:
I think it's in fact very nice syntax:
def f(x, cache=[]):
if x in cache: ...


No, it's not, because it suggests that cache is
intended to be an optional parameter, whereas it
probably isn't.


Depends - I'd probably read that just as you say - it's an optional
parameter. But why assume it probably isn't intended that way. If I
want to use my own cache I pass it in, otherwise I expect the function
to have a default cache that it will use for me.

-- David
Jul 18 '05 #14

P: n/a
On Thu, 30 Sep 2004 15:22:04 +1200, Greg Ewing
<gr**@cosc.canterbury.ac.nz> wrote:
Alex Martelli wrote:
I think it's in fact very nice syntax:

def f(x, cache=[]):
if x in cache: ...


No, it's not, because it suggests that cache is
intended to be an optional parameter, whereas it
probably isn't.

This is a hack. Don't do it.


Puh-LEEEZE!!!

Who are you to question what Him, the Great Alex, says about it ?

That's is a very nice piece of code and I among the others
true Alex' believers actually moved over from C to python
basically just for the beauty of the idea of moving local
statics from the body to the interface!

It doesn't matter *what* the great Alex says, just remember
*who* said it. Does the discussion about the risk of
rebinding names a total nonsense just because the very same
applies in that very same example to math.cos and math.sin ?
So ? Still it's Alex's word... widsom from another planet
you (a no-one) surely can't question.

Watch your mouth next time, you worst of all hypocrites...
or the maledition of thousands of irrelevant co_*
implementation details magic formulas will destroy you.

And don't try to say that pychecker actually emits
warnings when that cra^H^H^Hbeatiful technique is
used. It's just because the Great still didn't wasted
time annihilating the misbelievers behind it.

Andrea
Jul 18 '05 #15

P: n/a
[Andrea Griffini]
[Greg Ewing]
[Alex Martelli]
I think it's in fact very nice syntax:

This is a hack. Don't do it.

Who are you to question what Him, the Great Alex, says about it ?


Who are you to question what Greg Ewing says?

I'm having trouble figuring out whether the rest of this message is
supposed to be ironic or sarcastic or something. I can say with
certainty that it is pretty silly.
--
Michael Hoffman
Jul 18 '05 #16

P: n/a
On Fri, 01 Oct 2004 09:32:31 +0100, Michael Hoffman
<m.*********************************@example.com > wrote:
[Andrea Griffini]
[Greg Ewing]
[Alex Martelli]
I think it's in fact very nice syntax:
This is a hack. Don't do it. Who are you to question what Him, the Great Alex, says about it ?


Who are you to question what Greg Ewing says?


Are we going to go around in circles forever asking
each other "who are you to say this" ?
I'm having trouble figuring out whether the rest of this message is
supposed to be ironic or sarcastic or something. I can say with
certainty that it is pretty silly.


It's a 7am posting, so please be forgiving at least
for that reason.

I didn't reply to Alex message because it's clear that he has
a very personal problem with me (and ... no, I've no idea why).
My decision so was to stop feeding his hate and I ignored him;
that one is a problem he has with me and not the other way
around... may be he can try to find a solution inside himself
or talking to a good psychotherapist... I don't think I can
be of any help about it.

What kind of surprised me is however that no one else contested
the nonsenses and/or irrelevant facts in his message. So I came
to the conclusion that here we're leaving the land of logic.

I saw just one message saying what I (as a newbie to python)
think is obvious to at least anyone with a reasonable brain
and cold enough to think without prejudice; i.e. that defining

def foo(x, cache=[])

when you've no intention to receive that parameter is a purely,
simply, uncontestably, stinking, ugly hack (also IMO adding
underscores to that "cache" name is not making this hack really
any prettier).

And, in case you're really interested, I'm just a programmer
with an apparently tweaked sense of humor that approached
python very recently (that's why I don't consider myself part
of the python "world", yet).

Andrea

Jul 18 '05 #17

P: n/a
Andrea Griffini <ag****@tin.it> wrote:
I didn't reply to Alex message because it's clear that he has
a very personal problem with me (and ... no, I've no idea why).
I don't know why you started posting flaming attacks against me four
years or so ago (on Italian newsgroups on C++, where you were advocating
returning error codes rather than raising exceptions, and I the
reverse), but it was so blatant (you specifically accused me of
intellectual dishonesty, just like that, out of the blue!) that I
killfiled you -- and I remember a few days later somebody _else_ (who
actually agreed with you on the technical aspects of the discussion!)
was trying to point out to you that you were the one who had exceeded
the boundaries of good taste and indulged in uncalled-for personal
attacks. We're talking years 2000 or 2001, not the dark ages, so I bet
Google Groups has everything in its archives if one just googles for
both of our surnames together.

Of course, I'm using a different newsreader now, with a different
killfile and all, and I wasn't reminded of that occasion until you
showed your colors again -- now, I see, by trying to accuse _me_ of
having mysterious personal problems with you, when each time the foam is
so evidently at _your_ mouth...
My decision so was to stop feeding his hate and I ignored him;


Oh, I see, _that_ must be why you spewed so much venom in your post that
yet another "innocent bystander" felt it had to be condemned...!

Guess you deserve commendation for your consistency: four years ago you
said you were new to C++ yet had the arrogance to start personal attacks
and insults against me on the subject, now you say you're new to Python
and you behave identically -- my compliments.

Well, *PLONK* again, then, hopefully for good.
Alex
Jul 18 '05 #18

P: n/a
Andrea Griffini wrote:
On Fri, 01 Oct 2004 09:32:31 +0100, Michael Hoffman
<m.*********************************@example.com > wrote:

[Andrea Griffini]
[Greg Ewing]

[Alex Martelli]

>I think it's in fact very nice syntax:

This is a hack. Don't do it.

Who are you to question what Him, the Great Alex, says about it ?
Who are you to question what Greg Ewing says?

Are we going to go around in circles forever asking
each other "who are you to say this" ?

Apparently.
I'm having trouble figuring out whether the rest of this message is
supposed to be ironic or sarcastic or something. I can say with
certainty that it is pretty silly.

It's a 7am posting, so please be forgiving at least
for that reason.

I didn't reply to Alex message because it's clear that he has
a very personal problem with me (and ... no, I've no idea why).


It's clear to you, possibly.
My decision so was to stop feeding his hate and I ignored him;
Hate? This doesn't sound like the Alex I know (and I'm talking about
through the face meetings here, not just net acquaintanceship) This guy
was the technical editor for my book, and I know him to be not only
technically brilliant but also an affable and congenial person).
that one is a problem he has with me and not the other way
around... may be he can try to find a solution inside himself
or talking to a good psychotherapist... I don't think I can
be of any help about it.
Well, clearly not with an attitude like that. Frankly that's about as
insulting as you should be getting around here. In fact I think you've
gone too far. I preferred the sarcasm.
What kind of surprised me is however that no one else contested
the nonsenses and/or irrelevant facts in his message. So I came
to the conclusion that here we're leaving the land of logic.
Perhaps anyone who has opinions that vary from yours has a problem
requiring psychotherapeutic help? I'm beginning to sense that I too am a
little unbalanced.
I saw just one message saying what I (as a newbie to python)
think is obvious to at least anyone with a reasonable brain
and cold enough to think without prejudice; i.e. that defining

def foo(x, cache=[])

when you've no intention to receive that parameter is a purely,
simply, uncontestably, stinking, ugly hack (also IMO adding
underscores to that "cache" name is not making this hack really
any prettier).
Well, of course, as a newbie to Python you are clearly in a far better
position than anyone else to say what's reasonable. This couldn't
possibly be a sensible use of name scoping rules to avoid the necessity
for a static declaration, could it? Dammit, you know what a function is,
and if it has parameters then we should damned well use them in the calls.

Right.
And, in case you're really interested, I'm just a programmer
with an apparently tweaked sense of humor that approached
python very recently (that's why I don't consider myself part
of the python "world", yet).

Andrea

Well I don't often say this, but I think we have to get the attitude
adjusters out here. Just sit in this chair, please, you'll just feel a
little prick with a needle [this is a lie: I don't really have a
needle]. There, that should feel better. Take three of the purple
tablets a day, and come back when you are able to indulge in a
difference of opinion without suggesting that those of a different view
require therapy.

I don't suppose it's come to your attention that Alex is the author of
"Python in a Nutshell" and co-author of "The Python Cookbook", and
therefore rather well qualified to pontificate on the vagaries of Python
usage? I suspect the only offense he is actually guilty of is treating
you as better-informed than you actually are.

regards
Steve

Jul 18 '05 #19

P: n/a
Steve Holden <st***@holdenweb.com> wrote:
...
I don't suppose it's come to your attention that Alex is the author of
"Python in a Nutshell" and co-author of "The Python Cookbook", and
therefore rather well qualified to pontificate on the vagaries of Python


Heh, this may in fact have something to do with his attacks -- we're
both nobodies from a nowhere land (Italy well qualifies for such
epithets;-), yet I'm reasonably well-known in this field and he's not...
some people need no more motivation than envy, in order to start spewing
venomonous attacks, after all;-).

Seriously, being "well qualified to pontificate" isn't really the issue
here. For example, Greg Ewing is surely just as well qualified, yet
disagrees with me (and with the anonymous author of FAQ 1.4.21, and
presumably with Ka-Ping Yee, who uses the cache-as-default idiom in the
pydoc.py module he contributed to the Python Standard Library, ...) on
the specific point (while agreeing with me that evaluating default
values once at def-time is a good thing -- he has not commented on that
on this thread, but it's easy to google for what he said in the past).

Yet, none of us take such technical disagreements as excuses to spew
insults at each other, nor do we have the arrogance to proclaim our
opinions in the matter "uncontestable". I think these differences
between typical Pythonistas' behavior, and AG's, are important -- and
maybe, at one remove, they may help explain why you, I, Greg, Ka-Ping,
etc, can be "well qualified"... readiness to listen, and to argue with
the common courtesy civil people maintain, can help one _learn_...
Alex
Jul 18 '05 #20

P: n/a
On Fri, 01 Oct 2004 08:34:50 -0400, Steve Holden <st***@holdenweb.com>
wrote:
I didn't reply to Alex message because it's clear that he has
a very personal problem with me (and ... no, I've no idea why).
It's clear to you, possibly.


Yes. Feel also free to add "IMO" at every phrase. I originally
wrote "it's clear to me" but then removed it because I didn't
like the sound of it (to me...with me).
My decision so was to stop feeding his hate and I ignored him;


Hate? This doesn't sound like the Alex I know (and I'm talking about
through the face meetings here, not just net acquaintanceship) This guy
was the technical editor for my book, and I know him to be not only
technically brilliant but also an affable and congenial person).


Yes... I can very well understand that this is not the Alex you
know, but it's the Alex I know. Would you just please blank
out the names and read the messages instead ?
that one is a problem he has with me and not the other way
around... may be he can try to find a solution inside himself
or talking to a good psychotherapist... I don't think I can
be of any help about it.

Well, clearly not with an attitude like that. Frankly that's about as
insulting as you should be getting around here. In fact I think you've
gone too far. I preferred the sarcasm.


Can you take the time to read my messages in this thread
and Alex' replies to my messages, and tell me when was that
I passed the reasonable limit ?
What kind of surprised me is however that no one else contested
the nonsenses and/or irrelevant facts in his message. So I came
to the conclusion that here we're leaving the land of logic.

Perhaps anyone who has opinions that vary from yours has a problem
requiring psychotherapeutic help? I'm beginning to sense that I too am a
little unbalanced.


I'm not talking about this. I think Alex has a problem
with me and I really do not understand why this happened.
The problem (as I see it) started many years ago in a C++
newsgroup when I simply noted that at that time it was
IMO unfair to compare what the return code approach was
actually able to deliver (basically *all* the software we
were using at that time) with what the exception approach
was just promising.
The theme is of course very complex, but the discussion
simply ended on the spot because Alex understood that I
was calling him a dishonest (?) and then plonked me or at
least said he did (and shortly after actually left the group).
Before the alleged plonk I asked if he could actually provide
evidence that the exceptions-everywhere approach was paying
off in complex systems (I think exceptions are just wonderful
in a few special cases - i.e. when you can "rollback" or
at least "restart" a subsystem - but they're not a panacea
in general when your program state is complex, distributed
and unprotected... the core problem I see is that "strong"
exception safety doesn't scale up by composition) but his
reply was that he couldn't provide examples because it was
secret material (!?).

All this is probably on google, of course; but it's in italian.

What surprised me however is that nonsenses like the risk
of name rebinding (that pervades python; that is the
*essence* of python) were not commented. Why f,g = g,f and
not math.sin,math.cos = math.cos,math.sin ?

May be is the "pythonic" way to always privately import and
then bind functions to local names and doing all this
by using fake parameters with a default value ?

I was suprised that no one noted that if we want statics,
and the "hasattr" approach is slow then *the slowness* is
the problem. Probably a static keyword binding local names
to globally living objects to my newbie eyes would be the
best and would better describe the static local in C
(even if in python it would be arbitrary "how much" static
the var should be ... being the function definition an
executable statement should they be shared just between
calls of the same function instance ? should they be
shared between all instances of that function object ?)

I was also quite suprised about the discussion moving
to the microseconds when if I care about microseconds
the python is a questionable choice. True that python
is often "fast enough", but If I've to write uglier code
to get a 1.2x speedup then I can do it with other languages
instead of using something that is *essentially* slow
and get a 10x speedup. Ugly for ugly I'd use C++ (or
pyrex or whatever else) for that part if speed is a problem.
I saw just one message saying what I (as a newbie to python)
think is obvious to at least anyone with a reasonable brain
and cold enough to think without prejudice; i.e. that defining

def foo(x, cache=[])

when you've no intention to receive that parameter is a purely,
simply, uncontestably, stinking, ugly hack (also IMO adding
underscores to that "cache" name is not making this hack really
any prettier).

Well, of course, as a newbie to Python you are clearly in a far better
position than anyone else to say what's reasonable. This couldn't
possibly be a sensible use of name scoping rules to avoid the necessity
for a static declaration, could it? Dammit, you know what a function is,
and if it has parameters then we should damned well use them in the calls.

Right.


I'm sorry I don't understand if this is sarcasm or not...
are you really saying that using those fake parameters is
not an ugly stinking hack for the absence of a sensible
way to declare function static variables ?

Where do you stop ? Is it beautiful to use them also for
binding builtin functions you need ?

What about adding an every-other parameter with a string
default just for adding per-parameter documentation ?
Well I don't often say this, but I think we have to get the attitude
adjusters out here. Just sit in this chair, please, you'll just feel a
little prick with a needle [this is a lie: I don't really have a
needle]. There, that should feel better. Take three of the purple
tablets a day, and come back when you are able to indulge in a
difference of opinion without suggesting that those of a different view
require therapy.
Is this humor ? I've had and I'm still having a lot of
discussions with people not agreeing with me, but luckily
enough not many were so personally aggressive as Alex.
With normal people I normally end up agreeing on something,
or my counter-part does the same, or, most often, it's a
mix of the two. There are cases in which the discussion
ends up with everyone remaining with the same starting
position. But rarely I got to the "puh-LEEZE" level.

When things tend to degenerate my standard reaction has
been lately to just keep silent. This normally happens
after writing a VERY long reply, that I just avoid
posting... not because I fear the consequences; but
because all the content seems me so obvious that makes
clear the discussion left the land of logic and it's
entering the war territory. When someone I'm discussing
with is avoiding acknowledging even the obvious (and
it's clear that it can't be for a mental limit problem)
it's also obvious there's no point in keep discussing.
I don't suppose it's come to your attention that Alex is the author of
"Python in a Nutshell" and co-author of "The Python Cookbook", and
therefore rather well qualified to pontificate on the vagaries of Python
usage?
Sure I know that. I didn't read either however (yet).

But the key point is that your name is just not enough
to make drink what you say without thinking; sorry if
this sounds offending, but that philosophy is a part
of me I just can't shut off.

Say something convincing and I'll be more than happy to
agree with you. Say something that IMO is wrong and I'll
say it's wrong, whatever is your name (remaining of
course well prepared to accept an explanation if you're
kind enough to explain why you stand behind your position).

And (drumrolls) Alex Martelli name is surely not the
biggest I've had discussion with. By far.
I suspect the only offense he is actually guilty of is treating
you as better-informed than you actually are.


I can't find a way to say more clearly that I know
basically nothing of python. The biggest python program
I wrote so far is totalling a ridicolous 3800 lines.

But tell me that

def foo(x,my_personal_cache_so_please_dont_pass_this_p arm=[]):
...

is beautiful and I can sign a paper where is stated
that you're either kidding or a dork.

Andrea
Jul 18 '05 #21

P: n/a
On Fri, 1 Oct 2004 15:38:14 +0200, al*****@yahoo.com (Alex Martelli)
wrote:
Steve Holden <st***@holdenweb.com> wrote:
...
I don't suppose it's come to your attention that Alex is the author of
"Python in a Nutshell" and co-author of "The Python Cookbook", and
therefore rather well qualified to pontificate on the vagaries of Python
Heh, this may in fact have something to do with his attacks -- we're
both nobodies from a nowhere land (Italy well qualifies for such
epithets;-), yet I'm reasonably well-known in this field and he's not...
some people need no more motivation than envy, in order to start spewing
venomonous attacks, after all;-).


So you feel attacked. You also feel being a nobody. That would
explain the reaction... but can you tell me when I started
spewing venomonous attacks ? I don't understand this part.
Seriously, being "well qualified to pontificate" isn't really the issue
here. For example, Greg Ewing is surely just as well qualified, yet
disagrees with me (and with the anonymous author of FAQ 1.4.21, and
presumably with Ka-Ping Yee, who uses the cache-as-default idiom in the
pydoc.py module he contributed to the Python Standard Library, ...) on
the specific point (while agreeing with me that evaluating default
values once at def-time is a good thing -- he has not commented on that
on this thread, but it's easy to google for what he said in the past).
Evaluating defaults at def-time is IMO a reasonable decision;
not the only reasonable one I can see (but remember I'm a newbie),
but still quite reasonable.

(mis)using modifiable defaults is however quite another thing,
the former *allows* for the latter; but the two are not IMO the
same. One thing is what is legal, another is what is moral.
Yet, none of us take such technical disagreements as excuses to spew
insults at each other, nor do we have the arrogance to proclaim our
opinions in the matter "uncontestable".
"puh-LEEZE" is the courtesy form for IMHO ? I'm an "hypocrit" just
because your little brain isn't able to grasp that difference ?

Then "I piss on your head" (please consider this as the courtesy
form for "I don't agree wholeheartedly with you") :-)
I think these differences
between typical Pythonistas' behavior, and AG's, are important -- and
maybe, at one remove, they may help explain why you, I, Greg, Ka-Ping,
etc, can be "well qualified"... readiness to listen, and to argue with
the common courtesy civil people maintain, can help one _learn_...


Is this a calling everyone for a vote ? Sounds sorta funny...
and sort of pathetic at the same time.

Is there any specific reason for which you want me out of
python ? I was quite seriously thinking to pushing a lot for
adopting python as the main language for developing our next
CAD-CAM...

Andrea
Jul 18 '05 #22

P: n/a
>>>>> "Andrea" == Andrea Griffini <ag****@tin.it> writes:
through the face meetings here, not just net acquaintanceship)
This guy was the technical editor for my book, and I know him
to be not only technically brilliant but also an affable and
congenial person).
Andrea> Yes... I can very well understand that this is not the
Andrea> Alex you know, but it's the Alex I know. Would you just
Andrea> please blank out the names and read the messages instead ?

Doesn't help much.

that one is a problem he has with me and not the other way
around... may be he can try to find a solution inside himself
or talking to a good psychotherapist... I don't think I can be
of any help about it.
Well, clearly not with an attitude like that. Frankly that's
about as insulting as you should be getting around here. In
fact I think you've gone too far. I preferred the sarcasm.


Andrea> Can you take the time to read my messages in this thread
Andrea> and Alex' replies to my messages, and tell me when was
Andrea> that I passed the reasonable limit ?

Actually, you appeared to pass the reasonable limits for this
particular newsgroup. This newsgroup is noticeably friendlier than
most of the other newsgroups out there - I don't know why, it might be
a byproduct of some cosmic similarity between people who dig Python,
or just a nice, contagious tradition.

What you might consider appropriate in a C++ newsgroup sticks out like
a sore thumb here. Going for Ad Hominem is always a bad idea,
especially when provoked by a purely technical discussion. I believe
you will learn to appreciate this tradition when you hang out more
around here.

Andrea> The problem (as I see it) started many years ago in a C++
Andrea> newsgroup when I simply noted that at that time it was IMO
Andrea> unfair to compare what the return code approach was
Andrea> actually able to deliver (basically *all* the software we
Andrea> were using at that time) with what the exception approach
Andrea> was just promising.

I guess comparing the ups and downs is reasonable, rewriting a big
pile of code is a different thing. Surely you agree that in Python the
exceptions are the way to go?

Andrea> off in complex systems (I think exceptions are just
Andrea> wonderful in a few special cases - i.e. when you can
Andrea> "rollback" or at least "restart" a subsystem - but they're
Andrea> not a panacea in general when your program state is
Andrea> complex, distributed and unprotected... the core problem I

Coding using exceptions is just much less ledious and
error-prone. Also, the code is much more readable when every line
doesn't have CroakIfError(stuff_that_needs_to_be_done()). Exceptions
are slighly less cool in C++ because of all the memory management
complications.

Andrea> May be is the "pythonic" way to always privately import
Andrea> and then bind functions to local names and doing all this
Andrea> by using fake parameters with a default value ?

Of course not.

Andrea> I was also quite suprised about the discussion moving to
Andrea> the microseconds when if I care about microseconds the
Andrea> python is a questionable choice. True that python is often
Andrea> "fast enough", but If I've to write uglier code to get a
Andrea> 1.2x speedup then I can do it with other languages instead
Andrea> of using something that is *essentially* slow and get a
Andrea> 10x speedup. Ugly for ugly I'd use C++ (or

1.2x speedup just isn't worth the ugly code, for typical
situations. Just go ahead and write pretty code, it's probably fast
enough as well. Premature optimization is the root of all evil.

Andrea> But the key point is that your name is just not enough to
Andrea> make drink what you say without thinking; sorry if this
Andrea> sounds offending, but that philosophy is a part of me I
Andrea> just can't shut off.

Name, perhaps not, but when you are a newbie at something, the more
experienced ones are right surprisingly often. Questioning stuff when
you are new is almost a rite of passage :-).

Andrea> And (drumrolls) Alex Martelli name is surely not the
Andrea> biggest I've had discussion with. By far.

Again, completely unnecessary.

People do get pissed off on usenet, for one reason or another. When I
feel insulted (once here, a few times elsewhere), I just like to point
out briefly that what the other guy said was insulting, and stop
there. Unlike in "real life", the parent comment is there for all to
see, and everyone can draw their own conclusions. Perhaps the other
guy had a bad day, or has some personal issues to sort out; rarely is
it worth it fire back. There are no "debate points" to score, and
nobody thinks that whoever wields the sharpest sarcasm wins. It's not
slashdot, we are here with our real names :-).

Andrea> But tell me that

Andrea> def foo(x,my_personal_cache_so_please_dont_pass_this_p arm=[]):
Andrea> ...

Andrea> is beautiful and I can sign a paper where is stated that
Andrea> you're either kidding or a dork.

It's not beautiful, but it works, and is already in the language. Come
on, you are an old C++ hand, you are used to dealing with the horrors
of chtulhuan proportions daily. I'm a C++ programmer as well, and
nothing in Python compares to the dirt I deal with every day. Private
cache in param list is a minor issue.

--
Ville Vainio http://tinyurl.com/2prnb
Jul 18 '05 #23

P: n/a

(Hopefully a humourous followup - click here to escape.)

Yup, I walked 5 ks into town today to watch the movie only to find the
cinema was closed. Grumble - trudge back home (avoiding swooping nesting
magpies) to kick the cats and then browse c.l.p to relax (such a nice civilized
news-group).

And I see this - tusk, tusk. Jeez these Mediterranean types know
how to perpetuate a feud. Make you wonder what their married life would be like ;)

OOPs - just saw the clock; "The Godfathers" now on TV !

Bye

- Gary
P.S. Don't tell mee which of these vicious critters won ( I'm talking about
this c.l.p exchange - I'll see the movie tomorrow and see that victor ;)


Alex Martelli wrote:
Andrea Griffini <ag****@tin.it> wrote:

I didn't reply to Alex message because it's clear that he has
a very personal problem with me (and ... no, I've no idea why).

I don't know why you started posting flaming attacks against me four
years or so ago (on Italian newsgroups on C++, where you were advocating
returning error codes rather than raising exceptions, and I the
reverse), but it was so blatant (you specifically accused me of
intellectual dishonesty, just like that, out of the blue!) that I
killfiled you -- and I remember a few days later somebody _else_ (who
actually agreed with you on the technical aspects of the discussion!)
was trying to point out to you that you were the one who had exceeded
the boundaries of good taste and indulged in uncalled-for personal
attacks. We're talking years 2000 or 2001, not the dark ages, so I bet
Google Groups has everything in its archives if one just googles for
both of our surnames together.

Of course, I'm using a different newsreader now, with a different
killfile and all, and I wasn't reminded of that occasion until you
showed your colors again -- now, I see, by trying to accuse _me_ of
having mysterious personal problems with you, when each time the foam is
so evidently at _your_ mouth...

My decision so was to stop feeding his hate and I ignored him;

Oh, I see, _that_ must be why you spewed so much venom in your post that
yet another "innocent bystander" felt it had to be condemned...!

Guess you deserve commendation for your consistency: four years ago you
said you were new to C++ yet had the arrogance to start personal attacks
and insults against me on the subject, now you say you're new to Python
and you behave identically -- my compliments.

Well, *PLONK* again, then, hopefully for good.
Alex

Jul 18 '05 #24

This discussion thread is closed

Replies have been disabled for this discussion.