Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #48742 > unrolled thread

Default Value

Started byAhmed Abdulshafy <abdulshafy@gmail.com>
First post2013-06-19 12:17 -0700
Last post2013-06-20 01:17 +0000
Articles 20 on this page of 86 — 21 participants

Back to article view | Back to comp.lang.python


Contents

  Default Value Ahmed Abdulshafy <abdulshafy@gmail.com> - 2013-06-19 12:17 -0700
    Re: Default Value Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2013-06-19 22:35 +0300
    Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-19 12:38 -0700
      Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 05:57 -0700
        Re: Default Value Roy Smith <roy@panix.com> - 2013-06-20 09:19 -0400
          Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 06:31 -0700
          Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 00:17 +0000
            Re: Default Value Roy Smith <roy@panix.com> - 2013-06-20 20:25 -0400
        Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-20 07:49 -0700
          Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-21 01:38 +1000
            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-20 11:05 -0700
              Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 00:57 +0000
                Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-20 20:16 -0700
                  Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-21 17:10 +1000
                    Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 07:32 -0700
                  Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 16:22 +0000
              Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 15:57 +0000
                Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 10:01 -0700
                  Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-21 18:47 +0100
                    Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 11:26 -0700
                      Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 18:37 +0000
                        Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 12:18 -0700
                          Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 12:35 -0700
                      Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 05:07 +1000
                        Re: Default Value Neil Cerutti <neilc@norwich.edu> - 2013-06-21 19:20 +0000
                          Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 13:27 -0700
                        Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-22 01:31 +0000
                          Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 11:40 +1000
                          Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 18:42 -0700
                          Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-22 03:04 +0100
                            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 19:32 -0700
                              Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-22 20:36 +0100
                              Re: Default Value Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-06-22 18:51 -0400
                            Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-21 19:43 -0700
                          Re: Default Value Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-06-22 09:26 +0100
                      Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-21 20:25 +0100
                        Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 13:44 -0700
                          Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-21 23:49 +0100
                            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 16:51 -0700
                              Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-22 02:54 +0100
                            Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-22 01:15 +0000
                              Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-21 19:27 -0600
                                Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-21 19:32 -0700
                                  Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 19:55 -0700
                                    Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-21 23:23 -0700
                                      Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-22 08:07 -0700
                                        Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-22 08:31 -0700
                                        Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-22 09:11 -0700
                                Re: Default Value Grant Edwards <invalid@invalid.invalid> - 2013-06-24 14:22 +0000
                                  Re: [SPAM] Re: Default Value MRAB <python@mrabarnett.plus.com> - 2013-06-24 16:22 +0100
                              Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 11:41 +1000
                              Re: Default Value Michael Torrie <torriem@gmail.com> - 2013-06-21 20:46 -0600
                              Re: Default Value Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2013-06-22 16:40 +0200
                              Re: Default Value Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-06-22 12:49 -0400
                              Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-22 12:57 -0600
                              Re: Default Value Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-06-22 18:48 -0400
                      Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-22 00:40 +0100
                        Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 18:15 -0700
                          Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 11:37 +1000
                          Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-21 19:42 -0600
                          Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-21 19:38 -0600
                            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 19:40 -0700
                          Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-22 03:01 +0100
                            Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-22 12:18 +1000
                              Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-22 03:25 +0100
                            Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-22 18:19 +0100
                              Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-22 11:49 -0700
                                Re: Default Value Rotwang <sg552@hotmail.co.uk> - 2013-06-23 01:49 +0100
          Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 10:12 -0700
            Re: Default Value Chris Angelico <rosuav@gmail.com> - 2013-06-21 03:19 +1000
              Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 10:30 -0700
            Re: Default Value Ian Kelly <ian.g.kelly@gmail.com> - 2013-06-20 11:57 -0600
              Re: Default Value rusi <rustompmody@gmail.com> - 2013-06-20 11:15 -0700
              Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 01:08 +0000
                Re: Default Value Tim Chase <python.list@tim.thechases.com> - 2013-06-20 20:26 -0500
                  Re: Default Value Roy Smith <roy@panix.com> - 2013-06-20 21:40 -0400
                    Re: Default Value Tim Chase <python.list@tim.thechases.com> - 2013-06-20 21:02 -0500
            Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-20 11:07 -0700
              Re: Default Value alex23 <wuwei23@gmail.com> - 2013-06-21 10:55 +1000
            Re: Default Value 88888 Dihedral <dihedral88888@gmail.com> - 2013-06-20 19:18 -0700
            Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 02:26 +0000
            Re: Default Value "Lefavor, Matthew (GSFC-582.0)[MICROTEL LLC]" <matthew.lefavor@nasa.gov> - 2013-06-20 17:28 -0500
              Re: Default Value Rick Johnson <rantingrickjohnson@gmail.com> - 2013-06-21 08:17 -0700
          Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-21 01:28 +0000
    Re: Default Value Gary Herron <gherron@digipen.edu> - 2013-06-19 12:57 -0700
    Re: Default Value Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-06-20 01:17 +0000

Page 4 of 5 — ← Prev page 1 2 3 [4] 5  Next page →


#48902

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-06-21 19:38 -0600
Message-ID<mailman.3680.1371865594.3114.python-list@python.org>
In reply to#48893
On Fri, Jun 21, 2013 at 7:15 PM, Rick Johnson
<rantingrickjohnson@gmail.com> wrote:
>> > Let's imagine for a second if Python allowed mutable keys in
>> > a dictionary,
>> which it does
>
> Am i just to take your word for this? You cannot provide an
> example? Here, allow me to "break the ice":
>
>     # Literal
>     py> d = {[1]:2}
>     Traceback (most recent call last):
>       File "<pyshell#0>", line 1, in <module>
>         d = {[1]:2}
>     TypeError: unhashable type: 'list'
>     # Symbol
>     py> lst = [1]
>     py> d = {lst:2}
>     Traceback (most recent call last):
>       File "<pyshell#2>", line 1, in <module>
>         d = {lst:2}
>     TypeError: unhashable type: 'list'
>
> Hmm, maybe only certain mutables work? Great, more esoteric
> rules! Feel free to enlighten me since i'm not going to
> waste one second of my time pursuing the docs just to learn
> about ANOTHER unintuitive PyWart i have no use for.

The answer to this conundrum is staring you in the face.  Note that
the TypeError complains that you passed it an "unhashable" type, and
not that you passed it a "mutable" type.  If you want to take a
mutable type and make it hashable, just add a __hash__ method.

class HashableList(list):
    def __hash__(self):
        return 42

>>> d = dict()
>>> hl = HashableList(range(5))
>>> hl2 = HashableList(range(6, 10))
>>> d[hl] = 10
>>> d[hl2] = 20
>>> d
{[0, 1, 2, 3, 4]: 10, [6, 7, 8, 9]: 20}

