Unexpected Python Behavior

Discussion in 'Python' started by Simon Wittber, Sep 24, 2004.

  1. 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---
    Simon Wittber, Sep 24, 2004
    #1
    1. Advertising

  2. 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/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>
    Fredrik Lundh, Sep 24, 2004
    #2
    1. Advertising

  3. "Fredrik Lundh" <> 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/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
    David Pokorny, Sep 24, 2004
    #3
  4. 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/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."
    --
    Michael Hoffman
    Michael Hoffman, Sep 24, 2004
    #4
  5. 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>
    Fredrik Lundh, Sep 24, 2004
    #5
  6. Simon Wittber

    Peter Otten Guest

    David Pokorny wrote:

    >
    > "Fredrik Lundh" <> 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/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
    Peter Otten, Sep 24, 2004
    #6
  7. On Fri, 24 Sep 2004 14:48:37 +0100, Michael Hoffman
    <> 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
    Andrea Griffini, Sep 26, 2004
    #7
  8. Andrea Griffini <> wrote:

    > On Fri, 24 Sep 2004 14:48:37 +0100, Michael Hoffman
    > <> 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
    Alex Martelli, Sep 26, 2004
    #8
  9. On Sun, 26 Sep 2004 10:39:15 +0200, (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
    Andrea Griffini, Sep 28, 2004
    #9
  10. Andrea Griffini <> wrote:

    > On Sun, 26 Sep 2004 10:39:15 +0200, (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
    Alex Martelli, Sep 28, 2004
    #10
  11. On Tue, 28 Sep 2004 19:12:16 +0200, (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
    Bengt Richter, Sep 28, 2004
    #11
  12. Bengt Richter <> 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
    Alex Martelli, Sep 29, 2004
    #12
  13. Simon Wittber

    Greg Ewing Guest

    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
    Greg Ewing, Sep 30, 2004
    #13
  14. Simon Wittber

    David Bolen Guest

    Greg Ewing <> 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
    David Bolen, Sep 30, 2004
    #14
  15. On Thu, 30 Sep 2004 15:22:04 +1200, Greg Ewing
    <> 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
    Andrea Griffini, Oct 1, 2004
    #15
  16. [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
    Michael Hoffman, Oct 1, 2004
    #16
  17. On Fri, 01 Oct 2004 09:32:31 +0100, Michael Hoffman
    <> 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
    Andrea Griffini, Oct 1, 2004
    #17
  18. Andrea Griffini <> 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
    Alex Martelli, Oct 1, 2004
    #18
  19. Simon Wittber

    Steve Holden Guest

    Andrea Griffini wrote:

    > On Fri, 01 Oct 2004 09:32:31 +0100, Michael Hoffman
    > <> 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
    Steve Holden, Oct 1, 2004
    #19
  20. Steve Holden <> 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
    Alex Martelli, Oct 1, 2004
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. G Dean Blake

    Unexpected datagrid behavior

    G Dean Blake, Jan 13, 2005, in forum: ASP .Net
    Replies:
    0
    Views:
    305
    G Dean Blake
    Jan 13, 2005
  2. Chuck Bowling

    Unexpected page designer behavior

    Chuck Bowling, Jul 4, 2005, in forum: ASP .Net
    Replies:
    1
    Views:
    431
    Chuck Bowling
    Jul 4, 2005
  3. Victor Bazarov
    Replies:
    0
    Views:
    830
    Victor Bazarov
    Jun 25, 2003
  4. Russell Hanneken
    Replies:
    0
    Views:
    876
    Russell Hanneken
    Jun 25, 2003
  5. Mark Wright

    Unexpected (by me) exec behavior

    Mark Wright, Jul 8, 2003, in forum: Python
    Replies:
    0
    Views:
    277
    Mark Wright
    Jul 8, 2003
Loading...

Share This Page