Unexpected Python Behavior

S

Simon Wittber

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

Fredrik Lundh

Simon said:
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/general.html#why-are-default-values-shared-between-objects
http://docs.python.org/tut/node6.html#SECTION006710000000000000000
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>
 
D

David Pokorny

Fredrik Lundh said:
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/general.html#why-are-default-values-shared-between-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
 
M

Michael Hoffman

David said:
"Because of this feature, it is good programming practice to not use mutable
objects as default values." --
http://www.python.org/doc/faq/general.html#why-are-default-values-shared-between-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."
 
F

Fredrik Lundh

David said:
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>
 
P

Peter Otten

David said:
thing,

"Because of this feature, it is good programming practice to not use
mutable objects as default values." --
http://www.python.org/doc/faq/general.html#why-are-default-values-shared-between-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
 
A

Andrea Griffini

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
 
A

Alex Martelli

Andrea Griffini said:
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
 
A

Andrea Griffini

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
 
A

Alex Martelli

Andrea Griffini said:
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.

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.

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.

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.

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

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

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
 
B

Bengt Richter

]

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
If you want to hint that a parameter is really 'internal' name it with a
leading underscore, that's Python's convention.



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.,
... try: return cache[x]
... except KeyError:
... cache[x] = result = math.sin(x)
... return result
... {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')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: f() takes exactly 2 arguments (3 given)

Regards,
Bengt Richter
 
A

Alex Martelli

Bengt Richter said:
...
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...
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
 
G

Greg Ewing

Alex said:
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.
 
D

David Bolen

Greg Ewing said:
Alex said:
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
 
A

Andrea Griffini

Alex said:
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
 
M

Michael Hoffman

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

Andrea Griffini

[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
 
A

Alex Martelli

Andrea Griffini said:
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
 
S

Steve Holden

Andrea said:
[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
 
A

Alex Martelli

Steve Holden said:
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
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top