Additionally, instances of user-defined classes are, by default, both
mutable and hashable.  This is safe because equality and hashing for
such objects are by default based on identity.  If you override the
__eq__ method though, then you lose hashability unless you explicitly
override __hash__ as well.
>
>> Now, I don't really believe that you think that the user
>> shouldn't be protected from doing one idiotic thing with
>> mutable dict keys but should be protected from doing
>> another idiotic thing with mutable default arguments,
>> especially as you've already been given a use case for the
>> latter. So I assume that The Benevolent Approach is not
>> the approach you would have gone for if you had designed
>> the language, right? If so then let's ignore it.
>
> You are correct. Finally, we can agree on something.
>
>> > ============================================================
>> >   The Apathetic Approach:
>> > ============================================================
>> > I could just assume that a programmer is responsible for the
>> > code he writes. If he passes mutables into a function as
>> > default arguments, and then mutates the mutable later, too
>> > bad, he'll understand the value of writing solid code after
>> > a few trips to exception Hell.
>>
>> It seems to me that this is exactly what currently happens.
>
> (is this lazy readers day? I swear i explained this earlier)
>
> And here is where you are wrong. In the current implementation
> python functions carry the state of mutable default arguments
> between successive calls. That's a flaw. Observe:
>
>     py> def foo(arg=[]):
>     ...     arg.append(1)
>     ...     print(arg)
>     ...
>     py> foo()
>     [1]
>     py> foo()
>     [1, 1]
>     py> foo()
>     [1, 1, 1]
>
> No, no, NO! That's wrong! Subroutines should be stateless.
> That means that an empty mutable default argument will
> ALWAYS be empty at each call of the subroutine.  This is
> what should happen:
>
>     py> def foo(arg=[]):
>     ...     arg.append(1)
>     ...     print(arg)
>     ...
>     py> foo()
>     [1]
>     py> foo()
>     [1]
>     py> foo()
>     [1]
>
> Yes, Yes, YES! That is intuitive! That is sane! Now, what if
> we pass a reference to a mutable object? What then. Well, let's
> see:
>
>     py> lst = range(5)
>     py> lst
>     [0, 1, 2, 3, 4]
>     py> def foo(arg=lst):
>     ...     arg.append(1)
>     ...     print(arg)
>     ...
>     py> foo()
>     [0, 1, 2, 3, 4, 1]
>     py> foo()
>     [0, 1, 2, 3, 4, 1, 1]
>
> That's fine. Because the object was already created OUTSIDE
> the subroutine. So therefore, modifications to the mutable
> are not breaking the fundamental of statelessness INSIDE
> subroutines. The modification is merely a side effect, and
> the subroutine is unconcerned with anything that exists
> beyond it's own scope.
>
> IS ALL THIS REGISTERING YET? DO YOU UNDERSTAND?
>
>> > ============================================================
>> >   The Malevolent Approach (disguised as beneva-loon-icy):
>> > ============================================================
>> > I could use early binding to confuse the hell out of him and
>> > enjoy the laughs with all my ivory tower buddies as he falls
>> > into fits of confusion and rage. Then enjoy again when he
>> > reads the docs. Ahh, the gift that just keeps on giving!
>> My question was about how you think the language should
>> work, not about what your buddies should or shouldn't
>> enjoy.
>
> My buddies? This design flaw is NOT my brain child. Your
> barking up the wrong tree pal.
>
>> In terms of how a language actually works, is there
>> any difference between The Malevolent Approach and The
>> Apathetic Approach? And is there any difference between
>> either of them and what Python currently does?
>
> I explained this to MRAB already.
>
>> Of course using a mutable default as a cache can be
>> reproduced by other means, as can another common use case
>> that I don't think anyone's mentioned yet (defining
>> functions parametrised by variables whose values aren't
>> known until runtime). That's hardly an argument against it
>> - you might as well argue that Python shouldn't have
>> decorators, or that it shouldn't have for loops because
>> their behaviour can be reproduced with while loops.
>
> Nice attempt at sleight of hand but your logic is clumsy.
>
> Your trying to argue that my use of a "custom callable state
> object" (to avoid the esoteric and unintuitive nature of the
> current implementation of Python "mutable function
> arguments") is somehow only a mere reproduction of the
> function behavior and has no positive benefits, when in
> fact, it has a HUGE direct benefit:
>
>  * AVOIDING A FLAW IN THE LANGUAGE
>
> It also has quite a few positive side effects:
>
>  * CODE ENCAPSULATION
>  * INTERFACE
>  * USING THE CORRECT TOOL FOR THE JOB++
>  * READABILITY
>  * NO HIDDEN SURPRISES
>  * LESS BUGGY
>
> How much more justification do you need?
>
>> or that it shouldn't have for loops because their
>> behaviour can be reproduced with while loops.
>
> Yes, iterating a sequence can be achieved using a "while
> loop", but "for loops" should not be thrown out because they
> offer a specific type of iteration that nicely complements a
> while loop. Plus, for loops do not have any strange side
> effects (unlike Python functions). They do one thing and
> they do damn well! So stop picking on for loops :-)
>
> I want Python functions to also "do one thing and do it
> well", and what is that "one thing" you ask, execute
> subprograms.
>
>> But this is beside the point anyway, until you present an
>> alternative to Python's current behavior. If you do so
>> then we can start debating the relative merits of the two
>> approaches.
>
> The fix is simple. No more "magical Python functions", only
> stateless routines. I've explained this ad nauseam already,
> and until you provide more specific questions on the matter,
> i refuse to reply to any more bombastically general questions.
>
> --
> http://mail.python.org/mailman/listinfo/python-list

[toc] | [prev] | [next] | [standalone]


#48911

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-21 19:40 -0700
Message-ID<86fa9f9b-cc32-4c53-8b9b-1abd126b3de8@googlegroups.com>
In reply to#48902
On Friday, June 21, 2013 8:38:21 PM UTC-5, Ian wrote:
> The answer to this conundrum is staring you in the face.

Thanks for posting a solution for this. Not sure if i'll
ever need it, but nice to know.

> Note that the TypeError complains that you passed it an
> "unhashable" type, and not that you passed it a "mutable"
> type.  If you want to take a mutable type and make it
> hashable, just add a __hash__ method.
> 
> class HashableList(list):
>     def __hash__(self):
>         return 42
> >>> d = dict()
> >>> hl = HashableList(range(5))
> >>> hl2 = HashableList(range(6, 10))
> >>> d[hl] = 10
> >>> d[hl2] = 20
> >>> d
> {[0, 1, 2, 3, 4]: 10, [6, 7, 8, 9]: 20}
> 
> Additionally, instances of user-defined classes are, by
> default, both mutable and hashable.  This is safe because
> equality and hashing for such objects are by default based
> on identity.  If you override the __eq__ method though,
> then you lose hashability unless you explicitly override
> __hash__ as well.

Hey, you went above and beyond to provide that last bit of info. 
Thanks again!

[toc] | [prev] | [next] | [standalone]


#48905

FromRotwang <sg552@hotmail.co.uk>
Date2013-06-22 03:01 +0100
Message-ID<kq308b$1ll$1@dont-email.me>
In reply to#48893
On 22/06/2013 02:15, Rick Johnson wrote:
> On Friday, June 21, 2013 6:40:51 PM UTC-5, Rotwang wrote:
>> On 21/06/2013 19:26, Rick Johnson wrote:
>> [...]
>> I didn't ask what alternative methods of handling default
>> argument binding exist (I can think of several, but none
>> of them strikes me as preferable to how Python currently
>> does it). I asked what would happen in /your/ version of
>> Python. Which of the alternatives that you present would
>> have been implemented, if you had designed the language?
>
> The apathetic approach. However, you fail to understand that
> whilst Python's current implementation is partly apathetic,
> is is also benevolent, and malevolent simultaneously. My
> approach is purely apathetic. I'll explain later. Stay
> tuned.

OK...


