Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #48742 > unrolled thread
| Started by | Ahmed Abdulshafy <abdulshafy@gmail.com> |
|---|---|
| First post | 2013-06-19 12:17 -0700 |
| Last post | 2013-06-20 01:17 +0000 |
| Articles | 20 on this page of 86 — 21 participants |
Back to article view | Back to comp.lang.python
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 →
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Rotwang <sg552@hotmail.co.uk> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Rotwang <sg552@hotmail.co.uk> |
|---|---|
| Date | 2013-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]
| From | Rotwang <sg552@hotmail.co.uk> |
|---|---|
| Date | 2013-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]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Rotwang <sg552@hotmail.co.uk> |
|---|---|
| Date | 2013-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]
| From | rusi <rustompmody@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | rusi <rustompmody@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2013-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]
| From | rusi <rustompmody@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-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]
| From | Tim Chase <python.list@tim.thechases.com> |
|---|---|
| Date | 2013-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]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-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]
| From | Tim Chase <python.list@tim.thechases.com> |
|---|---|
| Date | 2013-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]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2013-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]
| From | alex23 <wuwei23@gmail.com> |
|---|---|
| Date | 2013-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]
| From | 88888 Dihedral <dihedral88888@gmail.com> |
|---|---|
| Date | 2013-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