>> [...]
>> So how does the interpreter know whether an arbitrary
>> object passed as a default value is mutable or not? Not
>> that it really matters.
>
> Well i'm glad it does not matter to you because it does not
> matter to me either. *shrugs*
>
>>> Let's imagine for a second if Python allowed mutable keys in
>>> a dictionary,
>> which it does
>
> Am i just to take your word for this? You cannot provide an
> example?

Of course I can:

 >>> class hashablelist(list):
...     def __hash__(self):
...         return hash(tuple(self))
... 	
 >>> x = hashablelist(range(4))
 >>> x
[0, 1, 2, 3]
 >>> # Let's try using x as a dict key:
 >>> d = {x: 'Hello'}
 >>> d[x]
'Hello'
 >>> # Let's try mutating it:
 >>> x.append(4)
 >>> x
[0, 1, 2, 3, 4]


> Here, allow me to "break the ice":
>
>      # Literal
>      py> d = {[1]:2}
>      Traceback (most recent call last):
>        File "<pyshell#0>", line 1, in <module>
>          d = {[1]:2}
>      TypeError: unhashable type: 'list'
>      # Symbol
>      py> lst = [1]
>      py> d = {lst:2}
>      Traceback (most recent call last):
>        File "<pyshell#2>", line 1, in <module>
>          d = {lst:2}
>      TypeError: unhashable type: 'list'
>
> Hmm, maybe only certain mutables work?

Try reading the tracebacks. Notice how they don't say anything about 
mutability?


> Great, more esoteric
> rules! Feel free to enlighten me since i'm not going to
> waste one second of my time pursuing the docs just to learn
> about ANOTHER unintuitive PyWart i have no use for.

Sure. In order to be used as a dictionary key a Python has to be 
hashable. That means its type has to define a __hash__ method, which is 
called by the builtin function hash. The __hash__ method should return 
an int, and objects that compare equal should have the same hash.


>> Now, I don't really believe that you think that the user
>> shouldn't be protected from doing one idiotic thing with
>> mutable dict keys but should be protected from doing
>> another idiotic thing with mutable default arguments,
>> especially as you've already been given a use case for the
>> latter. So I assume that The Benevolent Approach is not
>> the approach you would have gone for if you had designed
>> the language, right? If so then let's ignore it.
>
> You are correct. Finally, we can agree on something.
>
>>> ============================================================
>>>    The Apathetic Approach:
>>> ============================================================
>>> I could just assume that a programmer is responsible for the
>>> code he writes. If he passes mutables into a function as
>>> default arguments, and then mutates the mutable later, too
>>> bad, he'll understand the value of writing solid code after
>>> a few trips to exception Hell.
>>
>> It seems to me that this is exactly what currently happens.
>
> (is this lazy readers day? I swear i explained this earlier)
>
> And here is where you are wrong. In the current implementation
> python functions carry the state of mutable default arguments
> between successive calls. That's a flaw.

But your description of The Apathetic Approach doesn't say anything 
about functions carrying the state of mutable default arguments, or 
otherwise. How am I supposed to know how your proposed approach treats 
mutable defaults if you don't tell me, even after I explicitly ask?


> Observe:
>
>      py> def foo(arg=[]):
>      ...     arg.append(1)
>      ...     print(arg)
>      ...
>      py> foo()
>      [1]
>      py> foo()
>      [1, 1]
>      py> foo()
>      [1, 1, 1]

Yes, I am well aware of how Python currently treats mutable default 
arguments.


> No, no, NO! That's wrong! Subroutines should be stateless.
> That means that an empty mutable default argument will
> ALWAYS be empty at each call of the subroutine.  This is
> what should happen:
>
>      py> def foo(arg=[]):
>      ...     arg.append(1)
>      ...     print(arg)
>      ...
>      py> foo()
>      [1]
>      py> foo()
>      [1]
>      py> foo()
>      [1]
>
> Yes, Yes, YES! That is intuitive! That is sane! Now, what if
> we pass a reference to a mutable object? What then. Well, let's
> see:
>
>      py> lst = range(5)
>      py> lst
>      [0, 1, 2, 3, 4]
>      py> def foo(arg=lst):
>      ...     arg.append(1)
>      ...     print(arg)
>      ...
>      py> foo()
>      [0, 1, 2, 3, 4, 1]
>      py> foo()
>      [0, 1, 2, 3, 4, 1, 1]
>
> That's fine. Because the object was already created OUTSIDE
> the subroutine. So therefore, modifications to the mutable
> are not breaking the fundamental of statelessness INSIDE
> subroutines. The modification is merely a side effect, and
> the subroutine is unconcerned with anything that exists
> beyond it's own scope.
>
> IS ALL THIS REGISTERING YET? DO YOU UNDERSTAND?

No, I don't. These two special cases are not sufficient for me to 
determine what semantics you are proposing for the general case. For 
example, what happens in the second example if lst is rebound? Does the 
default stay the same or does it change to the new value of lst? What 
about if you pass a call as a default argument, and then subsequently 
change the behaviour of the callable? Does the argument get re-evaluated 
every time foo() is called, or is the argument guaranteed to be the same 
every time? If the latter, what happens if the arguments type is 
modified (e.g. by changing one of its class attributes)? What about 
defining functions dynamically, with default arguments that are only 
known at runtime? Is there any way to avoid the second type of behaviour 
in this case? If so, how? If not, isn't that likely to prove at least as 
big a gotcha to people who don't know the rules of RickPy as the problem 
you're trying to solve?


>>> ============================================================
>>>    The Malevolent Approach (disguised as beneva-loon-icy):
>>> ============================================================
>>> I could use early binding to confuse the hell out of him and
>>> enjoy the laughs with all my ivory tower buddies as he falls
>>> into fits of confusion and rage. Then enjoy again when he
>>> reads the docs. Ahh, the gift that just keeps on giving!
>> My question was about how you think the language should
>> work, not about what your buddies should or shouldn't
>> enjoy.
>
> My buddies? This design flaw is NOT my brain child. Your
> barking up the wrong tree pal.

But I didn't ask about Python's current approach, which I already 
understand quite well. I was asking about what your approach would be. 
If this is not your brainchild then why were you telling me about it?


>> In terms of how a language actually works, is there
>> any difference between The Malevolent Approach and The
>> Apathetic Approach? And is there any difference between
>> either of them and what Python currently does?
>
> I explained this to MRAB already.

But you haven't said how you test an object for mutability.


>> Of course using a mutable default as a cache can be
>> reproduced by other means, as can another common use case
>> that I don't think anyone's mentioned yet (defining
>> functions parametrised by variables whose values aren't
>> known until runtime). That's hardly an argument against it
>> - you might as well argue that Python shouldn't have
>> decorators, or that it shouldn't have for loops because
>> their behaviour can be reproduced with while loops.
>
> Nice attempt at sleight of hand but your logic is clumsy.
>
> Your trying to argue that my use of a "custom callable state
> object" (to avoid the esoteric and unintuitive nature of the
> current implementation of Python "mutable function
> arguments") is somehow only a mere reproduction of the
> function behavior and has no positive benefits, when in
> fact, it has a HUGE direct benefit:
>
>   * AVOIDING A FLAW IN THE LANGUAGE

But it doesn't avoid a flaw in the language, unless you get rid of 
function defaults altogether. As long as functions can have default 
arguments, people are going to try passing mutable ones. Avoiding the 
alleged "flaw" in the language means proposing a different semantics for 
when they do, not just explaining how the current behaviour can be 
reproduced in other ways (which nobody AFAICR has denied).


> It also has quite a few positive side effects:
>
>   * CODE ENCAPSULATION
>   * INTERFACE
>   * USING THE CORRECT TOOL FOR THE JOB++
>   * READABILITY
>   * NO HIDDEN SURPRISES
>   * LESS BUGGY
>
> How much more justification do you need?

I don't need more justification, I just need you to tell me 
unambiguously what alternative behaviour you're proposing. I can't 
really compare the pros and cons of the two approaches if I only know 
one of them.


>> or that it shouldn't have for loops because their
>> behaviour can be reproduced with while loops.
>
> Yes, iterating a sequence can be achieved using a "while
> loop", but "for loops" should not be thrown out because they
> offer a specific type of iteration that nicely complements a
> while loop. Plus, for loops do not have any strange side
> effects (unlike Python functions).

They exhaust iterators. Whether that is considered "strange" depends on 
who is doing the considering (Python's default binding behaviour doesn't 
seem strange to most people who are familiar with its data model).


> They do one thing and
> they do damn well! So stop picking on for loops :-)
>
> I want Python functions to also "do one thing and do it
> well", and what is that "one thing" you ask, execute
> subprograms.
>
>> But this is beside the point anyway, until you present an
>> alternative to Python's current behavior. If you do so
>> then we can start debating the relative merits of the two
>> approaches.
>
> The fix is simple. No more "magical Python functions", only
> stateless routines.

So no generators, then?

[toc] | [prev] | [next] | [standalone]


#48907

FromChris Angelico <rosuav@gmail.com>
Date2013-06-22 12:18 +1000
Message-ID<mailman.3684.1371867545.3114.python-list@python.org>
In reply to#48905
On Sat, Jun 22, 2013 at 12:01 PM, Rotwang <sg552@hotmail.co.uk> wrote:
>>>> class hashablelist(list):
> ...     def __hash__(self):
> ...         return hash(tuple(self))

There's a vulnerability in that definition:

>>> a=hashablelist((1,[],3))
>>> a
[1, [], 3]
>>> {a:1}
Traceback (most recent call last):
  File "<pyshell#255>", line 1, in <module>
    {a:1}
  File "<pyshell#249>", line 3, in __hash__
    return hash(tuple(self))
TypeError: unhashable type: 'list'

Of course, if you monkey-patch list itself to have this functionality,
or always use hashablelist instead of list, then it will work. But
it's still vulnerable.

ChrisA

[toc] | [prev] | [next] | [standalone]


#48908

FromRotwang <sg552@hotmail.co.uk>
Date2013-06-22 03:25 +0100
Message-ID<kq31lm$7g5$1@dont-email.me>
In reply to#48907
On 22/06/2013 03:18, Chris Angelico wrote:
> On Sat, Jun 22, 2013 at 12:01 PM, Rotwang <sg552@hotmail.co.uk> wrote:
>>>>> class hashablelist(list):
>> ...     def __hash__(self):
>> ...         return hash(tuple(self))
>
> There's a vulnerability in that definition:
>
>>>> a=hashablelist((1,[],3))
>>>> a
> [1, [], 3]
>>>> {a:1}
> Traceback (most recent call last):
>    File "<pyshell#255>", line 1, in <module>
>      {a:1}
>    File "<pyshell#249>", line 3, in __hash__
>      return hash(tuple(self))
> TypeError: unhashable type: 'list'
>
> Of course, if you monkey-patch list itself to have this functionality,
> or always use hashablelist instead of list, then it will work. But
> it's still vulnerable.

Quite right, sorry. I should have called my class 
"sometimeshashablelist", or something.

[toc] | [prev] | [next] | [standalone]


#48936

FromRotwang <sg552@hotmail.co.uk>
Date2013-06-22 18:19 +0100
Message-ID<kq4m1f$dg0$1@dont-email.me>
In reply to#48905
On 22/06/2013 03:01, I wrote:
> On 22/06/2013 02:15, Rick Johnson wrote:
>> [...]
>>
>> This is what should happen:
>>
>>      py> def foo(arg=[]):
>>      ...     arg.append(1)
>>      ...     print(arg)
>>      ...
>>      py> foo()
>>      [1]
>>      py> foo()
>>      [1]
>>      py> foo()
>>      [1]
>>
>> Yes, Yes, YES! That is intuitive! That is sane! Now, what if
>> we pass a reference to a mutable object? What then. Well, let's
>> see:
>>
>>      py> lst = range(5)
>>      py> lst
>>      [0, 1, 2, 3, 4]
>>      py> def foo(arg=lst):
>>      ...     arg.append(1)
>>      ...     print(arg)
>>      ...
>>      py> foo()
>>      [0, 1, 2, 3, 4, 1]
>>      py> foo()
>>      [0, 1, 2, 3, 4, 1, 1]
>>
>> That's fine. Because the object was already created OUTSIDE
>> the subroutine. So therefore, modifications to the mutable
>> are not breaking the fundamental of statelessness INSIDE
>> subroutines. The modification is merely a side effect, and
>> the subroutine is unconcerned with anything that exists
>> beyond it's own scope.
>>
>> IS ALL THIS REGISTERING YET? DO YOU UNDERSTAND?
>
> No, I don't. These two special cases are not sufficient for me to
> determine what semantics you are proposing for the general case. For
> example, what happens in the second example if lst is rebound? Does the
> default stay the same or does it change to the new value of lst? What
> about if you pass a call as a default argument, and then subsequently
> change the behaviour of the callable? Does the argument get re-evaluated
> every time foo() is called, or is the argument guaranteed to be the same
> every time? If the latter, what happens if the arguments type is
> modified (e.g. by changing one of its class attributes)? What about
> defining functions dynamically, with default arguments that are only
> known at runtime? Is there any way to avoid the second type of behaviour
> in this case? If so, how? If not, isn't that likely to prove at least as
> big a gotcha to people who don't know the rules of RickPy as the problem
> you're trying to solve?

Since you haven't answered this, allow me to suggest something. One 
thing that a language could do is treat default arguments as mini 
function definitions with their own scope, which would be the same as 
the scope of the function itself but without the function's arguments. 
In other words, in this alternative version of Python, the following

 >>> def f(x = <expression>):
...    <stuff>

would be equivalent, in actual Python, to this:

 >>> default = lambda: <expression>
 >>> sentinel = object()
 >>> def f(x = sentinel):
...    if x is sentinel:
...        x = default()
...    <stuff>

That would be something that could be implemented, and as far as I can 
tell it's consistent with the examples you've given of how you would 
like Python to work. Is this indeed the kind of thing you have in mind?

[toc] | [prev] | [next] | [standalone]


#48940

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-22 11:49 -0700
Message-ID<399f0ad3-9554-4b28-b4f5-588074f82655@googlegroups.com>
In reply to#48936
On Saturday, June 22, 2013 12:19:31 PM UTC-5, Rotwang wrote:
> > On 22/06/2013 02:15, Rick Johnson wrote:
> > IS ALL THIS REGISTERING YET? DO YOU UNDERSTAND?
> 
> No, I don't. These two special cases are not sufficient
> for me to determine what semantics you are proposing for
> the general case. 

============================================================
 QUESTION 1:
============================================================
> For example, what happens in the second
> example if lst is rebound? 

Well nothing could happen, or something significant could
happen. How do you expect me to determine an answer for
such a general question when i have no context, or any 
algorithms to work from. 

Maybe you are trying to set a situation that results in
chaos, okay, then chaos will happen. But who's fault is the
chaos when a programmer is rebinding names? The programmer
is ultimately responsible for his action. 

  Remember my "Apathetic Approach"?

============================================================
 QUESTION 2:
============================================================
> Does the default stay the same or does it change to the
> new value of lst?

Here you go again, you cannot seem to comprehend very simple
concepts. My second example clearly explains what will happen

>>      py> lst = range(5)
>>      py> lst
>>      [0, 1, 2, 3, 4]
>>      py> def foo(arg=lst):
>>      ...     arg.append(1)
>>      ...     print(arg)
>>      ...
>>      py> foo()
>>      [0, 1, 2, 3, 4, 1]
>>      py> foo()
>>      [0, 1, 2, 3, 4, 1, 1] 

Do you see how the name 'lst' is bound to a list object
living in global module scope? Do you see how the default
argument (named `arg`) is a reference to a global list named
`lst`?

 ARE YOU FOLLOWING ALONG SO FAR?

Since the mutable arg exists OUTSIDE the subroutine, the
subroutine merely need to provide access to the global
*name* `lst` from within the body of the subroutine, and the
subroutine merely do this ONCE at compile time!

 ARE YOU FAMILIAR WITH THE CONCEPT OF POINTERS?

============================================================
 QUESTION 3-A:
============================================================
> What about if you pass a call as a default argument, and
> then subsequently change the behaviour of the callable?

Hmm, let's have a thought experiment. What if i give you a
digital birthday card. And when you open the card you see a
friendly note from me:

 "Rotwang is my best friend in the whole wide world". 

But unbeknownst to you, i have actually hacked the card and
installed a secret wifi device. I've made the message
mutable -- hmm, surely nothing "bad" could arise from
mutability correct?

 *evil-grin*

A few hours later when you open the card to show to some
friends, you are alarmed to see a new message:

 "Rotwang is a degenerative penis condition"
 
Now, besides being embarrassed, and probably angry as hell,
do you understand the dangers of mutable objects? 

I'm not suggesting you don't ever want to use the power of
mutability, no, but you do need to have a healthy respect for
mutability -- because it can really ruin your day!

============================================================
 QUESTION 3-B:
============================================================
> Does the argument get re-evaluated every time foo() is
> called, or is the argument guaranteed to be the same every
> time?

If the argument is an expression, like a literal, it will be
reset to the literal each time the subroutine is called. If
the argument is a non-local object, the argument will NOT be
reset each time. See "ANSWER 2" for more context.
 
============================================================
 QUESTION 3-C:
============================================================
> If the latter, what happens if the arguments type is
> modified (e.g. by changing one of its class attributes)?
> What about defining functions dynamically, with default
> arguments that are only known at runtime? Is there any way
> to avoid the second type of behaviour in this case? If so,
> how? If not, isn't that likely to prove at least as big a
> gotcha to people who don't know the rules of RickPy as the
> problem you're trying to solve?

What if X? 
What if Y? 
What i pass in a pony but i sell it to a glue factory before 
the subroutine gets called???

I'm sorry but have no more patience for these ridiculous
questions. If you want me to answer *specific* questions, then
be sure to ask them one at a time and provide relevant code
examples.

[toc] | [prev] | [next] | [standalone]


#48958

FromRotwang <sg552@hotmail.co.uk>
Date2013-06-23 01:49 +0100
Message-ID<kq5gcc$d6c$1@dont-email.me>
In reply to#48940
On 22/06/2013 19:49, Rick Johnson wrote:
> On Saturday, June 22, 2013 12:19:31 PM UTC-5, Rotwang wrote:
>>> On 22/06/2013 02:15, Rick Johnson wrote:
>>> IS ALL THIS REGISTERING YET? DO YOU UNDERSTAND?
>>
>> No, I don't. These two special cases are not sufficient
>> for me to determine what semantics you are proposing for
>> the general case.
>
> ============================================================
>   QUESTION 1:
> ============================================================
>> For example, what happens in the second
>> example if lst is rebound?
>
> Well nothing could happen, or something significant could
> happen. How do you expect me to determine an answer for
> such a general question when i have no context, or any
> algorithms to work from.

You don't have an algorithm to work from? I assumed you did. If you 
don't have an algorithm in mind as an alternative to Python's existing 
behaviour, then what exactly is your point?

Anyway, I already proposed an algorithm that is consistent with your 
examples, in

   http://mail.python.org/pipermail/python-list/2013-June/650447.html

. Is that what you have in mind?


> Maybe you are trying to set a situation that results in
> chaos, okay, then chaos will happen.

No, I'm not. I'm simply trying to find out what alternative behaviour 
you're proposing for Python, because the examples you've given so far 
are not sufficient to explain what happens in the general case.


> But who's fault is the
> chaos when a programmer is rebinding names? The programmer
> is ultimately responsible for his action.
>
>    Remember my "Apathetic Approach"?
>
> ============================================================
>   QUESTION 2:
> ============================================================
>> Does the default stay the same or does it change to the
>> new value of lst?
>
> Here you go again, you cannot seem to comprehend very simple
> concepts. My second example clearly explains what will happen
>
>>>       py> lst = range(5)
>>>       py> lst
>>>       [0, 1, 2, 3, 4]
>>>       py> def foo(arg=lst):
>>>       ...     arg.append(1)
>>>       ...     print(arg)
>>>       ...
>>>       py> foo()
>>>       [0, 1, 2, 3, 4, 1]
>>>       py> foo()
>>>       [0, 1, 2, 3, 4, 1, 1]

No, it doesn't, because lst is not rebound in your second example. As 
such, entering >>> lst = []; foo() could return [1], or it could return 
[0, 1, 2, 3, 4, 1, 1, 1]. Both of those could result from behaviours 
that gave the exact same output as the two examples you've given. It is 
literally impossible for me to know what you would like to see happen in 
this case from the limited information you've given me.

On the other hand, from the specification I gave earlier it's easy to 
see that >>> lst = []; foo() would return [1]. Is this what you want?


> Do you see how the name 'lst' is bound to a list object
> living in global module scope? Do you see how the default
> argument (named `arg`) is a reference to a global list named
> `lst`?
>
>   ARE YOU FOLLOWING ALONG SO FAR?
>
> Since the mutable arg exists OUTSIDE the subroutine, the
> subroutine merely need to provide access to the global
> *name* `lst` from within the body of the subroutine, and the
> subroutine merely do this ONCE at compile time!
>
>   ARE YOU FAMILIAR WITH THE CONCEPT OF POINTERS?

Yes, but Python doesn't have them. Are you proposing that it should have 
them, and that they should play some role in Python default binding 
behaviour? If so then a better way of making people aware of this would 
be to tell them, rather than expecting them to guess and then pretending 
that their failure to do so represents some failing on their part.


> ============================================================
>   QUESTION 3-A:
> ============================================================
>> What about if you pass a call as a default argument, and
>> then subsequently change the behaviour of the callable?
>
> Hmm, let's have a thought experiment. What if i give you a
> digital birthday card. And when you open the card you see a
> friendly note from me:
>
>   "Rotwang is my best friend in the whole wide world".
>
> But unbeknownst to you, i have actually hacked the card and
> installed a secret wifi device. I've made the message
> mutable -- hmm, surely nothing "bad" could arise from
> mutability correct?
>
>   *evil-grin*
>
> A few hours later when you open the card to show to some
> friends, you are alarmed to see a new message:
>
>   "Rotwang is a degenerative penis condition"
>
> Now, besides being embarrassed, and probably angry as hell,
> do you understand the dangers of mutable objects?

Yes. As I expect you already know, I'm well aware of the dangers of 
mutable objects. But that isn't what I'm asking you about. I'm asking 
you what method you propose to avoid one of those dangers. Why don't you 
just answer the question, instead of answering a different question I 
didn't ask?


> I'm not suggesting you don't ever want to use the power of
> mutability, no, but you do need to have a healthy respect for
> mutability -- because it can really ruin your day!
>
> ============================================================
>   QUESTION 3-B:
> ============================================================
>> Does the argument get re-evaluated every time foo() is
>> called, or is the argument guaranteed to be the same every
>> time?
>
> If the argument is an expression, like a literal, it will be
> reset to the literal each time the subroutine is called. If
> the argument is a non-local object, the argument will NOT be
> reset each time.

Notice how neither of those answers the question I asked? I asked what 
happens when the argument is a call.


> ============================================================
>   QUESTION 3-C:
> ============================================================
>> If the latter, what happens if the arguments type is
>> modified (e.g. by changing one of its class attributes)?
>> What about defining functions dynamically, with default
>> arguments that are only known at runtime? Is there any way
>> to avoid the second type of behaviour in this case? If so,
>> how? If not, isn't that likely to prove at least as big a
>> gotcha to people who don't know the rules of RickPy as the
>> problem you're trying to solve?
>
> What if X?
> What if Y?
> What i pass in a pony but i sell it to a glue factory before
> the subroutine gets called???
>
> I'm sorry but have no more patience for these ridiculous
> questions. If you want me to answer *specific* questions, then
> be sure to ask them one at a time and provide relevant code
> examples.

Please answer the question I asked in

   http://mail.python.org/pipermail/python-list/2013-June/650447.html

.

[toc] | [prev] | [next] | [standalone]


#48809

Fromrusi <rustompmody@gmail.com>
Date2013-06-20 10:12 -0700
Message-ID<09cfa648-ab87-4261-b8f0-bf493de00553@4g2000pbf.googlegroups.com>
In reply to#48796
You know Rick, you are good at python, you are better at polemics.
If only you would cut the crap I would (be able to) agree with you.
See below

On Jun 20, 7:49 pm, Rick Johnson <rantingrickjohn...@gmail.com> wrote:
> On Thursday, June 20, 2013 7:57:06 AM UTC-5, rusi wrote:
> > Every language has gotchas. This is one of python's.
>
> So are we purposely injecting illogic into our language just
> to be part of some "cool crowd" of programming languages with
> gotchas.
>
>  "You thought intuitiveness was a virtue? Haha, we gotcha!"


Python (and all the other 'cool' languages) dont have gotchas because
someone malevolently put them there.
In most cases, the problem is seen too late and the cost of changing
entrenched code too great.
Or the problem is clear, the solution is not etc etc.

>
> Or maybe this is reminiscent of the fraternity hazing rituals
> of days gone by:
>
>  *POP*
>  "Thank you Sir, may i have another?"
>
> > If you are a beginning python programmer, really the best
> > answer is: Just dont do it!  Dont do what? Dont use
> > mutable arguments as function defaults. Once you cross the
> > noob stage you can check that its a standard gotcha: Just
> > run a search for 'python gotcha default []'
>
> > And when you feel that you need to, use Steven's trick:
> > use a immutable indicator 'None' for the mutable []. Once
> > you cross the noob stage you can check that its a standard
> > gotcha: Just run a search for 'python gotcha default []'
> > Its even been discussed repeatedly on the python-ideas
> > list
>
> Your attempting to excuse an inexcusable language flaw by
> pointing out that the effects of the flaw can be avoided by
> using a workaround. And, to add insult to injury, you
> provide no good reason for the flaw to exist:
>
>  "Just do x, y, and z and shut up. Yes we made a mistake
>  but we are not about to admit our mistake and the onerous
>  will be on all the noobs to re-invent the workaround each
>  time"
>
> To me that is unacceptable.
>
> > Heres a correction suggestion: [...] Here's Terry Reedy's
> > nicely explaining the 'why-of-the-how' : [...] FWIW here
> > is a conceptual/philosophical explanation of your
> > confusion: There are 2 fundamental ways for approaching
> > the programming task -- functional and imperative.
>
> All these "explanations" ignore a fundamental fact about
> subroutines[1].

>
> A call to a subroutine should exists as a unique transaction
> within the entire program. It is expected to optionally take
> inputs, and optionally return an output (depending on the
> definition).
>
> When the subroutine is completed, all inputs and local
> variables are expected to be destroyed. If the programmer
> wants a return value, he need simply ask. Data persistence
> is not a function of subroutines! Finally, a subroutine
> should never have side effects UNLESS the programmer
> explicitly ask for a side effect.
>
> However, the Python flaw of allowing mutable sequence
> arguments to persist between successive calls of a
> subroutine is breaking the entire definition of a
> subroutine, and for what noble purpose i ask? What purpose
> is SO important that you change a well established interface
> in a totally unintuitive manner?
>
> If your answer is that recursion is easier, then i say that
> is foolish because a programmer can keep a reference
> to a mutable sequence OUTSIDE the subroutine and you can
> save the "gotchas" for Guido's next birthday party.
>
> [1]:http://en.wikipedia.org/wiki/Subroutine


You are saying in different language what I said: Functional
programming is a good idea, imperative programming is a bad idea.
From the invention of subroutines (ie 50 years) PL designers are
hearing this truth but somehow or other fail to listen; for more
details see http://blog.languager.org/2012/11/imperative-programming-lessons-not.html

[toc] | [prev] | [next] | [standalone]


#48811

FromChris Angelico <rosuav@gmail.com>
Date2013-06-21 03:19 +1000
Message-ID<mailman.3633.1371748769.3114.python-list@python.org>
In reply to#48809
On Fri, Jun 21, 2013 at 3:12 AM, rusi <rustompmody@gmail.com> wrote:
> Python (and all the other 'cool' languages) dont have gotchas because
> someone malevolently put them there.
> In most cases, the problem is seen too late and the cost of changing
> entrenched code too great.
> Or the problem is clear, the solution is not etc etc.

Or, in many MANY cases, the choice was the right one, but isn't
obvious to everyone.

ChrisA

[toc] | [prev] | [next] | [standalone]


#48815

Fromrusi <rustompmody@gmail.com>
Date2013-06-20 10:30 -0700
Message-ID<7140726f-1549-4537-8175-fe14b22e0e3b@v10g2000pbv.googlegroups.com>
In reply to#48811
On Jun 20, 10:19 pm, Chris Angelico <ros...@gmail.com> wrote:
> On Fri, Jun 21, 2013 at 3:12 AM, rusi <rustompm...@gmail.com> wrote:
> > Python (and all the other 'cool' languages) dont have gotchas because
> > someone malevolently put them there.
> > In most cases, the problem is seen too late and the cost of changing
> > entrenched code too great.
> > Or the problem is clear, the solution is not etc etc.
>
> Or, in many MANY cases, the choice was the right one, but isn't
> obvious to everyone.
>
> ChrisA

Ha!

If you've ever taught a first programming class you would know how
frequent is the complaint (said by a beginning student in a loud
confident voice): THE COMPILER HAS A BUG!

[toc] | [prev] | [next] | [standalone]


#48816

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-06-20 11:57 -0600
Message-ID<mailman.3636.1371751097.3114.python-list@python.org>
In reply to#48809
On Thu, Jun 20, 2013 at 11:19 AM, Chris Angelico <rosuav@gmail.com> wrote:
> On Fri, Jun 21, 2013 at 3:12 AM, rusi <rustompmody@gmail.com> wrote:
>> Python (and all the other 'cool' languages) dont have gotchas because
>> someone malevolently put them there.
>> In most cases, the problem is seen too late and the cost of changing
>> entrenched code too great.
>> Or the problem is clear, the solution is not etc etc.
>
> Or, in many MANY cases, the choice was the right one, but isn't
> obvious to everyone.

I think it's worth pointing out that changing function defaults to
late-binding would merely change the nature of the gotcha, not eliminate it.

words = ("one", "two", "red", "blue", "fish")

def join_strings(strings=words):
    return ' '.join('%s %s' % (s, strings[-1]) for s in strings[:-1])

# Later:
words = open("gettysburg_address.txt", "r").read().split()
# Oops, the default argument of join_strings just changed.


Additionally, with late-binding semantics the default values would no
longer be default *values*.  They would be initialization code
instead, which sort of flies in the face of the idea that late-binding
would somehow be better for functional programming -- if the default
expressions have no side effects and since they don't depend on the
function arguments, why should they need to run more than once?  If
the goal is indeed to make the the functions more functional, then the
proper solution would be to keep the binding early but just disallow
mutable defaults altogether -- which is tricky to achieve in Python,
so we simply emulate it with the advice "don't use mutable function
defaults".

[toc] | [prev] | [next] | [standalone]


#48819

Fromrusi <rustompmody@gmail.com>
Date2013-06-20 11:15 -0700
Message-ID<8cdfd28f-8170-4360-9dfe-1544929daf9b@jr6g2000pbb.googlegroups.com>
In reply to#48816
On Jun 20, 10:57 pm, Ian Kelly <ian.g.ke...@gmail.com> wrote:
> If
> the goal is indeed to make the the functions more functional, then the
> proper solution would be to keep the binding early but just disallow
> mutable defaults altogether -- which is tricky to achieve in Python,
> so we simply emulate it with the advice "don't use mutable function
> defaults".


Nicely put.  "Imperative programming is a bad idea; FP is a good idea"
is an attractive religious dogma.
When put into practice with full religious zeal, we then need
something like monads to make realistic programming possible.
Which then becomes a case of "remedy worse than disease".

Which is why I prefer to keep FP in the limbo region between ideology
and technology

[toc] | [prev] | [next] | [standalone]


#48834

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-06-21 01:08 +0000
Message-ID<51c3a799$0$29999$c3e8da3$5496439d@news.astraweb.com>
In reply to#48816
On Thu, 20 Jun 2013 11:57:34 -0600, Ian Kelly wrote:

> Additionally, with late-binding semantics the default values would no
> longer be default *values*.  They would be initialization code instead,
> which sort of flies in the face of the idea that late-binding would
> somehow be better for functional programming -- if the default
> expressions have no side effects and since they don't depend on the
> function arguments, why should they need to run more than once?  If the
> goal is indeed to make the the functions more functional, then the
> proper solution would be to keep the binding early but just disallow
> mutable defaults altogether -- which is tricky to achieve in Python, so
> we simply emulate it with the advice "don't use mutable function
> defaults".


Well said!


At the risk of having twice as many gotchas, and at making the 
implementation become even more complex, I would very slightly lean 
towards allowing some sort of syntactic sugar for late binding default 
values just to shut people up about this issue. Here's my syntax plucked 
out of thin air:

def func(arg, x=expression, !y=expression):
    ...

where y=expression is late-bound, and the above is compiled to:

def func(arg, x=expression, y=None):
    if y is None:
        y = expression
    ...


Then Ranting Rick can bitch and moan about how this violates "Explicit is 
better than implicit".


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#48837

FromTim Chase <python.list@tim.thechases.com>
Date2013-06-20 20:26 -0500
Message-ID<mailman.3647.1371777895.3114.python-list@python.org>
In reply to#48834
On 2013-06-21 01:08, Steven D'Aprano wrote:
> Here's my syntax plucked out of thin air:
> 
> def func(arg, x=expression, !y=expression):
>     ...
> 
> where y=expression is late-bound, and the above is compiled to:
> 
> def func(arg, x=expression, y=None):
>     if y is None:
>         y = expression
>     ...

I think it would have to translate to something like

  _temp_semaphore = object()
  def func(arg, x=expression, y=_temp_semaphore):
    if y is _temp_semaphore:
      y = expression

    ...

because there are times you want to be able to pass None as a legit
value in such a case (speaking from the trenches after getting stung
by exactly that case on multiple occasions).

-tkc

[toc] | [prev] | [next] | [standalone]


#48838

FromRoy Smith <roy@panix.com>
Date2013-06-20 21:40 -0400
Message-ID<roy-6BA13F.21401120062013@news.panix.com>
In reply to#48837
In article <mailman.3647.1371777895.3114.python-list@python.org>,
 Tim Chase <python.list@tim.thechases.com> wrote:

> On 2013-06-21 01:08, Steven D'Aprano wrote:
> > Here's my syntax plucked out of thin air:
> > 
> > def func(arg, x=expression, !y=expression):
> >     ...
> > 
> > where y=expression is late-bound, and the above is compiled to:
> > 
> > def func(arg, x=expression, y=None):
> >     if y is None:
> >         y = expression
> >     ...
> 
> I think it would have to translate to something like
> 
>   _temp_semaphore = object()
>   def func(arg, x=expression, y=_temp_semaphore):
>     if y is _temp_semaphore:
>       y = expression
> 
>     ...
> 
> because there are times you want to be able to pass None as a legit
> value in such a case (speaking from the trenches after getting stung
> by exactly that case on multiple occasions).

You can go around and around on that one.  Whatever distinguished value 
you set aside to mean "no argument passed", somebody will come up with a 
use case for why they might want to pass that as a real value.

If you really want to avoid then, then you need to go to something like:

def func(arg, **kwargs):
    if 'x' not in kwargs:
        kwargs['x'] = expression

and so on.  But that's klunky enough, I'm willing to accept the in-band 
signalling consequences of using None as a sentinel.

[toc] | [prev] | [next] | [standalone]


#48839

FromTim Chase <python.list@tim.thechases.com>
Date2013-06-20 21:02 -0500
Message-ID<mailman.3649.1371780021.3114.python-list@python.org>
In reply to#48838
On 2013-06-20 21:40, Roy Smith wrote:
> In article <mailman.3647.1371777895.3114.python-list@python.org>,
>  Tim Chase <python.list@tim.thechases.com> wrote:
> 
> > On 2013-06-21 01:08, Steven D'Aprano wrote:
> > > Here's my syntax plucked out of thin air:
> > > 
> > > def func(arg, x=expression, !y=expression):
> > >     ...
> > > 
> > > where y=expression is late-bound, and the above is compiled to:
> > > 
> > > def func(arg, x=expression, y=None):
> > >     if y is None:
> > >         y = expression
> > >     ...
> > 
> > I think it would have to translate to something like
> > 
> >   _temp_semaphore = object()
> >   def func(arg, x=expression, y=_temp_semaphore):
> >     if y is _temp_semaphore:
> >       y = expression
> > 
> >     ...
> 
> You can go around and around on that one.  Whatever distinguished
> value you set aside to mean "no argument passed", somebody will
> come up with a use case for why they might want to pass that as a
> real value.

That's why I suggested using an "is" test against a custom/local(ish)
semaphore instance that is only used for the particular invocation in
which the "def" statement occurs.

-tkc



[toc] | [prev] | [next] | [standalone]


#48818

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-06-20 11:07 -0700
Message-ID<660f143f-27a9-4991-85db-c996d493b610@googlegroups.com>
In reply to#48809
On Thursday, June 20, 2013 12:12:01 PM UTC-5, rusi wrote:

> Python (and all the other 'cool' languages) dont have
> gotchas because someone malevolently put them there. In
> most cases, the problem is seen too late and the cost of
> changing entrenched code too great. 

Okay. So now you are admitting the problem. That is a good
start. Thanks for being honest.

> Or the problem is clear, the solution is not etc etc.

Both the problem and solution are clear, however, the will to execute
the solution remains to be seem. Are you telling me we can
justify breaking backwards compatibility for the sake of
"print"[1] but we cannot justify breaking it for this
monstrosity? Come on Rusi, you've gone too far with the
comedy now.

[1]: FYI I personally think print as function is the correct implementation.

[toc] | [prev] | [next] | [standalone]


#48831

Fromalex23 <wuwei23@gmail.com>
Date2013-06-21 10:55 +1000
Message-ID<kq0813$pge$1@dont-email.me>
In reply to#48818
On 21/06/2013 4:07 AM, Rick Johnson wrote:
> Okay. So now you are admitting the problem. That is a good
> start. Thanks for being honest.

If you think mutable default arguments is a "problem", then you don't 
really understand Python. The only "gotcha" here is in people's heads.

[toc] | [prev] | [next] | [standalone]


#48840

From88888 Dihedral <dihedral88888@gmail.com>
Date2013-06-20 19:18 -0700
Message-ID<2ad7d32b-90de-4516-9a4c-88f2dd454c4c@googlegroups.com>
In reply to#48809
rusi於 2013年6月21日星期五UTC+8上午1時12分01秒寫道:
> You know Rick, you are good at python, you are better at polemics.
> 
> If only you would cut the crap I would (be able to) agree with you.
> 
> See below
> 
> 
> 
> On Jun 20, 7:49 pm, Rick Johnson <rantingrickjohn...@gmail.com> wrote:
> 
> > On Thursday, June 20, 2013 7:57:06 AM UTC-5, rusi wrote:
> 
> > > Every language has gotchas. This is one of python's.
> 
> >
> 
> > So are we purposely injecting illogic into our language just
> 
> > to be part of some "cool crowd" of programming languages with
> 
> > gotchas.
> 
> >
> 
> >  "You thought intuitiveness was a virtue? Haha, we gotcha!"
> 
> 
> 
> 
> 
> Python (and all the other 'cool' languages) dont have gotchas because
> 
> someone malevolently put them there.
> 
> In most cases, the problem is seen too late and the cost of changing
> 
> entrenched code too great.
> 
> Or the problem is clear, the solution is not etc etc.
> 
> 
> 
> >
> 
> > Or maybe this is reminiscent of the fraternity hazing rituals
> 
> > of days gone by:
> 
> >
> 
> >  *POP*
> 
> >  "Thank you Sir, may i have another?"
> 
> >
> 
> > > If you are a beginning python programmer, really the best
> 
> > > answer is: Just dont do it!  Dont do what? Dont use
> 
> > > mutable arguments as function defaults. Once you cross the
> 
> > > noob stage you can check that its a standard gotcha: Just
> 
> > > run a search for 'python gotcha default []'
> 
> >
> 
> > > And when you feel that you need to, use Steven's trick:
> 
> > > use a immutable indicator 'None' for the mutable []. Once
> 
> > > you cross the noob stage you can check that its a standard
> 
> > > gotcha: Just run a search for 'python gotcha default []'
> 
> > > Its even been discussed repeatedly on the python-ideas
> 
> > > list
> 
> >
> 
> > Your attempting to excuse an inexcusable language flaw by
> 
> > pointing out that the effects of the flaw can be avoided by
> 
> > using a workaround. And, to add insult to injury, you
> 
> > provide no good reason for the flaw to exist:
> 
> >
> 
> >  "Just do x, y, and z and shut up. Yes we made a mistake
> 
> >  but we are not about to admit our mistake and the onerous
> 
> >  will be on all the noobs to re-invent the workaround each
> 
> >  time"
> 
> >
> 
> > To me that is unacceptable.
> 
> >
> 
> > > Heres a correction suggestion: [...] Here's Terry Reedy's
> 
> > > nicely explaining the 'why-of-the-how' : [...] FWIW here
> 
> > > is a conceptual/philosophical explanation of your
> 
> > > confusion: There are 2 fundamental ways for approaching
> 
> > > the programming task -- functional and imperative.
> 
> >
> 
> > All these "explanations" ignore a fundamental fact about
> 
> > subroutines[1].
> 
> 
> 
> >
> 
> > A call to a subroutine should exists as a unique transaction
> 
> > within the entire program. It is expected to optionally take
> 
> > inputs, and optionally return an output (depending on the
> 
> > definition).
> 
> >
> 
> > When the subroutine is completed, all inputs and local
> 
> > variables are expected to be destroyed. If the programmer
> 
> > wants a return value, he need simply ask. Data persistence
> 
> > is not a function of subroutines! Finally, a subroutine
> 
> > should never have side effects UNLESS the programmer
> 
> > explicitly ask for a side effect.
> 
> >
> 
> > However, the Python flaw of allowing mutable sequence
> 
> > arguments to persist between successive calls of a
> 
> > subroutine is breaking the entire definition of a
> 
> > subroutine, and for what noble purpose i ask? What purpose
> 
> > is SO important that you change a well established interface
> 
> > in a totally unintuitive manner?
> 
> >
> 
> > If your answer is that recursion is easier, then i say that
> 
> > is foolish because a programmer can keep a reference
> 
> > to a mutable sequence OUTSIDE the subroutine and you can
> 
> > save the "gotchas" for Guido's next birthday party.
> 
> >
> 
> > [1]:http://en.wikipedia.org/wiki/Subroutine
> 
> 
> 
> 
> 
> You are saying in different language what I said: Functional
> 
> programming is a good idea, imperative programming is a bad idea.
> 
> From the invention of subroutines (ie 50 years) PL designers are
> 
> hearing this truth but somehow or other fail to listen; for more
> 
> details see http://blog.languager.org/2012/11/imperative-programming-lessons-not.html

Well, that was the story of the expensive memory era.the 
In 198X -2000 the auto GC of LISP was beaten 
by practical engineers using C, C++, PASCAL, and object pascal.

But now it is different in 201X.

[toc] | [prev] | [next] | [standalone]


Page 4 of 5 — ← Prev page 1 2 3 [4] 5  Next page →

Back to top | Article view | comp.lang.python


csiph-web