Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-27 Thread Marko Rauhamaa
BartC :

> I think [functions] are more first class in Lisp than they are in most
> other languages including Python.

Functions in Python and Lisp have the same status.

I would say that Python is one of the many modern Lisp derivatives. What
Python still lacks is:

 * A way to augment the language syntax on the fly. (How could I add an
   "until" statement to Python in my Python application?)

 * A unified syntax for code and data. (Why use braces for dictionaries
   instead of indentation?)


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-27 Thread BartC

On 27/11/2015 01:09, Steven D'Aprano wrote:

On Thu, 26 Nov 2015 12:23 pm, BartC wrote:


[First-class functions]

The names are declared, but the names are rarely bound to anything else.
Functions are just called the same boring way they are in C.

/They might as well be static definitions/.


Sure. And that's probably true for, oh, I don't know, I'll be generous, and
say that 95% of Python functions in use are of a straight-forward
pseudo-static form, using no dynamic features.

But it's the other 5% -- one in twenty -- that *shine*. They're the ones
that do things that you can't do in Pascal or C except with the greatest of
difficulty.


OK, you're worried about that 5%, I'm more concerned about the other 95%.

I'm not saying you shouldn't have dynamic functions at all, just that 
it's not necessary for 100% to be dynamic.


I understand now that they are dynamic because that is the only 
mechanism that Python has to create any function definition, even the 
boring, static ones.


Together with the ability to subsequently re-bind the function name to 
something else, that's a bit unfortunate because it makes it harder to 
identifier calls to those functions in order to streamline them, or even 
for someone to look at a bit of code and be sure whether that fn(a,b,c) 
is calling the function defined as 'fn' a few hundred lines earlier or 
something else entirely.


(MRAB mentioned Postscript, which also introduces functions using 
executable statements.


However, Postscript was designed to execute code on-the-fly being 
received a character at a time over a printer cable. It had a good excuse!)



Because Pascal doesn't have first-class functions, you couldn't pass a
function as an argument to another function. So the ODE solvers used a
hard-coded function as the equation to be solved. So if you wanted to solve
a particular equation, you had to *edit the source code of the program*,
modifying that hard-coded function to match your equation, then re-compile,
and then run the code. You couldn't just type in the equation you wanted to
solve and run the code.


Wouldn't Python have the same problem? If the equation to be solved, or 
even the actual function to be executed, is input by the user, then 
doesn't that require whichever one of exec() or eval() it is that 
processes the source code?



There's a lot to like about Pascal,


It was designed for teaching. The original language would have needed 
tweaking for use in general purpose programming.



but gosh it sure is lacking in power. C
at least has function pointers, which is a step up from Pascal, but still
pretty weak and feeble. If functions are first class values in Python,
Ruby, Lisp and others, they're second class values in C and third class in
Pascal.


I think they are more first class in Lisp than they are in most other 
languages including Python. That doesn't stop Python still being jolly 
useful though...


--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Marko Rauhamaa
Gregory Ewing :

> Marko Rauhamaa wrote:
>> What I'm saying is that Python does not prevent mutable keys but
>> tries to do that with lists and tuples.
>>
>> I think Python should stop trying.
>
> Do you volunteer to answer all the posts from beginners complaining
> that "the dict type is broken" because they used a list as a key and
> then mutated it?

What happened to consenting adults?

Even Java (of all languages) allows lists to be keys and simply notes:

   Note: great care must be exercised if mutable objects are used as map
   keys.

   http://docs.oracle.com/javase/7/docs/api/java/util/Map.html>


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Gregory Ewing

Marko Rauhamaa wrote:

What I'm saying is that Python does not prevent mutable keys but tries
to do that with lists and tuples.

I think Python should stop trying.


Do you volunteer to answer all the posts from beginners
complaining that "the dict type is broken" because they
used a list as a key and then mutated it?

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Gregory Ewing

BartC wrote:
I simply stated that Python's approach was novel. Steven D'Aprano then 
responded by belittling my view, and effectively trashing every language 
I've ever used.


He pointed out that many other dynamic languages construct
functions on the fly the same way that Python does, going
all the way back to the earliest Lisp implementations. If
you think that Python invented that idea, then either you
haven't studied any of those languages, or you didn't
realise that's what they were doing. If your view was
"belittled" in any way, it's only because you said something
that is objectively wrong.

But as it happens I do think features like first class functions are 
overrated (and probably the software underpinning the hardware we're all 
using is written in the very languages he despises). I don't think a 
language is worthless without such a feature.


I think Steven went off on a bit of a tangent there.
First-classness of functions doesn't really have anything
to do with whether they're constructed statically or
dynamically. C lets you pass pointers to functions around,
for example, but I don't think anyone would describe C
as executing function definitions at run time.

While a language isn't worthless without first-class
functions, such a language tends to feel rather limited
if you're used to having them. Think of any API that
involves passing in callback functions, and what you
would have to do if you didn't have that ability.

Anyhow, the whole issue of static vs. dynamic function
creation is itself tangential to what started all this.
I think Laura Creighton has it right: Python provides
exactly *one* way to delay evaluation of code: put it
in the body of a function. That's a very simple rule,
and I think maintaining that simplicity is a good
thing.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread BartC

On 26/11/2015 13:15, Chris Angelico wrote:

On Thu, Nov 26, 2015 at 11:53 PM, BartC  wrote:



http://pastebin.com/JrVTher6



#14 and #15: Are you assuming that a character is a byte and that
diacritical-free English is the only language in the world?


I don't think that need be the assumption. Any UTF8 string that fits 
within 8 bytes could also be represented by an integer value.



Case
insensitivity is a *pain* when you try to be language-agnostic; for
instance, the case-folding rules of English state that U+0069 LATIN
SMALL LETTER I and U+0049 LATIN CAPITAL LETTER I are identical, but
Turkish would upper-case the first to U+0130 LATIN CAPITAL LETTER I
WITH DOT ABOVE and lower-case the second to U+0131 LATIN SMALL LETTER
DOTLESS I. German has U+00DF LATIN SMALL LETTER SHARP S (also called
eszett), which traditionally upper-cases to "SS", which lower-cases to
"ss".


I use Windows which is also case insensitive with regard to filenames 
and such. How does it solve those problems? How about web-site names, 
email addresses and Google searches?


Within a program source code (where you have mainly technical users), 
you can just impose some restrictions on keywords and identifiers 
otherwise there are plenty of problems even without case switching, if 
you want to allow Unicode here.



--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Chris Angelico
On Fri, Nov 27, 2015 at 9:27 AM, BartC  wrote:
> On 26/11/2015 13:15, Chris Angelico wrote:
>>
>> On Thu, Nov 26, 2015 at 11:53 PM, BartC  wrote:
>
>
>>> http://pastebin.com/JrVTher6
>
>
>> #14 and #15: Are you assuming that a character is a byte and that
>> diacritical-free English is the only language in the world?
>
>
> I don't think that need be the assumption. Any UTF8 string that fits within
> 8 bytes could also be represented by an integer value.

Okay, so you're making UTF-8 your visible string representation.
That's better than assuming character==byte, but it still has the case
insensitivity problem.

>> Case
>> insensitivity is a *pain* when you try to be language-agnostic; for
>> instance, the case-folding rules of English state that U+0069 LATIN
>> SMALL LETTER I and U+0049 LATIN CAPITAL LETTER I are identical, but
>> Turkish would upper-case the first to U+0130 LATIN CAPITAL LETTER I
>> WITH DOT ABOVE and lower-case the second to U+0131 LATIN SMALL LETTER
>> DOTLESS I. German has U+00DF LATIN SMALL LETTER SHARP S (also called
>> eszett), which traditionally upper-cases to "SS", which lower-cases to
>> "ss".
>
>
> I use Windows which is also case insensitive with regard to filenames and
> such. How does it solve those problems? How about web-site names, email
> addresses and Google searches?

Windows: I'm not sure, and frankly, I don't trust it. A quick test
showed a couple of failures:

C:\Users\Rosuav\Desktop>dir /b TE*
teßting
C:\Users\Rosuav\Desktop>dir /b TESST*
File Not Found

C:\Users\Rosuav\Desktop>dir /b ParıldıYOR*
Parıldıyor Parts & Pieces
C:\Users\Rosuav\Desktop>dir /b PARILDIYOR*
File Not Found

It might be case insensitive only for ASCII.

(Note: This test was done on Windows 7, because that's the VM I had
handy. Things might be different on newer Windowses, but I can't
check.

Web site names: Presumably you mean DNS. It started out as an
ASCII-only protocol, and grew a number of gross hacks to support
"internationalized domain names". I'm not sure where the case
insensitivity is applied; but it doesn't matter too much, because
conflicts can be resolved at registration. Also, you'll generally see
IDNs in country-specific TLDs, so there'll be only one language (or a
small family of languages) used, reducing the likelihood of
collisions.

Google searches are (deliberately) a LOT more sloppy than just case
sensitivity. You can search for something without diacriticals and get
back results with diacriticals; you can transpose letters, omit
letters, have extra letters, and it'll generally figure out what you
want. This is absolutely awesome for a search engine, but equally
horrifying for name lookups in a program.

None of these is something I'd recommend following.

> Within a program source code (where you have mainly technical users), you
> can just impose some restrictions on keywords and identifiers otherwise
> there are plenty of problems even without case switching, if you want to
> allow Unicode here.

I would strongly support ASCII-only *language keywords*. You don't
have many of them (compared to the number of identifiers in a
program), and everyone has to type them. But for identifiers, Python 3
defines character validity based on Unicode categories, and performs
NFKC normalization on all names. That's pretty straight-forward. No
case sensitivity hassles, no messy non-transitive equalities, it's
easy.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Steven D'Aprano
On Thu, 26 Nov 2015 07:27 pm, Marko Rauhamaa wrote:

> What I'm saying is that Python does not prevent mutable keys but tries
> to do that with lists and tuples.
> 
> I think Python should stop trying.
> 
> I have wanted to use lists as keys, and there should be no reason to
> allow mutable tuples. It should be enough to say that the behavior of a
> dictionary is undefined if a key should mutate on the fly.

Well, when you design your own language, you can make all the bad design
decisions you like :-)

Seriously, if you think *this* thread about mutable function defaults has
been long, can you imagine the bug reports and arguments if this was
possible in Python?


L = [1, 2]
d = {L: "found it"}

# much later, after L has been modified...

d[ [1, 2] ]
=> raises KeyError



But even worse:


a = [1, 2]
b = [1, 3]
d = {a: "spam", b: "ham"}
a[1] += 1

What will d[ [1, 3] ] return?


-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Steven D'Aprano
On Thu, 26 Nov 2015 12:23 pm, BartC wrote:

> On 26/11/2015 00:31, Steven D'Aprano wrote:

>> In 2015, it's hard to think of any non-obsolete, non-toy language which
>> doesn't treat functions as first-class values, including creating them on
>> the fly. Fortran and C perhaps.
> 
> It's funny then that the vast majority of top-level function definitions
> I see in Python (and import and class statements too) are decidedly
> static.

I can't be held responsible for what code you see.

It is probably true that many, maybe even a majority, of top-level
functions, and methods, are static. So what? That's not the point. The
point is that *more than that is possible*, so when you need the power, you
have it.

Any time you see a function decorator:

@decorate
def function(arg): ...


you're probably seeing a dynamically-generated function. The typical
decorator idiom looks like this:

def decorate(function):
@functools.wraps(function)
def inner(arg):
do stuff
call the original function
return the result
return inner


Lo and behold, the simple @decorate idiom usually hides a function created
on the fly. (That would be the inner function, which is called a closure.)

Any time you see a function factory, chances are good that it involves
dynamic generation of function objects.

Any time you see lambda, you are definitely seeing the dynamic generation of
function objects. If you do any sort of programming involving callbacks
(for example, some GUI toolkits, like Tkinter, make extensive use of
callbacks) you probably will use lambda a lot.

The equivalent to lambda, code blocks, is even more powerful in Ruby, and
Ruby programmers use code blocks *a lot*. So much so that I know at least
one Ruby programmer who considers Python almost unusably primitive and
crippled because it lacks code blocks.

You really should read Paul Graham's essay, "Beating the Averages", and
understand the Blub Paradox. (It's not really a paradox.) It might open
your eyes.

[quote]
As long as our hypothetical Blub programmer is looking down the power
continuum, he knows he's looking down. Languages less powerful than Blub
are obviously less powerful, because they're missing some feature he's used
to. But when our hypothetical Blub programmer looks in the other direction,
up the power continuum, he doesn't realize he's looking up. What he sees
are merely weird languages. He probably considers them about equivalent in
power to Blub, but with all this other hairy stuff thrown in as well. Blub
is good enough for him, because he thinks in Blub.
[end quote]

http://www.paulgraham.com/avg.html


We're all Blub programmers. But some of us are aware that we're Blub
programmers, and when we see "weird languages" with "hairy stuff", we don't
immediately dismiss the possibility that maybe that stuff is powerful and
useful, just because we've never found a use for it.



> The names are declared, but the names are rarely bound to anything else.
> Functions are just called the same boring way they are in C.
> 
> /They might as well be static definitions/.

Sure. And that's probably true for, oh, I don't know, I'll be generous, and
say that 95% of Python functions in use are of a straight-forward
pseudo-static form, using no dynamic features.

But it's the other 5% -- one in twenty -- that *shine*. They're the ones
that do things that you can't do in Pascal or C except with the greatest of
difficulty.

Back when I was an undergrad at uni, I did a course on computational
mathematics. At the time, Pascal was the language of choice at my uni, and
when it came to solving ODEs (Ordinary Differential Equations) we used a
package of Pascal programs to do so.

Because Pascal doesn't have first-class functions, you couldn't pass a
function as an argument to another function. So the ODE solvers used a
hard-coded function as the equation to be solved. So if you wanted to solve
a particular equation, you had to *edit the source code of the program*,
modifying that hard-coded function to match your equation, then re-compile,
and then run the code. You couldn't just type in the equation you wanted to
solve and run the code.

Of course Pascal is Turing Complete, and the solver could have been written
to work that way. It just would have been much, much, much harder.
Something that in a language like Python you can do almost without
thinking:

function(another_function, x, y, z)

would have required hundreds, perhaps thousands or tens of thousands of
lines to do in standard Pascal. You would have had to build up all this
infrastructure for dealing with functions that Python gives you for free.

There's a lot to like about Pascal, but gosh it sure is lacking in power. C
at least has function pointers, which is a step up from Pascal, but still
pretty weak and feeble. If functions are first class values in Python,
Ruby, Lisp and others, they're second class values in C and third class in
Pascal.




-- 
Steven

-- 

Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Chris Angelico
On Fri, Nov 27, 2015 at 11:15 AM, Random832  wrote:
> Chris Angelico  writes:
>> Windows: I'm not sure, and frankly, I don't trust it. A quick test
>> showed a couple of failures:
>>
>> It might be case insensitive only for ASCII.
>
> Windows uses a simple WCHAR->WCHAR (lower->upper) mapping for case
> comparison. it doesn't handle those cases, but it does handle all BMP
> characters that have a simple case equivalent within the BMP as of the
> unicode version that Microsoft supported when the disk was formatted.
>
> It's unfair to pick the two worst examples that you know offhand and
> declare that this means "only for ASCII". Pick any latin-1 (etc)
> diacritic, any letter of the greek and cyrillic alphabet, and it'll
> handle them just fine.
>

I picked a couple of test cases, found them to not do the case
insensitivity special cases, and concluded that I don't understand
Windows' file system case folding (with the possibility that it's an
ASCII-only case fold).

Anyway, it's still not something I would recommend; if you want true
case folding, you need to go the whole way - and it still has
problems.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread MRAB

On 2015-11-27 00:15, Random832 wrote:

Chris Angelico  writes:

Windows: I'm not sure, and frankly, I don't trust it. A quick test
showed a couple of failures:

It might be case insensitive only for ASCII.


Windows uses a simple WCHAR->WCHAR (lower->upper) mapping for case
comparison. it doesn't handle those cases, but it does handle all BMP
characters that have a simple case equivalent within the BMP as of the
unicode version that Microsoft supported when the disk was formatted.


Interesting, on Windows 10, "dir" on the command line treats
"TEßTING.txt" and "teßting.txt" as equivalent, whereas a file dialog
treats "TEßTING.txt", "teßting.txt" and "TESSTING.txt" as equivalent.

They don't treat "ParıldıYOR.txt" and "PARILDIYOR.txt" as equivalent,
which doesn't surprise me.


It's unfair to pick the two worst examples that you know offhand and
declare that this means "only for ASCII". Pick any latin-1 (etc)
diacritic, any letter of the greek and cyrillic alphabet, and it'll
handle them just fine.

OSX fails the same cases, incidentally.



--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Steven D'Aprano
On Thu, 26 Nov 2015 12:52 pm, Ned Batchelder wrote:

> For someone who claims to be interested in language design, you're
> remarkably dismissive of pretty much the entire industry.  I don't think
> it's worth the effort to try to change your mind.

In fairness to BartC, I don't think that's malicious or trolling. I think it
is as pure an example of what Paul Graham calls the Blub Paradox as I've
ever seen.



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Random832
Chris Angelico  writes:
> Windows: I'm not sure, and frankly, I don't trust it. A quick test
> showed a couple of failures:
> 
> It might be case insensitive only for ASCII.

Windows uses a simple WCHAR->WCHAR (lower->upper) mapping for case
comparison. it doesn't handle those cases, but it does handle all BMP
characters that have a simple case equivalent within the BMP as of the
unicode version that Microsoft supported when the disk was formatted.

It's unfair to pick the two worst examples that you know offhand and
declare that this means "only for ASCII". Pick any latin-1 (etc)
diacritic, any letter of the greek and cyrillic alphabet, and it'll
handle them just fine.

OSX fails the same cases, incidentally.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Steven D'Aprano
On Thu, 26 Nov 2015 10:23 pm, Marko Rauhamaa wrote:

> Chris Angelico :
> 
>> On Thu, Nov 26, 2015 at 9:54 PM, Marko Rauhamaa  wrote:
>>>
>>>>>> hash([])
>>>Traceback (most recent call last):
>>>  File "", line 1, in 
>>>TypeError: unhashable type: 'list'
>>>
>>> Annoying.
>>
>> Yes, it's really annoying that you get an immediate exception instead
>> of unpredictably getting bizarre failures that depend on the exact
>> bucket sizes and dict size and so on. It's such a pain to get told
>> exactly where the problem is.
> 
> The problem is that lists don't have __hash__ and __eq__ defined.


I'm pretty sure that lists have __eq__ defined :-P



>> Python tends to assume that programmers are intelligent people who are
>> prepared to fix their mistakes.
> 
> It's not letting me in the case of list.


Less whining, more programming:

class MyList(list):
def __hash__(self):
return 1


There you go, problem solved. New problems are your responsibility:


py> a = MyList([1, 2])
py> d = {a: "spam"}
py> d[MyList([1, 2])]  # Looks good so far.
'spam'
py> a.append(3)
py> d[MyList([1, 2])]  # Where did my key go?
Traceback (most recent call last):
  File "", line 1, in 
KeyError: [1, 2]


py> b = MyList([1, 3])
py> d[b] = "eggs"
py> d[MyList([1, 3])]  # So far so good.
'eggs'
py> b[1] -= 1
py> b.append(3)
py> d[b]  # What?
'spam'


All I can say is, this would be an absolutely awesome feature for Python to
have, if you were being paid by the hour for debugging.



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread BartC

On 27/11/2015 01:46, Steven D'Aprano wrote:

On Thu, 26 Nov 2015 12:52 pm, Ned Batchelder wrote:


For someone who claims to be interested in language design, you're
remarkably dismissive of pretty much the entire industry.  I don't think
it's worth the effort to try to change your mind.


In fairness to BartC, I don't think that's malicious or trolling. I think it
is as pure an example of what Paul Graham calls the Blub Paradox as I've
ever seen.


"Well, PaulGraham has a very (very) low opinion of OO, mostly because he 
does a lot of stuff that most people haven't been able to do, and he 
says he almost never "resorts" to it. However, more recent posts on LL1 
suggest PaulGraham is coming around. He's starting to be less derogatory 
to OO (and seems to have done a 180 on continuations). No one, not even 
PaulGraham himself, ever said that PaulGraham was immune to the 
BlubParadox. ;) "


http://c2.com/cgi/wiki?BlubParadox

--
bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Chris Angelico
On Thu, Nov 26, 2015 at 5:52 PM, Marko Rauhamaa  wrote:
> Steven D'Aprano :
>
>> Making tuples mutable would break their use as dictionary keys, which is a
>> *critical* use.
>
> No, it wouldn't. Any object that provides __hash__() and __eq__() can be
> used as a key.
>
> Nothing prevents using mutable objects as keys in Python.
>
>

Sure, you _can_. But if the key's hash changes between dict insertion
and retrieval, all manner of invariants will break, and likewise if
two equal objects have different hashes. From which you can deduce
logically that any object used as a key must remain (not) equal to
everything that it was (not) equal to from that time until it is
looked up... which basically means its value mustn't change. It must
be immutable.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Marko Rauhamaa
Chris Angelico :

> On Thu, Nov 26, 2015 at 5:52 PM, Marko Rauhamaa  wrote:
>> Nothing prevents using mutable objects as keys in Python.
>
> Sure, you _can_. But if the key's hash changes between dict insertion
> and retrieval, all manner of invariants will break, and likewise if
> two equal objects have different hashes. From which you can deduce
> logically that any object used as a key must remain (not) equal to
> everything that it was (not) equal to from that time until it is
> looked up... which basically means its value mustn't change. It must
> be immutable.

What I'm saying is that Python does not prevent mutable keys but tries
to do that with lists and tuples.

I think Python should stop trying.

I have wanted to use lists as keys, and there should be no reason to
allow mutable tuples. It should be enough to say that the behavior of a
dictionary is undefined if a key should mutate on the fly.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Antoon Pardon
Op 26-11-15 om 02:52 schreef Ned Batchelder:
> I almost started to explain about how yes, Python is often written in
> conservative static ways. I was going to mention that a little dynamic
> nature goes a long way, and is never far from the surface in even the
> simplest Python programs.
>
> But I won't, because I'm not sure you're really interested.  There's a
> pattern here of people trying to explain Python to you, and eventually,
> after many words, getting to some kind of shared understanding, only
> for you to shrug it all off as a fad, or pocket-lining, or needless
> complexity.
>
> For someone who claims to be interested in language design, you're
> remarkably dismissive of pretty much the entire industry.  I don't think
> it's worth the effort to try to change your mind.

I agree. I still think the regulars tend to react in a too defensive way
when someone rather new dares to find fault with some python aspects. But
if someone comes here and can't get over their bizarre first impression of 
some python aspects then there is not much reason to continue the discussion
with them either.

-- 
Antoon.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Chris Angelico
On Thu, Nov 26, 2015 at 7:27 PM, Marko Rauhamaa  wrote:
> Chris Angelico :
>
>> On Thu, Nov 26, 2015 at 5:52 PM, Marko Rauhamaa  wrote:
>>> Nothing prevents using mutable objects as keys in Python.
>>
>> Sure, you _can_. But if the key's hash changes between dict insertion
>> and retrieval, all manner of invariants will break, and likewise if
>> two equal objects have different hashes. From which you can deduce
>> logically that any object used as a key must remain (not) equal to
>> everything that it was (not) equal to from that time until it is
>> looked up... which basically means its value mustn't change. It must
>> be immutable.
>
> What I'm saying is that Python does not prevent mutable keys but tries
> to do that with lists and tuples.
>
> I think Python should stop trying.
>
> I have wanted to use lists as keys, and there should be no reason to
> allow mutable tuples. It should be enough to say that the behavior of a
> dictionary is undefined if a key should mutate on the fly.

Python defines dict-key-validity as being synonymous with hashability.
It's up to the class author to make sure the object's hash is useful.

Behaviour being undefined works just fine [1] in C. It's not so
popular in Python. I don't think we want to have myriad new and
experienced programmers trying to figure out why square brackets in
dict keys are usually fine but occasionally not.

ChrisA

[1] For some definition of "fine", anyway.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Antoon Pardon
Op 26-11-15 om 09:27 schreef Marko Rauhamaa:
> Chris Angelico :
>
>> On Thu, Nov 26, 2015 at 5:52 PM, Marko Rauhamaa  wrote:
>>> Nothing prevents using mutable objects as keys in Python.
>> Sure, you _can_. But if the key's hash changes between dict insertion
>> and retrieval, all manner of invariants will break, and likewise if
>> two equal objects have different hashes. From which you can deduce
>> logically that any object used as a key must remain (not) equal to
>> everything that it was (not) equal to from that time until it is
>> looked up... which basically means its value mustn't change. It must
>> be immutable.
> What I'm saying is that Python does not prevent mutable keys but tries
> to do that with lists and tuples.
>
> I think Python should stop trying.
>
> I have wanted to use lists as keys, and there should be no reason to
> allow mutable tuples. It should be enough to say that the behavior of a
> dictionary is undefined if a key should mutate on the fly.

Maybe python could introduce a dictionary that copies the keys in and
out the dictionary. In that case keys can be mutable without that being
a problem for the dictionary, because the dictionary works with it's own
copy of the key that it doesn't mutate.

-- 
Antoon.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Marko Rauhamaa
Chris Angelico :

> On Thu, Nov 26, 2015 at 7:27 PM, Marko Rauhamaa  wrote:
>> I have wanted to use lists as keys, and there should be no reason to
>> allow mutable tuples. It should be enough to say that the behavior of
>> a dictionary is undefined if a key should mutate on the fly.
>
> Python defines dict-key-validity as being synonymous with hashability.
> It's up to the class author to make sure the object's hash is useful.

   >>> hash([])
   Traceback (most recent call last):
 File "", line 1, in 
   TypeError: unhashable type: 'list'

Annoying.

> Behaviour being undefined works just fine [1] in C. It's not so
> popular in Python. I don't think we want to have myriad new and
> experienced programmers trying to figure out why square brackets in
> dict keys are usually fine but occasionally not.

But there's no way to enforce that with any of the myriad new classes.

   Ye blind guides, which strain at a gnat, and swallow a camel.

But I say unto you, Swallow the gnat as well.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Chris Angelico
On Thu, Nov 26, 2015 at 9:54 PM, Marko Rauhamaa  wrote:
> Chris Angelico :
>
>> On Thu, Nov 26, 2015 at 7:27 PM, Marko Rauhamaa  wrote:
>>> I have wanted to use lists as keys, and there should be no reason to
>>> allow mutable tuples. It should be enough to say that the behavior of
>>> a dictionary is undefined if a key should mutate on the fly.
>>
>> Python defines dict-key-validity as being synonymous with hashability.
>> It's up to the class author to make sure the object's hash is useful.
>
>>>> hash([])
>Traceback (most recent call last):
>  File "", line 1, in 
>TypeError: unhashable type: 'list'
>
> Annoying.

Yes, it's really annoying that you get an immediate exception instead
of unpredictably getting bizarre failures that depend on the exact
bucket sizes and dict size and so on. It's such a pain to get told
exactly where the problem is.

>> Behaviour being undefined works just fine [1] in C. It's not so
>> popular in Python. I don't think we want to have myriad new and
>> experienced programmers trying to figure out why square brackets in
>> dict keys are usually fine but occasionally not.
>
> But there's no way to enforce that with any of the myriad new classes.

Python tends to assume that programmers are intelligent people who are
prepared to fix their mistakes. As a general rule, if you define
__eq__, you should probably define __hash__ as well, and then you need
to know what you're doing; specifically, the invariant that if a==b,
hash(a)==hash(b). Python doesn't enforce that because it's impossible
to enforce.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: What does a list comprehension do (was: Late-binding of function defaults (was Re: What is a function parameter =[] for?))

2015-11-26 Thread Nobody
On Wed, 25 Nov 2015 14:51:23 +0100, Antoon Pardon wrote:

> Am I missing something?

The issue is with lambdas rather than with list comprehensions per se.

Python's lambdas capture free variables by reference, not value.

> x = 3
> f = lambda y: x + y
> f(0)
3
> x = 7
> f(0)
7

The same issue applies to nested functions:

> def foo():
=x = 3
=def f(y):
=   return x + y
=print f(0)
=x = 7
=print f(0)
= 
> foo()
3
7

And also to non-nested functions (but most people expect that):

> x = 3
> def f(y,x=x):
=   return x + y
=
> print f(0)
3
> x=7
> print f(0)
3

If you want to capture a variable by value, add a parameter with a default
value using that variable:

> def foo():
=x = 3
=def f(y, x=x):
=   return x + y
=print f(0)
=x = 7
=print f(0)
= 
> foo()
3
3

This also works for lambdas:

> x = 3
> f = lambda y,x=x: x + y
> f(0)
3
> x = 7
> f(0)
3

Returning to the original expression:

> q = [lambda x: i * x for i in range(4)]
> q[0](1), q[3](1)
(3, 3)
> q = [lambda x,i=i: i * x for i in range(4)]
> q[0](1), q[3](1)
(0, 3)


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Mark Lawrence

On 26/11/2015 06:52, Marko Rauhamaa wrote:

Steven D'Aprano :


Making tuples mutable would break their use as dictionary keys, which is a
*critical* use.


No, it wouldn't. Any object that provides __hash__() and __eq__() can be
used as a key.



Almost, see https://wiki.python.org/moin/DictionaryKeys.  Under the 
title "Types Usable as Dictionary Keys" it states "The discussion above 
should explain why Python requires that:


To be used as a dictionary key, an object must support the hash function 
(e.g. through __hash__), equality comparison (e.g. through __eq__ or 
__cmp__), and must satisfy the correctness condition above."


The correctness condition is:-

"For such a lookup algorithm to work correctly, the hash functions 
provided must guarantee that if two keys produce different hash values 
then the two key objects are not equivalent, that is,


for all i1, i2, if hash(i1) != hash(i2), then i1 != i2"

Aren't search engines just wonderful :)

--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Marko Rauhamaa
Chris Angelico :

> On Thu, Nov 26, 2015 at 9:54 PM, Marko Rauhamaa  wrote:
>>
>>>>> hash([])
>>Traceback (most recent call last):
>>  File "", line 1, in 
>>TypeError: unhashable type: 'list'
>>
>> Annoying.
>
> Yes, it's really annoying that you get an immediate exception instead
> of unpredictably getting bizarre failures that depend on the exact
> bucket sizes and dict size and so on. It's such a pain to get told
> exactly where the problem is.

The problem is that lists don't have __hash__ and __eq__ defined.

> Python tends to assume that programmers are intelligent people who are
> prepared to fix their mistakes.

It's not letting me in the case of list.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Chris Angelico
On Thu, Nov 26, 2015 at 10:23 PM, Marko Rauhamaa  wrote:
> Chris Angelico :
>
>> On Thu, Nov 26, 2015 at 9:54 PM, Marko Rauhamaa  wrote:
>>>
>>>>>> hash([])
>>>Traceback (most recent call last):
>>>  File "", line 1, in 
>>>TypeError: unhashable type: 'list'
>>>
>>> Annoying.
>>
>> Yes, it's really annoying that you get an immediate exception instead
>> of unpredictably getting bizarre failures that depend on the exact
>> bucket sizes and dict size and so on. It's such a pain to get told
>> exactly where the problem is.
>
> The problem is that lists don't have __hash__ and __eq__ defined.

They do define equality. And it depends on their contents, ergo there
cannot be a stable hash. This is NOT a problem. This is the concept of
unhashability behaving EXACTLY CORRECTLY. Sorry to shout, but this is
another case of refusing to accept what has been explained as having
good reason, and I'm getting a little tired of it.

>> Python tends to assume that programmers are intelligent people who are
>> prepared to fix their mistakes.
>
> It's not letting me in the case of list.

Actually it is. Your mistake is trying to use a list as a dict key.
You have a solution available: use a tuple.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Marko Rauhamaa
Chris Angelico :

> On Thu, Nov 26, 2015 at 10:23 PM, Marko Rauhamaa  wrote:
>> It's not letting me in the case of list.
>
> Actually it is. Your mistake is trying to use a list as a dict key.
> You have a solution available: use a tuple.

Yes, or wrap the list in a class.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread BartC

On 26/11/2015 01:52, Ned Batchelder wrote:

On Wednesday, November 25, 2015 at 8:23:36 PM UTC-5, BartC wrote:

On 26/11/2015 00:31, Steven D'Aprano wrote:



It really, truly isn't. Your viewpoint is clouded by too much immersion in
crippled languages. *Old and obsolete versions* of crippled languages.
Dynamic creation of functions goes back to the 1950s.



It's funny then that the vast majority of top-level function definitions
I see in Python (and import and class statements too) are decidedly static.



I almost started to explain about how yes, Python is often written in
conservative static ways. I was going to mention that a little dynamic
nature goes a long way, and is never far from the surface in even the
simplest Python programs.

But I won't, because I'm not sure you're really interested.  There's a
pattern here of people trying to explain Python to you, and eventually,
after many words, getting to some kind of shared understanding, only
for you to shrug it all off as a fad, or pocket-lining, or needless
complexity.


I'm sorry if I've been misunderstood.

I simply stated that Python's approach was novel. Steven D'Aprano then 
responded by belittling my view, and effectively trashing every language 
I've ever used.


But as it happens I do think features like first class functions are 
overrated (and probably the software underpinning the hardware we're all 
using is written in the very languages he despises). I don't think a 
language is worthless without such a feature.


> For someone who claims to be interested in language design, you're
> remarkably dismissive of pretty much the entire industry.  I don't think
> it's worth the effort to try to change your mind.

I did say somewhere in this thread or the other one, that I liked 
Python's model well enough that I tried to emulate it in my own 
language. That's not being dismissive! (It don't work because the 
languages are too different internally; I'll have to save it for a 
separate, higher-level language.)


Also, as an implementer, you can understand that I might view certain 
features differently from other people. Dynamic features do make it 
harder to implement things efficiently, and you have to decide whether 
it's worthwhile for the 1% of the time they might be used.


--

FWIW here is that list of features that are different between Python and 
my language, or that work a different way, or that I think could be a 
useful addition. (Although Python's internal workings make many 
impractical.)


http://pastebin.com/JrVTher6

This is not an attempt to compare the complete languages as they are for 
different purposes (mine is more low-level, simpler, smaller and 
designed to make it easier to create an efficient byte-code interpreter 
for it).


--
Bartc


--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread Chris Angelico
On Thu, Nov 26, 2015 at 11:53 PM, BartC  wrote:
> FWIW here is that list of features that are different between Python and my
> language, or that work a different way, or that I think could be a useful
> addition. (Although Python's internal workings make many impractical.)
>
> http://pastebin.com/JrVTher6
>
> This is not an attempt to compare the complete languages as they are for
> different purposes (mine is more low-level, simpler, smaller and designed to
> make it easier to create an efficient byte-code interpreter for it).

"I think Python now has hex, octal and binary literals. X allows any
base from 2 to 16: 2x10101 is binary, while 4x101 is quaternary (ie.
20)."

Do you mean that 4x101 means 1*(4*4) + 0*(4) + 1? If so, it would be
17, not 20. Is this a typo in the document, or am I misunderstanding
your syntax?

#14 and #15: Are you assuming that a character is a byte and that
diacritical-free English is the only language in the world? Case
insensitivity is a *pain* when you try to be language-agnostic; for
instance, the case-folding rules of English state that U+0069 LATIN
SMALL LETTER I and U+0049 LATIN CAPITAL LETTER I are identical, but
Turkish would upper-case the first to U+0130 LATIN CAPITAL LETTER I
WITH DOT ABOVE and lower-case the second to U+0131 LATIN SMALL LETTER
DOTLESS I. German has U+00DF LATIN SMALL LETTER SHARP S (also called
eszett), which traditionally upper-cases to "SS", which lower-cases to
"ss".

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread BartC

On 26/11/2015 13:15, Chris Angelico wrote:

On Thu, Nov 26, 2015 at 11:53 PM, BartC  wrote:

FWIW here is that list of features that are different between Python and my
language, or that work a different way, or that I think could be a useful
addition. (Although Python's internal workings make many impractical.)

http://pastebin.com/JrVTher6

This is not an attempt to compare the complete languages as they are for
different purposes (mine is more low-level, simpler, smaller and designed to
make it easier to create an efficient byte-code interpreter for it).


"I think Python now has hex, octal and binary literals. X allows any
base from 2 to 16: 2x10101 is binary, while 4x101 is quaternary (ie.
20)."

Do you mean that 4x101 means 1*(4*4) + 0*(4) + 1? If so, it would be
17, not 20. Is this a typo in the document, or am I misunderstanding
your syntax?


Just a mistake. The example had been 4x100 which is 16, but I changed it 
to 4x101 for a bit less confusion, which as you say is 17 not 20 which 
is 4x110.


(Although not used much, I have used quaternary here for example:

  4x3032_3233_2323

The digits represent the number of extra days more than 28 in each 
month, from Jan to Dec.)



--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread MRAB

On 2015-11-26 14:40, BartC wrote:

On 26/11/2015 13:15, Chris Angelico wrote:

On Thu, Nov 26, 2015 at 11:53 PM, BartC  wrote:

FWIW here is that list of features that are different between Python and my
language, or that work a different way, or that I think could be a useful
addition. (Although Python's internal workings make many impractical.)

http://pastebin.com/JrVTher6

This is not an attempt to compare the complete languages as they are for
different purposes (mine is more low-level, simpler, smaller and designed to
make it easier to create an efficient byte-code interpreter for it).


"I think Python now has hex, octal and binary literals. X allows any
base from 2 to 16: 2x10101 is binary, while 4x101 is quaternary (ie.
20)."

Do you mean that 4x101 means 1*(4*4) + 0*(4) + 1? If so, it would be
17, not 20. Is this a typo in the document, or am I misunderstanding
your syntax?


Just a mistake. The example had been 4x100 which is 16, but I changed it
to 4x101 for a bit less confusion, which as you say is 17 not 20 which
is 4x110.

(Although not used much, I have used quaternary here for example:

4x3032_3233_2323

The digits represent the number of extra days more than 28 in each
month, from Jan to Dec.)

Smalltalk uses "r" (for "radix") rather than "x", and can handle any 
base from 2 to 36.


--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-26 Thread MRAB

On 2015-11-26 12:53, BartC wrote:

On 26/11/2015 01:52, Ned Batchelder wrote:

On Wednesday, November 25, 2015 at 8:23:36 PM UTC-5, BartC wrote:

On 26/11/2015 00:31, Steven D'Aprano wrote:



It really, truly isn't. Your viewpoint is clouded by too much immersion in
crippled languages. *Old and obsolete versions* of crippled languages.
Dynamic creation of functions goes back to the 1950s.



It's funny then that the vast majority of top-level function definitions
I see in Python (and import and class statements too) are decidedly static.



I almost started to explain about how yes, Python is often written in
conservative static ways. I was going to mention that a little dynamic
nature goes a long way, and is never far from the surface in even the
simplest Python programs.

But I won't, because I'm not sure you're really interested.  There's a
pattern here of people trying to explain Python to you, and eventually,
after many words, getting to some kind of shared understanding, only
for you to shrug it all off as a fad, or pocket-lining, or needless
complexity.


I'm sorry if I've been misunderstood.

I simply stated that Python's approach was novel. Steven D'Aprano then
responded by belittling my view, and effectively trashing every language
I've ever used.


[snip]
Well, it's not /that/ new.

Both Forth and PostScript define functions by execution.

--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Arie van Wingerden
>and even then, familiar to who?  High school algebra students will at
>first be baffled by "x = x + 1", an equation which is clearly
>unsatisfiable.
Some languages are "better" in that specific case in my opinion (mind te
double quotes :-)
   - Ada and Pascal use := instead of = which is simpler to grasp for n00bs
(I think)
   - Erlang uses pattern matching. So when left hand side does NOT right
hand side, yuou get an exception.
 Each variable can be only assigned once and only once.
 That is the most purely mathematical approach (I think)
   - Haskell


2015-11-25 16:13 GMT+01:00 Ned Batchelder :

> On Wednesday, November 25, 2015 at 8:20:59 AM UTC-5, BartC wrote:
> > Accept that some things /are/ a source of confusion. When, in writing
> > documentation, I find something hard to explain something, then I try
> > and make it simpler in the program. But not enough of that goes on: it
> > seems to be more lucrative to write thicker user manuals, and provide
> > longer training courses, than to make software simpler.
>
> You seem to be insinuating that someone has made Python unusually complex
> for personal gain?  I'm not sure what to do with that: it's an absurd
> claim.
>
> > > "Why does the loop run forever?"
> > >
> > > The coin doesn't magically toss itself, no matter how intuitively
> obvious it
> > > is that it should.
> >
> > The concept of variables doesn't take long to learn in an 'ordinary'
> > language.
>
> There is a natural tension between making a language simple enough that
> it has no surprises or difficult parts; and making a language rich
> enough that it can be used for building serious systems.
>
> If you have another language to propose as a better beginner's learning
> language, please propose it.  I think it serves beginners better to
> teach them with a language that they can then go on to use for building
> real things.  Is there a real language (an "ordinary" language) that
> you think is better than Python for that?  Empirical evidence in the
> world says, "not really."
>
> I know you have languages of your own, and that you like the way they
> work better.  We have no way of evaluating their power or simplicity,
> since they are not available to us.
>
> I agree with you: there are things about Python that surprise people.
> That's because it's a programming language, and very very little about
> programming languages is obvious.  The best we can hope for is "familiar,"
> and even then, familiar to who?  High school algebra students will at
> first be baffled by "x = x + 1", an equation which is clearly
> unsatisfiable.
>
> So yes, there are parts of Python that are hard, and surprising. There
> are subtleties that require study and careful thought.  We believe that
> on the balance, Python is better than many of the alternatives. You
> are welcome to disagree, but don't be surprised if you encounter
> vigorous counter-arguments in a Python mailing list!
>
> There isn't much we can do about the structure of the language, certainly
> not the parts that have been discussed in this thread.  The best we can
> do is try to explain it better.
>
> --Ned.
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 25/11/2015 15:13, Ned Batchelder wrote:

On Wednesday, November 25, 2015 at 8:20:59 AM UTC-5, BartC wrote:

Accept that some things /are/ a source of confusion. When, in writing
documentation, I find something hard to explain something, then I try
and make it simpler in the program. But not enough of that goes on: it
seems to be more lucrative to write thicker user manuals, and provide
longer training courses, than to make software simpler.


You seem to be insinuating that someone has made Python unusually complex
for personal gain?  I'm not sure what to do with that: it's an absurd
claim.


Actually I was thinking of certain Microsoft products. But I think my 
point stands: the design of software could be influenced more by the 
documentation. In the case of languages, that's perhaps harder because 
languages tend to evolve, and they usually have to be backwards compatible.



"Why does the loop run forever?"

The coin doesn't magically toss itself, no matter how intuitively obvious it
is that it should.


The concept of variables doesn't take long to learn in an 'ordinary'
language.



There is a natural tension between making a language simple enough that
it has no surprises or difficult parts; and making a language rich
enough that it can be used for building serious systems.


Well, with Python I get the impression it's gone too far. Too many 
things are dynamic for the sake of it, and people are perhaps tempted to 
make too much use of that.


Although I do find Python's design interesting, from a language design 
and implementation point of view. It looks deceptively simple...


> I know you have languages of your own, and that you like the way they
> work better.  We have no way of evaluating their power or simplicity,
> since they are not available to us.

My language, while simpler, has its own problems. And I don't want to 
get into support (I've done that in the past with other languages).


So at present, I'd probably still recommend Python, although there is 
also the similar Ruby and the smaller language Lua. There a few others 
but I haven't tried them.


> We have no way of evaluating their power or simplicity,
> since they are not available to us.

I'll see if I can rustle up a comparison so that Python users can see 
what they're missing!


--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Laura Creighton
In a message of Wed, 25 Nov 2015 07:13:41 -0800, Ned Batchelder writes:
>That's because it's a programming language, and very very little about
>programming languages is obvious.  The best we can hope for is "familiar,"
>and even then, familiar to who?  High school algebra students will at
>first be baffled by "x = x + 1", an equation which is clearly
>unsatisfiable.

The great sticking point for the children I am teaching is
'*' means multiplication.  You can really see that some people 
have to make extensive mental modifications in order to handle
the concept that mathematical truths are expressed in linguistic
and orthographic conventions, and that one can swap out a particular
convention 'x means multiply' and swap in another one '* means
multiply' while leaving the underlying truth unchanged.

Laura
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Chris Angelico
On Thu, Nov 26, 2015 at 2:13 AM, Ned Batchelder  wrote:
> I agree with you: there are things about Python that surprise people.
> That's because it's a programming language, and very very little about
> programming languages is obvious.  The best we can hope for is "familiar,"
> and even then, familiar to who?  High school algebra students will at
> first be baffled by "x = x + 1", an equation which is clearly
> unsatisfiable.

And then *lots* of people are confused by "x += 1" being almost, but
not entirely, identical to the above. Actually, if there were one
change I could make to Python, it would be to redefine the augmented
assignment operators to be semantically identical to their expanded
forms; there might be some optimizations, but absolutely no difference
in effect. (Which would mean, among other things, that it would be a
very bad way to append to a list, instead of being an alias for
.extend.)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Random832
On 2015-11-25, Ben Finney  wrote:
> That is, the ‘2’ in ‘cartesian_point = (2, 3)’ means something different
> than in ‘cartesian_point = (3, 2)’.
>
> Whereas the ‘2’ in ‘test_scores = [2, 3]’ means exactly the same as in
> ‘test_scores = [3, 2]’.
>
> If each position in the sequence gives the value there a different
> menaning, use a tuple; if not, use a list.

I don't think that's really right. The absence of first-class
multisets in python does mean that lists get "abused" for that
purpose, but I don't think that means that there's no legitimate
use-case for a list (i.e. a mutable sequence in which position is
significant).

The difference between a tuple and a list is that one is mutable
and the other is not. The difference you are describing is
between a list and a multiset (or a tuple and an immutable
multiset).

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 25/11/2015 22:16, Marko Rauhamaa wrote:

BartC :


I'm interested in language design because that's what I've done on and
off for over 30 years. And I'm discussing some design decisions in
Python.


That *is* a fun ambition, useful or not.


(At the moment, it's mostly fun. But in the past I actually needed the 
languages to do my job (designing microprocessor hardware). The 
scripting languages came a bit later, to go with my 3D graphics 
applications.)



You seem to have been surprised with some advanced concepts and idioms
in this discussion. Really, apart from its indentation syntax, Python
offers no unique or even rare software engineering concepts (Python's
emphasis duck-typing comes close to being distinctive). You'll find
equivalents in quite many languages, and in active, money-making uses.


Maybe you're too familiar with it. But the idea of /executing/ the 
function and other definitions in a file, instead of they just being 
there, is novel.


--
Bartc

--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Emile van Sebille

On 11/25/2015 4:25 AM, Antoon Pardon wrote:


I think there are reasons to find the above behaviour bizarre. I personnaly
don't find it bizarre, but that is because I'm familiar with what is going
on.


Which I suspect is necessary.

>but if someone expects the compilor to take a snapshot of L and iterate

over that I am not going to say he shouldn't have expected that.


That's something I've learned to figure out about any new language I 
pick up -- if parameters are passed by value or by reference, and 
secondly how to invoke a function appropriately for my specific use case.


Unfortunately, there are issues determining if python is in either camp, 
which certainly leads to confusion. see 
http://www.python-course.eu/passing_arguments.php or google "python pass 
by value or reference" for more examples.


Emile

--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Steven D'Aprano
On Thu, 26 Nov 2015 09:41 am, BartC wrote:

> Maybe you're too familiar with it. But the idea of executing the
> function and other definitions in a file, instead of they just being
> there, is novel.


It really, truly isn't. Your viewpoint is clouded by too much immersion in
crippled languages. *Old and obsolete versions* of crippled languages.
Dynamic creation of functions goes back to the 1950s.

Functions in Python are *first class values*, just like ints, strings, lists
etc. That means functions can be passed around as arguments, assigned to
variables, returned from functions, and created on the fly as needed. This
is not an innovation from Python -- Python rarely, if ever, innovates. By
the time any feature hits Python (yes, even significant indentation) it has
typically been proven in at least one other language.

Languages with first class functions include Perl, Javascript, Lua, PHP,
Tcl/Tk, Io, Go, Rust, Maple, Mathematica, Smalltalk, Swift, and varied mix
of old (Smalltalk and Perl) and new (Rust and Swift).

It is almost unthinkable to imagine a functional programming language
without this feature, and sure enough Scala, Haskell, ML, Clojure, and
Scheme have it -- as does Lisp, which is the second oldest high level
language in existence. Only Fortran is older.

Delphi (a variant on Pascal/Algol) has supported them since 2009. C++, C#
and Objective C have support for first class functions. Even Java 8 and
above includes this feature.

In 2015, it's hard to think of any non-obsolete, non-toy language which
doesn't treat functions as first-class values, including creating them on
the fly. Fortran and C perhaps.



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Steven D'Aprano
On Thu, 26 Nov 2015 01:34 am, BartC wrote:

> On 25/11/2015 13:53, Marko Rauhamaa wrote:
>> BartC :
>>
>>> Using tuples in the same way that other languages implement records is
>>> going to be difficult if you can't change the values of the fields!
>>
>> Guido could decide tomorrow that tuples are mutable.
> 
> (Could that be done without breaking existing code? And what then would
> be the difference between them and lists?)


No it could not, and no Guido could not decide to make them mutable. 

Well, strictly speaking he could make that decision, but the other core
developers would not go along with such a stupid backwards-incompatible
change. I don't know what would happen if Guido did make that decision -- I
suppose it would provoke some sort of constitutional crisis (figuratively
speaking), like what would happen if the Queen of the UK refused to sign
into law legislation after being lawfully asked to do so by the Prime
Minister. (The Queen has the power to reject any legislation put to her by
the Prime Minister, so long as she does not actually make use of that
power.)

Guido, as BDFL, has every right to make tuples mutable, or remove numbers
from the language, so long as he does not actually do so.

Making tuples mutable would break their use as dictionary keys, which is a
*critical* use.

https://docs.python.org/2/faq/design.html#why-must-dictionary-keys-be-immutable



>> Anyway, Python has two ways to represent records: classes and tuples.
>> Tuples are nice because they are concise and ad hoc. Often you start
>> with a scalar value, then turn it into a tuple. After a while your handy
>> tuple turns out a bit cumbersome to use so you convert it into an actual
>> class.
> 
> This is how records are handled in another language which I believe is
> simpler than Python: http://pastebin.com/vhsJML8U
> 
> This also implements my example from earlier in the thread. Now compare
> with Python's approach.
> 
> OK, that also needs two concepts, a list, and a record. But the
> distinction is now completely obvious. Records are also mutable. It
> would also be clear why you can't append to a record.
> 
> Now try explaining again to me how you would use tuples for the same
> thing...

In Pascal, strings are mutable. (Well, technically, standard Pascal doesn't
define a string data type, but most implementations do.) So you typically
have some function like:

insert(thestring, substring, pos)

which modifies thestring in place. In Python, strings are immutable, so the
equivalent of insert() would be a function that returns a new string:

thestring = insert(thestring, substring, pos)

It's not exactly an earth-shattering difference.

The implementation is simple that it is almost pointless to put it in a
function:

def insert(s, substring, pos):
return s[:pos] + substring + s[pos:]


Tuples-as-records are no different. Instead of modifying the existing
record, you create a new one. If that's inconvenient, then use a class,
which will be mutable by default.



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 26/11/2015 00:31, Steven D'Aprano wrote:

On Thu, 26 Nov 2015 09:41 am, BartC wrote:


Maybe you're too familiar with it. But the idea of executing the
function and other definitions in a file, instead of they just being
there, is novel.



It really, truly isn't. Your viewpoint is clouded by too much immersion in
crippled languages. *Old and obsolete versions* of crippled languages.
Dynamic creation of functions goes back to the 1950s.

Functions in Python are *first class values*, just like ints, strings, lists
etc. That means functions can be passed around as arguments, assigned to
variables, returned from functions, and created on the fly as needed. This
is not an innovation from Python -- Python rarely, if ever, innovates. By
the time any feature hits Python (yes, even significant indentation) it has
typically been proven in at least one other language.

Languages with first class functions include Perl, Javascript, Lua, PHP,
Tcl/Tk, Io, Go, Rust, Maple, Mathematica, Smalltalk, Swift, and varied mix
of old (Smalltalk and Perl) and new (Rust and Swift).

It is almost unthinkable to imagine a functional programming language
without this feature, and sure enough Scala, Haskell, ML, Clojure, and
Scheme have it -- as does Lisp, which is the second oldest high level
language in existence. Only Fortran is older.

Delphi (a variant on Pascal/Algol) has supported them since 2009. C++, C#
and Objective C have support for first class functions. Even Java 8 and
above includes this feature.

In 2015, it's hard to think of any non-obsolete, non-toy language which
doesn't treat functions as first-class values, including creating them on
the fly. Fortran and C perhaps.


It's funny then that the vast majority of top-level function definitions 
I see in Python (and import and class statements too) are decidedly static.


The names are declared, but the names are rarely bound to anything else. 
Functions are just called the same boring way they are in C.


/They might as well be static definitions/.

(In fact, all this dynamic set-up, while it makes for an elegant and 
consistent language, probably also makes it unnecessarily harder to 
accelerate.)


Clearly a huge amount of programming can be done without having to deal 
with first-class functions (or constructing functions at run-time; that 
sounds fun). (Or without using OOP, another thing I can't stand.)


Some people just don't want to be functional programmers. It is elitist 
to try and make out it that it is that important.


If lots of languages now have functional features, it's more likely to 
be a case of keeping up with the Joneses.


--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Steven D'Aprano
On Thu, 26 Nov 2015 12:20 am, BartC wrote:

> On 25/11/2015 10:52, Steven D'Aprano wrote:
>> On Wed, 25 Nov 2015 07:14 pm, Antoon Pardon wrote:
> 
>>> What exactly is your point?
>>
>> That there is a simple analogy between the distinction between code
>> inside/outside a for-loop, and code inside/outside a function. If you can
>> understand why this loops forever, instead of just twice, then you can
>> understand why function defaults work the way they do:
>>
>> L = [1, 2]
>> for i in L:
>>  L.append(i)
>>  print(L)
>>
>>
>> There is nothing "bizarre" or complicated or difficult to understand
>> happening here.
> 
> What do you think most people would expect to happen here? 

I wouldn't try to guess what "most" people would expect. Their expectations
would depend on what exposure they have had with programming languages, if
any, what languages those are, and how well they grok the idea of
simulating code in their own head.



> I know, 
> because you gave a spoiler, that it loops forever, otherwise I wouldn't
> be sure /without trying it/ (but I tried it anyway).
> 
> Here's the same code in a somewhat different language:
> 
> L := (1,2)
> for i in L do
> |   L append:= i
> |   println L
> od
> 
> And this is the output:
> 
> (1,2,1)
> (1,2,1,2)
> 
> Which output (infinite series of [1,2,1,2,1,] or the above) is more
> sensible, and which do you think people might prefer?

The infinite loop is more sensible, and people would prefer the above
output. Who wants an infinite loop? That's nearly always a bug.

But consider why, bug or no bug, the Python version which leads to an
infinite series should be preferred over the other version. I can think of
at least three reasons why the Python behaviour is objectively better,
despite leading to an unwanted infinite loop in this specific case.

(1) The Python version avoids always making a copy of the (potentially huge)
list before looping over it. That makes the performance of for-loops more
predictable and avoids horrible surprises:

for x in L:
break

takes the same amount of time to execute whether L has one item or a hundred
billion items. The for-loop *overhead* (as opposed to the cost of the loop
itself) is a fixed, small amount.


(2) The Python version has a cleaner, easier to understand execution model.
Apart from two obvious exceptions (on the left hand side of an assignment,
or following the "del" statement) all uses of the name L have the same
meaning. Whether you write:

for x in L

if "foo" in L

while L

L + [1, 2]

len(L)

L or []

L.append(42)

or any other expression, all uses of the name L evaluate to the same thing:
the object currently bound to that name. You don't have to try to remember
which uses evaluate to the original object and which make a copy. It is
*never* a copy -- if you want a copy, you can copy it yourself. (Use the
copy module, copy.copy(L), or take a slice, L[:].)

The cost of this is that you are always responsible for making a copy, since
Python won't automatically do it for you (whether you want a copy or not).
But the benefit is that you avoid making unnecessary copies. 

I infer from the line "L append:= i" that your language doesn't always make
a copy (otherwise, how could you modify the original?). That means that
you, the programmer, still has to manage the copying of the list, exactly
the same as we have to do with Python. The difference is, Python doesn't
lure you into a false sense of security by *sometimes* making that copy for
you. The rules are:

"In Python, if you want a copy of the list, make a copy yourself."

versus:

"In BartC's language, if you want a copy of the list, look up the operation
you are about to do to see if it already makes a copy, and if it doesn't,
then make a copy yourself. (Otherwise, you might make two copies.)"


(3) What if you don't want a copy? How does one disable that feature? Or
does your language simply declare that "you can't do that"?

for item in queue:
process(item)
if condition: queue.append(something)


What's the most natural equivalent to that code snippet in your language?



> The point is that the behaviour of the loop is by no means obvious, so
> neither is the behaviour of the function defaults.

I'm pretty sure that nobody said the behaviour was obvious in the sense of
predictable to those unfamiliar with the rules of the language. There's
even a FAQ about it.

There's a big difference between *obvious in advance* and *obvious in
hindsight once an explanation is given*.



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Ian Kelly
On Wed, Nov 25, 2015 at 5:52 PM, Random832  wrote:
> On 2015-11-25, Ben Finney  wrote:
>> That is, the ‘2’ in ‘cartesian_point = (2, 3)’ means something different
>> than in ‘cartesian_point = (3, 2)’.
>>
>> Whereas the ‘2’ in ‘test_scores = [2, 3]’ means exactly the same as in
>> ‘test_scores = [3, 2]’.
>>
>> If each position in the sequence gives the value there a different
>> menaning, use a tuple; if not, use a list.
>
> I don't think that's really right. The absence of first-class
> multisets in python does mean that lists get "abused" for that
> purpose, but I don't think that means that there's no legitimate
> use-case for a list (i.e. a mutable sequence in which position is
> significant).
>
> The difference between a tuple and a list is that one is mutable
> and the other is not. The difference you are describing is
> between a list and a multiset (or a tuple and an immutable
> multiset).

I think that Ben was actually trying to make a distinction between
heterogeneity and homogeneity of the contents, not a distinction of
whether the collection was ordered or not. You can of course have a
homogeneous collection for which order is still important, e.g. a
batting line-up.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Ned Batchelder
On Wednesday, November 25, 2015 at 8:23:36 PM UTC-5, BartC wrote:
> On 26/11/2015 00:31, Steven D'Aprano wrote:
> > On Thu, 26 Nov 2015 09:41 am, BartC wrote:
> >
> >> Maybe you're too familiar with it. But the idea of executing the
> >> function and other definitions in a file, instead of they just being
> >> there, is novel.
> >
> >
> > It really, truly isn't. Your viewpoint is clouded by too much immersion in
> > crippled languages. *Old and obsolete versions* of crippled languages.
> > Dynamic creation of functions goes back to the 1950s.
> >
> > Functions in Python are *first class values*, just like ints, strings, lists
> > etc. That means functions can be passed around as arguments, assigned to
> > variables, returned from functions, and created on the fly as needed. This
> > is not an innovation from Python -- Python rarely, if ever, innovates. By
> > the time any feature hits Python (yes, even significant indentation) it has
> > typically been proven in at least one other language.
> >
> > Languages with first class functions include Perl, Javascript, Lua, PHP,
> > Tcl/Tk, Io, Go, Rust, Maple, Mathematica, Smalltalk, Swift, and varied mix
> > of old (Smalltalk and Perl) and new (Rust and Swift).
> >
> > It is almost unthinkable to imagine a functional programming language
> > without this feature, and sure enough Scala, Haskell, ML, Clojure, and
> > Scheme have it -- as does Lisp, which is the second oldest high level
> > language in existence. Only Fortran is older.
> >
> > Delphi (a variant on Pascal/Algol) has supported them since 2009. C++, C#
> > and Objective C have support for first class functions. Even Java 8 and
> > above includes this feature.
> >
> > In 2015, it's hard to think of any non-obsolete, non-toy language which
> > doesn't treat functions as first-class values, including creating them on
> > the fly. Fortran and C perhaps.
> 
> It's funny then that the vast majority of top-level function definitions 
> I see in Python (and import and class statements too) are decidedly static.
> 
> The names are declared, but the names are rarely bound to anything else. 
> Functions are just called the same boring way they are in C.
> 
> /They might as well be static definitions/.
> 
> (In fact, all this dynamic set-up, while it makes for an elegant and 
> consistent language, probably also makes it unnecessarily harder to 
> accelerate.)
> 
> Clearly a huge amount of programming can be done without having to deal 
> with first-class functions (or constructing functions at run-time; that 
> sounds fun). (Or without using OOP, another thing I can't stand.)
> 
> Some people just don't want to be functional programmers. It is elitist 
> to try and make out it that it is that important.
> 
> If lots of languages now have functional features, it's more likely to 
> be a case of keeping up with the Joneses.

I almost started to explain about how yes, Python is often written in
conservative static ways. I was going to mention that a little dynamic
nature goes a long way, and is never far from the surface in even the
simplest Python programs.

But I won't, because I'm not sure you're really interested.  There's a
pattern here of people trying to explain Python to you, and eventually,
after many words, getting to some kind of shared understanding, only
for you to shrug it all off as a fad, or pocket-lining, or needless
complexity.

For someone who claims to be interested in language design, you're
remarkably dismissive of pretty much the entire industry.  I don't think
it's worth the effort to try to change your mind.

--Ned.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 25/11/2015 18:03, Ian Kelly wrote:

On Wed, Nov 25, 2015 at 10:18 AM, BartC  wrote:

We have no way of evaluating their power or simplicity,
since they are not available to us.


I'll see if I can rustle up a comparison so that Python users can see what
they're missing!


Unless you're going to make the actual languages available for public
use, what's the point?


For ideas? Sometimes it's interesting to know about other approaches to 
a feature or new ones that can be useful.


Then someone else can implement them! I'd be sharing my language design 
ideas not my amateurish implementations.


(Which aren't easy to distribute anyway because they are implemented in 
themselves.)


--
Bartc




--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Emile van Sebille

On 11/25/2015 5:20 AM, BartC wrote:


it seems to be more lucrative to write thicker user manuals, and provide
longer training courses, than to make software simpler.


If that were true, certainly by now the sufficiently thick manual would 
provide crystal clear explanations.  :)


I-don't-think-obfustication-is-the-point-ly y'rs,

Emile


--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Ben Finney
Chris Angelico  writes:

> This is a distinction I generally make. Putting it another way: a list
> has the same meaning regardless of how many items are on it (for
> instance, a shopping list is still a shopping list whether it has five
> or fifty items on it), where a tuple is a package where each element
> has a specific meaning […]

Yes. The disctinction is even clearer, I find, by saying that the
*meaning of the position* in the sequence is significant for a tuple,
not significant for a list.

That is, the ‘2’ in ‘cartesian_point = (2, 3)’ means something different
than in ‘cartesian_point = (3, 2)’.

Whereas the ‘2’ in ‘test_scores = [2, 3]’ means exactly the same as in
‘test_scores = [3, 2]’.

If each position in the sequence gives the value there a different
menaning, use a tuple; if not, use a list.

> Nothing in the language enforces this, but the mutability of lists
> does tend to align well with things that can grow and shrink, and the
> immutability of tuples makes them more like strings or complex numbers
> (in fact, a complex number is basically a tuple of two floats).

Not only the growing and shrinking, but the re-ordering of items in a
list should not change the meaning of its items.

If you can ‘sort’ the sequence and the items still mean exactly what
they did before, then a tuple is the wrong type to use, semantically.

-- 
 \   “Crime is contagious… if the government becomes a lawbreaker, |
  `\  it breeds contempt for the law.” —Justice Louis Brandeis |
_o__)  |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Mark Lawrence

On 25/11/2015 17:18, BartC wrote:

On 25/11/2015 15:13, Ned Batchelder wrote:

On Wednesday, November 25, 2015 at 8:20:59 AM UTC-5, BartC wrote:

Accept that some things /are/ a source of confusion. When, in writing
documentation, I find something hard to explain something, then I try
and make it simpler in the program. But not enough of that goes on: it
seems to be more lucrative to write thicker user manuals, and provide
longer training courses, than to make software simpler.


You seem to be insinuating that someone has made Python unusually complex
for personal gain?  I'm not sure what to do with that: it's an absurd
claim.


Actually I was thinking of certain Microsoft products. But I think my
point stands: the design of software could be influenced more by the
documentation. In the case of languages, that's perhaps harder because
languages tend to evolve, and they usually have to be backwards compatible.


"Why does the loop run forever?"

The coin doesn't magically toss itself, no matter how intuitively
obvious it
is that it should.


The concept of variables doesn't take long to learn in an 'ordinary'
language.



There is a natural tension between making a language simple enough that
it has no surprises or difficult parts; and making a language rich
enough that it can be used for building serious systems.


Well, with Python I get the impression it's gone too far. Too many
things are dynamic for the sake of it, and people are perhaps tempted to
make too much use of that.

Although I do find Python's design interesting, from a language design
and implementation point of view. It looks deceptively simple...

 > I know you have languages of your own, and that you like the way they
 > work better.  We have no way of evaluating their power or simplicity,
 > since they are not available to us.

My language, while simpler, has its own problems. And I don't want to
get into support (I've done that in the past with other languages).

So at present, I'd probably still recommend Python, although there is
also the similar Ruby and the smaller language Lua. There a few others
but I haven't tried them.

 > We have no way of evaluating their power or simplicity,
 > since they are not available to us.

I'll see if I can rustle up a comparison so that Python users can see
what they're missing!



Can you please let us know what you're taking, what it costs and where 
we can get it, as we would also like to live in cloud cuckoo land, 
provided that The Price Is Right™.


Although credit where credit is due, you are one of the most successful 
trolls to con this list in years.  I must offer my congratulations.


--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Marko Rauhamaa
Ben Finney :

> Perhaps it would be easier if you point out that ‘x’ doesn't mean
> multiply either, and they've *already* been substituting that symbol
> instead of the correct ‘×’ for multiply.

In my childhood, we always used '·' for the multiplication sign until
senior high school, when the vector product was introduced.

I seem to recall ‘×’ was used in cartesian products already in junior
high.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 25/11/2015 20:50, Mark Lawrence wrote:

On 25/11/2015 17:18, BartC wrote:



Can you please let us know what you're taking, what it costs and where
we can get it, as we would also like to live in cloud cuckoo land,
provided that The Price Is Right™.


And I would really like to know what your problem is.

I'm interested in language design because that's what I've done on and 
off for over 30 years. And I'm discussing some design decisions in Python.



Although credit where credit is due, you are one of the most successful
trolls to con this list in years.  I must offer my congratulations.


If you think I'm a 'troll' then that's your business. But I'm not 
holding a gun to your head and forcing you to read my posts.


--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Marko Rauhamaa
BartC :

> I'm interested in language design because that's what I've done on and
> off for over 30 years. And I'm discussing some design decisions in
> Python.

That *is* a fun ambition, useful or not.

However, while I'm very choosy and critical when it comes to my
programming tools, I'm extremely happy with the programming language
options that are freely available. It would be very difficult to beat
the existing options with expressive power or elegance.

You seem to have been surprised with some advanced concepts and idioms
in this discussion. Really, apart from its indentation syntax, Python
offers no unique or even rare software engineering concepts (Python's
emphasis duck-typing comes close to being distinctive). You'll find
equivalents in quite many languages, and in active, money-making uses.

> I'm not holding a gun to your head and forcing you to read my posts.

Follow your own advice.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Ben Finney
Laura Creighton  writes:

> The great sticking point for the children I am teaching is '*' means
> multiplication. […] that one can swap out a particular convention 'x
> means multiply' and swap in another one '* means multiply' while
> leaving the underlying truth unchanged.

Perhaps it would be easier if you point out that ‘x’ doesn't mean
multiply either, and they've *already* been substituting that symbol
instead of the correct ‘×’ for multiply.

-- 
 \ “Our task must be to free ourselves from our prison by widening |
  `\our circle of compassion to embrace all humanity and the whole |
_o__)   of nature in its beauty.” —Albert Einstein |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Ian Kelly
On Wed, Nov 25, 2015 at 10:18 AM, BartC  wrote:
>> We have no way of evaluating their power or simplicity,
>> since they are not available to us.
>
> I'll see if I can rustle up a comparison so that Python users can see what
> they're missing!

Unless you're going to make the actual languages available for public
use, what's the point?
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Ned Batchelder
On Wednesday, November 25, 2015 at 8:20:59 AM UTC-5, BartC wrote:
> Accept that some things /are/ a source of confusion. When, in writing 
> documentation, I find something hard to explain something, then I try 
> and make it simpler in the program. But not enough of that goes on: it 
> seems to be more lucrative to write thicker user manuals, and provide 
> longer training courses, than to make software simpler.

You seem to be insinuating that someone has made Python unusually complex
for personal gain?  I'm not sure what to do with that: it's an absurd
claim.  

> > "Why does the loop run forever?"
> >
> > The coin doesn't magically toss itself, no matter how intuitively obvious it
> > is that it should.
> 
> The concept of variables doesn't take long to learn in an 'ordinary' 
> language.

There is a natural tension between making a language simple enough that
it has no surprises or difficult parts; and making a language rich
enough that it can be used for building serious systems.

If you have another language to propose as a better beginner's learning
language, please propose it.  I think it serves beginners better to
teach them with a language that they can then go on to use for building
real things.  Is there a real language (an "ordinary" language) that
you think is better than Python for that?  Empirical evidence in the
world says, "not really."

I know you have languages of your own, and that you like the way they
work better.  We have no way of evaluating their power or simplicity,
since they are not available to us.

I agree with you: there are things about Python that surprise people.
That's because it's a programming language, and very very little about
programming languages is obvious.  The best we can hope for is "familiar,"
and even then, familiar to who?  High school algebra students will at
first be baffled by "x = x + 1", an equation which is clearly
unsatisfiable.

So yes, there are parts of Python that are hard, and surprising. There
are subtleties that require study and careful thought.  We believe that
on the balance, Python is better than many of the alternatives. You
are welcome to disagree, but don't be surprised if you encounter
vigorous counter-arguments in a Python mailing list!

There isn't much we can do about the structure of the language, certainly
not the parts that have been discussed in this thread.  The best we can
do is try to explain it better.

--Ned.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Mark Lawrence

On 26/11/2015 05:08, Ben Finney wrote:

Ned Batchelder  writes:


For someone who claims to be interested in language design, you're
remarkably dismissive of pretty much the entire industry. I don't
think it's worth the effort to try to change your mind.


+1.

BartC, when you want to join us in discussions on good faith – that is,
honestly wanting to learn Python rather than dogmatically persisting in
your misperceptions dogmatically onto it – we'll still be here, making
happy use of Python the way it is.



Ben and Ned, I'd like to thank both of you for these comments as they 
are put far more eloquently and diplomatically than I would ever manage.


--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Marko Rauhamaa
BartC :
> Clearly a huge amount of programming can be done without having to deal
> with first-class functions (or constructing functions at run-time; that
> sounds fun). (Or without using OOP, another thing I can't stand.)

Even the lowliest code monkeys deal with on-the-fly functions and OOP
nowadays. You can't escape them in C# and Java, for example.

> Some people just don't want to be functional programmers. It is
> elitist to try and make out it that it is that important.
>
> If lots of languages now have functional features, it's more likely to
> be a case of keeping up with the Joneses.

There's some of that. Generics and closures in Java are examples.

However, anonymous classes have been there in Java since the dawn of
days, and they are equally "elitist" as closures.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Larry Hudson via Python-list

On 11/25/2015 12:32 AM, Chris Angelico wrote:

On Wed, Nov 25, 2015 at 7:14 PM, Antoon Pardon
 wrote:

[snip]


"Oh come on. It's basic arithmetic. You should be able to add 7 and
7... the result's 14!"

"But it's so confusing. Why can't it be 16? It'd be more convenient
for me if it were 16."


No.  It's 42.;-)

 -=- Larry -=-



--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Marko Rauhamaa
Steven D'Aprano :

> Making tuples mutable would break their use as dictionary keys, which is a
> *critical* use.

No, it wouldn't. Any object that provides __hash__() and __eq__() can be
used as a key.

Nothing prevents using mutable objects as keys in Python.

Egon Spengler: There's something very important I forgot to tell you.
Peter Venkman: What?
Spengler: Don't use mutable keys.
Venkman: Why?
Spengler: It would be bad.
Venkman: I'm fuzzy on the whole good/bad thing. What do you mean,
   "bad"?
Spengler: Try to imagine all life as you know it stopping
instantaneously and every molecule in your body exploding at the
speed of light.
Ray Stantz: Total protonic reversal!
Venkman: Right. That's bad. Okay. All right. Important safety tip.
Thanks, Egon.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Antoon Pardon
Op 25-11-15 om 09:32 schreef Chris Angelico:
> On Wed, Nov 25, 2015 at 7:14 PM, Antoon Pardon
>  wrote:
>> What exactly is your point? People's confusions don't disappear
>> because you as an expert have a good understanding of what is
>> going on and so are no longer confused.
>>
>> Some aspects in the langauage are easily grasped and other
>> aspects tend to create confusion. I see nothing wrong with
>> people trying to point out what the cause of this confusion
>> could be. You arguing that people shouldn't be confused is
>> not helping.
> "Oh come on. It's basic arithmetic. You should be able to add 7 and
> 7... the result's 14!"
>
> "But it's so confusing. Why can't it be 16? It'd be more convenient
> for me if it were 16."
>
> "This is just how arithmetic works."
>
> "But it's still confusing!"
>
> At some point, you have to simply accept that this is how the system
> works.. or use a different system. (Octal maybe.) If you are
> perpetually confused by Python, you need to either learn how Python
> works, or use something else.

Those are not the only choices. The third option is that those at
the drawing board of python come to the conclusion that some aspect
of python is needlessly confusing and change the design.

I also find your comparison disingenous. The responses I see often
enough are not simply: this is how python works. They are often
enough something like: How can you find this confusing, you shouldn't.

If the regulars would answer more something like: Yes it can be confusing,
you are not the only one, but let me explain what is going on. and the
other would keep complaining about it being confusing, you would have
a point.

Instead the regulars all too often go on a tangent on how it shouldn't
be confusing or something similar and then they are surprised that
the exchange that follows isn't very fruitful.

-- 
Antoon Pardon

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Antoon Pardon
Op 20-11-15 om 01:33 schreef Steven D'Aprano:
> On Fri, 20 Nov 2015 07:57 am, Marko Rauhamaa wrote:
>
>> Laura Creighton :
>>
>>> My experience says that the people who are confused want lists to
>>> behave like tuples. period. i.e. they don't want lists to be mutable.
>> I think it's simpler than that. When you have:
>>
>>def f(x=[]):
>>y = []
>>
>> the first [] is evaluated when "def" is executed, while the latter [] is
>> evaluated whenever "f" is executed. It's easy to be confused.
> It shouldn't be. The function declaration 
>
> def f(x=[]):
>
> is executed only once. The function body, conveniently indented to make it
> stand out:
>
> y = []
>
> is executed every time you call the function. 

What exactly is your point? People's confusions don't disappear
because you as an expert have a good understanding of what is
going on and so are no longer confused.

Some aspects in the langauage are easily grasped and other
aspects tend to create confusion. I see nothing wrong with
people trying to point out what the cause of this confusion
could be. You arguing that people shouldn't be confused is
not helping.

-- 
Antoon.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Chris Angelico
On Wed, Nov 25, 2015 at 7:14 PM, Antoon Pardon
 wrote:
> What exactly is your point? People's confusions don't disappear
> because you as an expert have a good understanding of what is
> going on and so are no longer confused.
>
> Some aspects in the langauage are easily grasped and other
> aspects tend to create confusion. I see nothing wrong with
> people trying to point out what the cause of this confusion
> could be. You arguing that people shouldn't be confused is
> not helping.

"Oh come on. It's basic arithmetic. You should be able to add 7 and
7... the result's 14!"

"But it's so confusing. Why can't it be 16? It'd be more convenient
for me if it were 16."

"This is just how arithmetic works."

"But it's still confusing!"

At some point, you have to simply accept that this is how the system
works.. or use a different system. (Octal maybe.) If you are
perpetually confused by Python, you need to either learn how Python
works, or use something else.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Marko Rauhamaa
Chris Angelico :

> At some point, you have to simply accept that this is how the system
> works.. or use a different system. (Octal maybe.) If you are
> perpetually confused by Python, you need to either learn how Python
> works, or use something else.

You are mixing two things: protesting and being confused. Protesting
about a fundamental tenet is of no use, but talking about confusion
might help.

One psychological problem I'm seeing in many answers here is that people
seem to want to defend the honor of Python. It's very religion-like. New
potential converts are welcomed with open arms but when they start to
ask awkward questions, they are treated as suppressive persons.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Steven D'Aprano
On Wed, 25 Nov 2015 07:14 pm, Antoon Pardon wrote:

> Op 20-11-15 om 01:33 schreef Steven D'Aprano:
>> On Fri, 20 Nov 2015 07:57 am, Marko Rauhamaa wrote:
>>
>>> Laura Creighton :
>>>
 My experience says that the people who are confused want lists to
 behave like tuples. period. i.e. they don't want lists to be mutable.
>>> I think it's simpler than that. When you have:
>>>
>>>def f(x=[]):
>>>y = []
>>>
>>> the first [] is evaluated when "def" is executed, while the latter [] is
>>> evaluated whenever "f" is executed. It's easy to be confused.
>> It shouldn't be. The function declaration
>>
>> def f(x=[]):
>>
>> is executed only once. The function body, conveniently indented to make
>> it stand out:
>>
>> y = []
>>
>> is executed every time you call the function.
> 
> What exactly is your point? 

That there is a simple analogy between the distinction between code
inside/outside a for-loop, and code inside/outside a function. If you can
understand why this loops forever, instead of just twice, then you can
understand why function defaults work the way they do:

L = [1, 2]
for i in L:
L.append(i)
print(L)


There is nothing "bizarre" or complicated or difficult to understand
happening here. It might not be what you want to happen. It might not be
what you expect to happen. But if you can't understand why it happens even
after multiple explanations, then your learning skills are severely
lacking.



> People's confusions don't disappear 
> because you as an expert have a good understanding of what is
> going on and so are no longer confused.

I'm an expert? Awesome!

No. But people's confusion would disappear if they would:

- think about the process
- try to follow the steps of what is happening
- pay attention to the explanations given
- and ask for clarification instead of arguing.

I have come to the conclusion that there is nobody as stupid as an
intelligent person who refuses to learn.

I really don't know how more clear we can possibly be. If you take a list,
initialised as the empty list ONCE, and then modify it repeatedly, the list
doesn't magically become empty just because you want it to be empty.

I completely understand beginners making this mistake:

# Simulate tossing a coin until it is heads.
count = 1
coin = random.choice(['heads', 'tails'])
while coin != 'heads':
count += 1

"Why does the loop run forever?"


The coin doesn't magically toss itself, no matter how intuitively obvious it
is that it should. (And I'm not making this example up -- I've seen three
or four beginners make equivalent errors. It seems to be a very common
conceptual mistake.)

These beginners, at least, don't argue back that it is "bizarre" and stupid
and crazy that you have to choose a new value for the coin variable each
time through the loop. They soon learn that code outside the loop only runs
once, if you want it to run each time through the loop, you should put it
inside the body of the loop.

Just like functions. If you want code to run each time you call the
function, PUT IT INSIDE THE FUNCTION BODY.


> Some aspects in the langauage are easily grasped and other
> aspects tend to create confusion. 

You're right. Some aspects of the language are inherently confusing and hard
to reason about. Threads are an example of that. The more powerful, and
tricky, aspects of regular expressions. The weird stuff that happens during
interpreter shutdown if you have __del__ methods in your objects. __del__
methods in general. There are many things which are hard to reason about,
and therefore confusing.

*This is not one of them.*

This is not hard to reason about. The rules are no different from what
happens in simple, ordinary code:

L = []  # Initialise the list *once*.
def func():
L.append(1)
return L

If I call func() three times, what value does it return? If you can get
that, you can get this:

def func(L=[]):  # Initialise the list *once*.
L.append(1)
return L

Confusing? Absolutely not. Or rather, if anyone cannot understand the
behaviour of either function *after having it explained multiple times*,
then programming is the wrong area for them. They should take up something
more suited to their intellectual limitations, like dish washing, ditch
digging, or politics.

But is it predictable or intuitive? No, I agree, this behaviour is not
intuitive, if you are coming from a background without equivalent rules. I
will completely grant you that most people without Python experience would
not correctly predict the behaviour of mutable defaults.

I was caught out on that too, as I already admitted. Even though I already
knew all the facts I needed to predict the behaviour correctly, I didn't
put 2+2 together and get 4. That's *my bad*, not the language's fault.

How much harder must it be for those who don't know the essential facts? I
don't expect anyone to intuit the behaviour of Python defaults. That would
be unreasonable. There's no shame in 

Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 25/11/2015 08:32, Chris Angelico wrote:

On Wed, Nov 25, 2015 at 7:14 PM, Antoon Pardon
 wrote:

What exactly is your point? People's confusions don't disappear
because you as an expert have a good understanding of what is
going on and so are no longer confused.

Some aspects in the langauage are easily grasped and other
aspects tend to create confusion. I see nothing wrong with
people trying to point out what the cause of this confusion
could be. You arguing that people shouldn't be confused is
not helping.


"Oh come on. It's basic arithmetic. You should be able to add 7 and
7... the result's 14!"

"But it's so confusing. Why can't it be 16? It'd be more convenient
for me if it were 16."

"This is just how arithmetic works."

"But it's still confusing!"

At some point, you have to simply accept that this is how the system
works.. or use a different system. (Octal maybe.) If you are
perpetually confused by Python, you need to either learn how Python
works, or use something else.


What is the purpose of the language, to make things easier for people or 
what? And who is it for?


In other forums I've frequently recommended Python as an easy to learn 
language with a rapid development cycle. That was before I knew it had 
nearly as many quirks and gotchas as C!


That was in preference to other choices which I found difficult and also 
elitist because of the advanced knowledge of CS and mathematics that it 
seemed you were expected to know. (Eg Lisp, which has at least 4 
different ways of comparing for equality. Python only has two that I 
know of. A simple language would have only one, although my own has 
recently graduated from one to two; it's no longer simple!)


One gotcha at least is well known. Where, in a language of the least 
surprises, you might write:


 d1 = date (25,12,2010)
 d2 = d1
 d2.year += 1

You would expect d1 and d2 to represent a period one year apart. In 
Python, they would both be the later date.


OK, so both names are bound to the same object-value. So then you try this:

a = 10
b = a
b += 1

'+=' is an 'in-place add', so you might expect different semantics from 
'b = b+1'. But no, a isn't changed (disappointingly!).


Then, from the point of view of a beginner, you have two distinct ways 
of representing a list of objects: a tuple and a list. Exactly why there 
have to be two is never really made clear beyond the inadequate 
explanation that one is immutable and the other mutable.


OK, but now I have to continuously think about whether this 
multiple-set-of-objects is going to be a tuple or a list, or something 
else entirely (my date example above I think needs to be a class in 
Python, so that's a third way of doing things. Plus there is something 
called a 'set' that I haven't played with yet).


> or use something else.

Python isn't as bad as some languages, but it's well on the way. But is 
there anything simpler around that is also well-supported?


--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Steven D'Aprano
On Wed, 25 Nov 2015 07:43 pm, Marko Rauhamaa wrote:

> One psychological problem I'm seeing in many answers here is that people
> seem to want to defend the honor of Python. 

No, your other honour!


(It's an Oglaf reference, and *definitely* not safe for work. I'm not even
going to link to it.)



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Antoon Pardon
Op 25-11-15 om 11:52 schreef Steven D'Aprano:
> On Wed, 25 Nov 2015 07:14 pm, Antoon Pardon wrote:
>
>> Op 20-11-15 om 01:33 schreef Steven D'Aprano:
>>> On Fri, 20 Nov 2015 07:57 am, Marko Rauhamaa wrote:
>>>
 Laura Creighton :

> My experience says that the people who are confused want lists to
> behave like tuples. period. i.e. they don't want lists to be mutable.
 I think it's simpler than that. When you have:

def f(x=[]):
y = []

 the first [] is evaluated when "def" is executed, while the latter [] is
 evaluated whenever "f" is executed. It's easy to be confused.
>>> It shouldn't be. The function declaration
>>>
>>> def f(x=[]):
>>>
>>> is executed only once. The function body, conveniently indented to make
>>> it stand out:
>>>
>>> y = []
>>>
>>> is executed every time you call the function.
>> What exactly is your point? 
> That there is a simple analogy between the distinction between code
> inside/outside a for-loop, and code inside/outside a function. If you can
> understand why this loops forever, instead of just twice, then you can
> understand why function defaults work the way they do:
>
> L = [1, 2]
> for i in L:
> L.append(i)
> print(L)
>
>
> There is nothing "bizarre" or complicated or difficult to understand
> happening here. It might not be what you want to happen. It might not be
> what you expect to happen. But if you can't understand why it happens even
> after multiple explanations, then your learning skills are severely
> lacking.

You shouldn't equate that what you understand with what is not bizarre
complicated or difficult.

I think there are reasons to find the above behaviour bizarre. I personnaly
don't find it bizarre, but that is because I'm familiar with what is going
on. But if someone expects the compilor to take a snapshot of L and iterate
over that I am not going to say he shouldn't have expected that.

And IMO each time you proclaim something nothing bizarre or complicated
or difficult you are not helping.

>> People's confusions don't disappear 
>> because you as an expert have a good understanding of what is
>> going on and so are no longer confused.
> I'm an expert? Awesome!
>
> No. But people's confusion would disappear if they would:
>
> - think about the process
> - try to follow the steps of what is happening
> - pay attention to the explanations given
> - and ask for clarification instead of arguing.

People would be more inclined to do so, if there wasn't someone
claiming there was nothing bizarre or complicated or difficult
going on. Telling the above is implying those steps are not
needed because it is obvious what is happening. And if you
don't want people arguing, don't start yourself. Because my
impression of what is most likely to happen when someone says
something like: That is bizarre, is that the regulars here
are the ones that start arguing about it not being bizarre
and then they are annoyed that the other is arguing too.

> I have come to the conclusion that there is nobody as stupid as an
> intelligent person who refuses to learn.

Sure but that works just as much for the regulars here, who despite
that some subjects keep confusing people new to the language, keep
repeating that there is nothing bizarre, complicated or difficult
going on.

>> Some aspects in the langauage are easily grasped and other
>> aspects tend to create confusion. 
> You're right. Some aspects of the language are inherently confusing and hard
> to reason about. Threads are an example of that. The more powerful, and
> tricky, aspects of regular expressions. The weird stuff that happens during
> interpreter shutdown if you have __del__ methods in your objects. __del__
> methods in general. There are many things which are hard to reason about,
> and therefore confusing.
>
> *This is not one of them.*

Please stop using your personal evaluation as if it is some kind of
objective measure. The number of people that seem to get confused by
this, contradicts your claim.

> But is it predictable or intuitive? No, I agree, this behaviour is not
> intuitive, if you are coming from a background without equivalent rules. I
> will completely grant you that most people without Python experience would
> not correctly predict the behaviour of mutable defaults.
>
> I was caught out on that too, as I already admitted. Even though I already
> knew all the facts I needed to predict the behaviour correctly, I didn't
> put 2+2 together and get 4. That's *my bad*, not the language's fault.

Why not? People are not perfect rational thinking machines. And expecting
them to act like ones in order to get the language out of the wind, is
a rather weak argument IMO.

> How much harder must it be for those who don't know the essential facts? I
> don't expect anyone to intuit the behaviour of Python defaults. That would
> be unreasonable. There's no shame in guessing wrong from a position of
> ignorance.
>
> Me, 

Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Chris Angelico
On Thu, Nov 26, 2015 at 12:06 AM, Marko Rauhamaa  wrote:
> However, tuples are a way to represent records, groupings of related
> values, where the semantics of each value is determined by its position
> in the tuple. The members in a tuple are typically of different data
> types.
>
> Lists are collections of values. Typically, each member of list is of
> the same type.

This is a distinction I generally make. Putting it another way: a list
has the same meaning regardless of how many items are on it (for
instance, a shopping list is still a shopping list whether it has five
or fifty items on it), where a tuple is a package where each element
has a specific meaning (such as Cartesian coordinates; the difference
between the position (2,3) and the position (2,3,4) is not just that
there's "more position" in the second one - it's a drastically
different beast, living in three dimensions instead of two).

Nothing in the language enforces this, but the mutability of lists
does tend to align well with things that can grow and shrink, and the
immutability of tuples makes them more like strings or complex numbers
(in fact, a complex number is basically a tuple of two floats).

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Marko Rauhamaa
BartC :

> That was in preference to other choices which I found difficult and
> also elitist because of the advanced knowledge of CS and mathematics
> that it seemed you were expected to know.

Python is not a toy. It is a tool for advanced programmers.

Mathematics has barely any touching point, but yes, solid CS fluency is
required to be a productive software developer regardless of the
programming language.

Is a plumber an elitist, when he prefers to use tools I wouldn't know
how to operate?

> One gotcha at least is well known. Where, in a language of the least
> surprises, you might write:
>
>  d1 = date (25,12,2010)
>  d2 = d1
>  d2.year += 1
>
> You would expect d1 and d2 to represent a period one year apart. In
> Python, they would both be the later date.

No elitism or expertise would help you "expect" any outcome. I wouldn't
even expect d2 to have a field called "year". That's why you read the
specification.

> Then, from the point of view of a beginner, you have two distinct ways
> of representing a list of objects: a tuple and a list. Exactly why
> there have to be two is never really made clear beyond the inadequate
> explanation that one is immutable and the other mutable.

>From a functional point of view, there don't have to be two separate
concepts. The immutability of tuples is also just a design choice.

However, tuples are a way to represent records, groupings of related
values, where the semantics of each value is determined by its position
in the tuple. The members in a tuple are typically of different data
types.

Lists are collections of values. Typically, each member of list is of
the same type.

Tuples are handy because they allow you to treat multiple values as a
single value. Also, they are syntactically analogous to tuples in
mathematics so chances are you have encountered them in elementary
school. Finally, they are similar to function arguments, allowing you to
return multiple values the same way you pass multiple values to the
function.

> Python isn't as bad as some languages, but it's well on the way. But
> is there anything simpler around that is also well-supported?

My "simpler" is different from your "simpler". Even C# has a lot of
advanced concepts, as maybe even Fortran does nowadays.

My own recommendation would be Scheme, but it is even more "elitist"
than Python.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Chris Angelico
On Wed, Nov 25, 2015 at 11:25 PM, Antoon Pardon
 wrote:
>> But there's a big difference between those who guess wrong from a position
>> of ignorance, and then make an honest attempt to understand the behaviour
>> and why it actually does make sense and is even sometimes useful (even if
>> they don't like it), and those people who insist that it is nonsensical,
>> magical and "bizarre".
>
> There is an equally big difference between trying to explain what is going
> on and insisting that what is going on is not bizarre.

There is also a big difference between finding that something doesn't
match your expectations and declaring that it is "bizarre", which
implies that it makes no sense *to anyone*. What we've been pointing
out to you is that Python's way *does* make sense - just a different
sense from the one you're expecting.

There are many design decisions in programming languages. I've used
languages that have myriad keywords, multiple levels of keywords (SQL
is a shocking mess in that area), or no keywords at all (in REXX, you
can legally write "if if then then; else else", and it interprets
three of those as structure-defining and three as identifiers). I've
used languages where everything's a statement, even basic arithmetic.
Some languages make you declare your local variables, while others
have you declare your globals instead. These are all viable choices,
and they all make sense. The languages are internally coherent. I
would not call any of them "bizarre", with the possible exception of
DeScribe Macro Language, and even that's not too hard to get your head
around. (I wouldn't want to use it for any sort of general
programming, though. Its sole value is manipulating the DeScribe Word
Processor, and if you were to use it for something else, you'd have to
expand the language lexicon. There's no system of extensibility.)

Expanding on one of those examples, here are three ways that you can
distinguish between local/nonlocal/global variables/names/etc:

/* C++: Declare everything at a specific scope. */
int global_variable = 1;

struct outer_scope
{
int instance_variable;
void inner_scope()
{
int local_variable = 3;
}
};

/* PHP: Declare your globals, otherwise they're local. */
$global_variable = 1;
function outer_function()
{
global $global_variable;
$local_variable = 2;
/* I don't trust PHP's nested functions. */
}

# Python: Declare any globals you want to rebind.
global_name = 1
def outer_function():
nonlocal_name = 2
def inner_function():
global global_name
local_name = 3

There are variations on these, too (like ECMAScript's "declare and
it's function local, else it's an attribute of the global object").
Anyway. Point is, each of these systems is internally consistent, and
in each one, you can explain in a single sentence what the rule is.
Not one of these is bizarre, but I do completely understand that
anyone who has experience with just one of them _would_ find either of
the others confusing at first. "Wait, why do you need to declare this
as global, but not that?" "You're not assigning to that one, so you
don't need to declare it."

If you want to call Python's system "bizarre", you have to show more
than just that your expectations weren't matched by the language. You
have to show that Python lacks internal sense or consistency. You
have, so far, not shown anything of the kind, ergo we are continuing
to insist that Python is NOT bizarre.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 25/11/2015 10:52, Steven D'Aprano wrote:

On Wed, 25 Nov 2015 07:14 pm, Antoon Pardon wrote:



What exactly is your point?


That there is a simple analogy between the distinction between code
inside/outside a for-loop, and code inside/outside a function. If you can
understand why this loops forever, instead of just twice, then you can
understand why function defaults work the way they do:

L = [1, 2]
for i in L:
 L.append(i)
 print(L)


There is nothing "bizarre" or complicated or difficult to understand
happening here.


What do you think most people would expect to happen here? I know, 
because you gave a spoiler, that it loops forever, otherwise I wouldn't 
be sure /without trying it/ (but I tried it anyway).


Here's the same code in a somewhat different language:

L := (1,2)
for i in L do
|   L append:= i
|   println L
od

And this is the output:

(1,2,1)
(1,2,1,2)

Which output (infinite series of [1,2,1,2,1,] or the above) is more 
sensible, and which do you think people might prefer?


The point is that the behaviour of the loop is by no means obvious, so 
neither is the behaviour of the function defaults.



It might not be what you want to happen. It might not be
what you expect to happen. But if you can't understand why it happens even
after multiple explanations, then your learning skills are severely
lacking.


Accept that some things /are/ a source of confusion. When, in writing 
documentation, I find something hard to explain something, then I try 
and make it simpler in the program. But not enough of that goes on: it 
seems to be more lucrative to write thicker user manuals, and provide 
longer training courses, than to make software simpler.



I really don't know how more clear we can possibly be. If you take a list,
initialised as the empty list ONCE, and then modify it repeatedly, the list
doesn't magically become empty just because you want it to be empty.


Sure. The problem is that it might not be obvious it's initialised once.


I completely understand beginners making this mistake:

# Simulate tossing a coin until it is heads.
count = 1
coin = random.choice(['heads', 'tails'])
while coin != 'heads':
 count += 1

"Why does the loop run forever?"

The coin doesn't magically toss itself, no matter how intuitively obvious it
is that it should.


The concept of variables doesn't take long to learn in an 'ordinary' 
language.


But one problem with Python is that it gives the impression that almost 
anything is possible. Your example can be made to work with a slight tweak:


 count = 1
 coin = lambda: random.choice(['heads', 'tails'])
 while coin() != 'heads':
  count += 1

In some languages, there would never be such a possibility because they 
don't have the extraordinary flexibility and dynamism of Python. But 
once you get the idea that the language can almost do magic, then it 
doesn't seem so far-fetched that you original example could work!



Just like functions. If you want code to run each time you call the
function, PUT IT INSIDE THE FUNCTION BODY.


Many languages don't have the concept of code running outside a function 
body. And especially they don't have the truly bizarre one that a 
function definition is itself a piece of code that is executed. Or maybe 
not executed, if it's inside a conditional statement! And therefore does 
not exist. This is an extra hurdle with learning or even using this 
language.


--
bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Chris Angelico
On Wed, Nov 25, 2015 at 11:35 PM, BartC  wrote:
> One gotcha at least is well known. Where, in a language of the least
> surprises, you might write:
>
>  d1 = date (25,12,2010)
>  d2 = d1
>  d2.year += 1
>
> You would expect d1 and d2 to represent a period one year apart. In Python,
> they would both be the later date.

I'm not sure why this is "a language of least surprises". It's just a
language of *different* surprises. I'll give you an example of exactly
that: PHP has semantics similar to what you're describing.

$ php
 foo
[1] => bar
)

I'm not exactly sure of the definition of PHP's assignment, as it's
been a while since I looked it up; but it seems to be something like
what you're describing. This seems well and good, until you start
contemplating gigantic arrays and what happens when you pass them from
one function to another. What're your performance expectations? With
Python, I know that "a = b" happens in constant time, and I also know
that the performance of "a[1]=2" is not going to be affected by any
other names that might be bound to the same object. PHP's references
make this even more messy:

$ php
 foo
[1] => baz
)

So... since I'd previously set $b to be a reference, now assigning to
it does something different. And what, exactly? Is $a[1] the exact
same array as $a? Has any copying happened? When I change $b[1], is
that the same as changing $a[1], or is it actually changing $a[1][1],
and is that even any different?

This isn't a magical solution to all surprises, except perhaps in that
you've built a language yourself, so it conforms perfectly to *your*
expectations. You can never make something that fits everyone's
expectations, so you'll always have surprises somewhere. It's just a
question of where, and how easily they can be explained when someone
runs into them.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 25/11/2015 13:06, Marko Rauhamaa wrote:

BartC :



Then, from the point of view of a beginner, you have two distinct ways
of representing a list of objects: a tuple and a list. Exactly why
there have to be two is never really made clear beyond the inadequate
explanation that one is immutable and the other mutable.



However, tuples are a way to represent records, groupings of related
values, where the semantics of each value is determined by its position
in the tuple. The members in a tuple are typically of different data
types.


Using tuples in the same way that other languages implement records is 
going to be difficult if you can't change the values of the fields!



My "simpler" is different from your "simpler". Even C# has a lot of
advanced concepts, as maybe even Fortran does nowadays.

My own recommendation would be Scheme, but it is even more "elitist"
than Python.


OK, Lisp. (I can't actually tell the difference.)

--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Marko Rauhamaa
BartC :

> Using tuples in the same way that other languages implement records is
> going to be difficult if you can't change the values of the fields!

Guido could decide tomorrow that tuples are mutable. The decision is
more or less arbitrary, and has to do with dictionary keys, I bet (not a
particularly good reason).

Anyway, Python has two ways to represent records: classes and tuples.
Tuples are nice because they are concise and ad hoc. Often you start
with a scalar value, then turn it into a tuple. After a while your handy
tuple turns out a bit cumbersome to use so you convert it into an actual
class.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


What does a list comprehension do (was: Late-binding of function defaults (was Re: What is a function parameter =[] for?))

2015-11-25 Thread Antoon Pardon
Op 20-11-15 om 08:49 schreef dieter:
> In addition, the last few days have had two discussions in this list
> demonstrating the conceptial difficulties of late binding -- one of them:
>
>   Why does "[lambda x: i * x for i in range(4)]" gives
>   a list of essentially the same functions?

Can you (or someone else) explain what a list comprehension is equivallent of.
Especially in python3.

Take this simple list comprhesion:

[x * x for x in range(10)]

what would this be equivallent of? Something like:

def lch1():
  ls = []
  for x in range(10):
ls.append(x * x)
  return ls

Or more something like:

def lch2():
  def expr(x):
return x * x

  ls = []
  for x in range(10):
ls.append(expr(x))
  return ls

For this example it doesn't make a difference but for the example above
it would become important.

def lch3():
  ls = []
  for i in range(4):
ls.append(lambda x: i * x)
  return ls

versus

def lch4():
  def expr(i):
return lambda x: i * x

  ls = []
  for i in range(4)
ls.append(expr(i))
  return ls

Now from the result we get I expect list comprehensions to work more
like lch1 and lch3 rather than lch2 and lch4. But I can understand
people who think of the expression as a function of the variable that
is iterated over.

Am I missing something? Would it be worthwile considering changing
this behaviour?

-- 
Antoon.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Antoon Pardon
Op 25-11-15 om 14:24 schreef Chris Angelico:
> On Wed, Nov 25, 2015 at 11:25 PM, Antoon Pardon
>  wrote:
>>> But there's a big difference between those who guess wrong from a position
>>> of ignorance, and then make an honest attempt to understand the behaviour
>>> and why it actually does make sense and is even sometimes useful (even if
>>> they don't like it), and those people who insist that it is nonsensical,
>>> magical and "bizarre".
>> There is an equally big difference between trying to explain what is going
>> on and insisting that what is going on is not bizarre.
> There is also a big difference between finding that something doesn't
> match your expectations and declaring that it is "bizarre", which
> implies that it makes no sense *to anyone*. What we've been pointing
> out to you is that Python's way *does* make sense - just a different
> sense from the one you're expecting.

I find the above a very defensive attitude. People are mostly not
very accurate in how they put things into words. People tend to
say that something was delicious instead of saying that they
found it delicious. So when someone declares as aspect of python
to be bizarre I interpret that as an indication of what impression
that aspect made on that person instead of some declaration of fact.
So stop feeling attacked because someone found something bizarre.

You also seem to think that bizarre contradicts making sense. It
is entirly possible to understand what is going on and still find
it bizarre that the designers allowed for certain kinds or result.

> If you want to call Python's system "bizarre", you have to show more
> than just that your expectations weren't matched by the language. You
> have to show that Python lacks internal sense or consistency. You
> have, so far, not shown anything of the kind, ergo we are continuing
> to insist that Python is NOT bizarre.

No I don't have to show any such thing. There are things with an internal
sense of consistency that can be found utterly bizarre. I also find it
telling that you go from me talking about someone thinking that what is
going on in a specific aspect of python being bizarre, to regarding 
such a person as calling Python's system "bizarre", as if judging one
aspect is like judging the whole system. 

-- 
Antoon.


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread BartC

On 25/11/2015 13:53, Marko Rauhamaa wrote:

BartC :


Using tuples in the same way that other languages implement records is
going to be difficult if you can't change the values of the fields!


Guido could decide tomorrow that tuples are mutable.


(Could that be done without breaking existing code? And what then would 
be the difference between them and lists?)



Anyway, Python has two ways to represent records: classes and tuples.
Tuples are nice because they are concise and ad hoc. Often you start
with a scalar value, then turn it into a tuple. After a while your handy
tuple turns out a bit cumbersome to use so you convert it into an actual
class.


This is how records are handled in another language which I believe is 
simpler than Python: http://pastebin.com/vhsJML8U


This also implements my example from earlier in the thread. Now compare 
with Python's approach.


OK, that also needs two concepts, a list, and a record. But the 
distinction is now completely obvious. Records are also mutable. It 
would also be clear why you can't append to a record.


Now try explaining again to me how you would use tuples for the same 
thing...


--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Semantics of collection types (was: Late-binding of function defaults (was Re: What is a function parameter =[] for?))

2015-11-25 Thread Ben Finney
Ian Kelly  writes:

> On Wed, Nov 25, 2015 at 5:52 PM, Random832  wrote:
> > On 2015-11-25, Ben Finney  wrote:
> >> That is, the ‘2’ in ‘cartesian_point = (2, 3)’ means something
> >> different than in ‘cartesian_point = (3, 2)’.
> >>
> >> Whereas the ‘2’ in ‘test_scores = [2, 3]’ means exactly the same as
> >> in ‘test_scores = [3, 2]’.
> >>
> >> If each position in the sequence gives the value there a different
> >> menaning, use a tuple; if not, use a list.
> >
> > I don't think that's really right.

I was expanding on (by replying to) earlier advice about expressing
semantics in our choice of data types.

> > The difference between a tuple and a list is that one is mutable
> > and the other is not.

That is a difference enforced in the behaviour of the types, yes.

I didn't talk about behaviour, but about meaning. I'm saying that the
behavioural difference conveniently lines up with a semantic difference,
even to the point of the meaning of “tuple” that pre-dates Python.

> I think that Ben was actually trying to make a distinction between
> heterogeneity and homogeneity of the contents, not a distinction of
> whether the collection was ordered or not.

That's right, thank you.

-- 
 \   “Nothing exists except atoms and empty space; everything else |
  `\is opinion.” —Democritus, c. 460 BCE – 370 BCE |
_o__)  |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-25 Thread Ben Finney
Ned Batchelder  writes:

> For someone who claims to be interested in language design, you're
> remarkably dismissive of pretty much the entire industry. I don't
> think it's worth the effort to try to change your mind.

+1.

BartC, when you want to join us in discussions on good faith – that is,
honestly wanting to learn Python rather than dogmatically persisting in
your misperceptions dogmatically onto it – we'll still be here, making
happy use of Python the way it is.

-- 
 \   “Facts are meaningless. You could use facts to prove anything |
  `\that's even remotely true!” —Homer, _The Simpsons_ |
_o__)  |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-23 Thread Chris Angelico
On Fri, Nov 20, 2015 at 6:46 AM, Chris Angelico  wrote:
> The expressions would be evaluated as closures, using the same scope
> that the function's own definition used. (This won't keep things alive
> unnecessarily, as the function's body will be nested within that same
> scope anyway.) Bikeshed the syntax all you like, but this would be
> something to point people to: "here's how to get late-binding
> semantics". For the purposes of documentation, the exact text of the
> parameter definition could be retained, and like docstrings, they
> could be discarded in -OO mode.

Just out of interest, I had a shot at implementing this with a
decorator. Here's the code:

# -- cut --

import functools
import time

class lb:
def __repr__(self): return ""

def latearg(f):
tot_args = f.__code__.co_argcount
min_args = tot_args - len(f.__defaults__)
defs = f.__defaults__
# With compiler help, we could get the original text as well as something
# executable that works in the correct scope. Without compiler help, we
# either use a lambda function, or an exec/eval monstrosity that can't use
# the scope of its notional definition (since its *actual* definition will
# be inside this decorator). Instead, just show a fixed bit of text.
f.__defaults__ = tuple(lb() if callable(arg) else arg for arg in defs)
@functools.wraps(f)
def inner(*a,**kw):
if len(a) < min_args: return f(*a, **kw) # Will trigger TypeError
if len(a) < tot_args:
more_args = defs[len(a)-tot_args:]
a += tuple(arg() if callable(arg) else arg for arg in more_args)
return f(*a,**kw)
return inner

def sleeper(tm):
"""An expensive function."""
t = time.monotonic()
time.sleep(tm)
return time.monotonic() - t - tm

seen_args = []
@latearg
def foo(spam, ham=lambda: [], val=lambda: sleeper(0.5)):
print("%s: Ham %X with sleeper %s" % (spam, id(ham), val))
seen_args.append(ham) # Keep all ham objects alive so IDs are unique

@latearg
def x(y=lambda: []):
y.append(1)
return y

print("Starting!")
foo("one-arg 1")
foo("one-arg 2")
foo("two-arg 1", [])
foo("two-arg 2", [])
foo("tri-arg 1", [], 0.0)
foo("tri-arg 2", [], 0.0)
print(x())
print(x())
print(x())
print(x([2]))
print(x([3]))
print(x([4]))
print("Done!")

# -- cut --


This does implement late binding, but:
1) The adornment is the rather verbose "lambda:", where I'd much
rather have something shorter
2) Since there's no way to recognize "the ones that were adorned", the
decorator checks for "anything callable"
3) Keyword args aren't handled - they're passed through as-is (and
keyword-only arg defaults aren't rendered)
4) As commented, the help text can't pick up the text of the function

But it does manage to render args at execution time, and the help()
for the function identifies the individual arguments correctly (thanks
to functools.wraps and the modified defaults - though this
implementation is a little unfriendly, mangling the original function
defaults instead of properly wrapping).

Clock this one up as "useless code that was fun to write".

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-23 Thread Chris Angelico
On Tue, Nov 24, 2015 at 3:40 AM, Ian Kelly  wrote:
> On Mon, Nov 23, 2015 at 1:23 AM, Chris Angelico  wrote:
>> def latearg(f):
>> tot_args = f.__code__.co_argcount
>> min_args = tot_args - len(f.__defaults__)
>> defs = f.__defaults__
>> # With compiler help, we could get the original text as well as something
>> # executable that works in the correct scope. Without compiler help, we
>> # either use a lambda function, or an exec/eval monstrosity that can't 
>> use
>> # the scope of its notional definition (since its *actual* definition 
>> will
>> # be inside this decorator). Instead, just show a fixed bit of text.
>
> You should be able to get the correct globals from f.__globals__.
>
> For locals, the decorator might capture the locals of the previous
> stack frame at the moment the decorator was called, but that's
> potentially a pretty heavy thing to be retaining for this purpose; the
> definition of a @latearg function would indefinitely keep a reference
> to every single object that was bound to a variable in that scope, not
> just the things it needs. For better specificity you could parse the
> expression and then just grab the names that it uses. Even so, this
> would still act somewhat like early binding in that it would reference
> the local variables at the time of definition rather than evaluation.
>
> Nonlocals? Just forget about it.

And since nonlocals are fundamentally unsolvable, I took the simpler
option and just used an actual lambda function.

>> This does implement late binding, but:
>> 1) The adornment is the rather verbose "lambda:", where I'd much
>> rather have something shorter
>> 2) Since there's no way to recognize "the ones that were adorned", the
>> decorator checks for "anything callable"
>
> A parameter annotation could be used in conjunction with the decorator.
>
> @latearg
> def x(y: latearg = lambda: []):
> ...
>
> But that's even more verbose. In the simple case where all the
> defaults should be late, one could have something like:
>
> @latearg('*')
> def x(y=lambda: []):
> ...
>
> The argument could be generalized to pass a set of parameter names as
> an alternative to the annotation.

Yeah, that might help. With real compiler support, both of these could
be solved:

def x(y=>[]):
...

The displayed default could be "=>[]", exactly the way it's seen in
the source, and the run-time would know exactly which args were
flagged this way. Plus, it could potentially use a single closure to
evaluate all the arguments.

>> 3) Keyword args aren't handled - they're passed through as-is (and
>> keyword-only arg defaults aren't rendered)
>
> I would expect that Python 3 Signature objects would make this a lot
> simpler to handle.

Maybe. It's still going to be pretty complicated. I could easily
handle keyword-only arguments, but recognizing that something in **kw
is replacing something in *a is a bit harder. Expansion invited.

This is reminiscent of the manual "yield from" implementation in PEP
380. It looks simple enough, until you start writing in all the corner
cases.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-23 Thread Ian Kelly
On Mon, Nov 23, 2015 at 1:23 AM, Chris Angelico  wrote:
> def latearg(f):
> tot_args = f.__code__.co_argcount
> min_args = tot_args - len(f.__defaults__)
> defs = f.__defaults__
> # With compiler help, we could get the original text as well as something
> # executable that works in the correct scope. Without compiler help, we
> # either use a lambda function, or an exec/eval monstrosity that can't use
> # the scope of its notional definition (since its *actual* definition will
> # be inside this decorator). Instead, just show a fixed bit of text.

You should be able to get the correct globals from f.__globals__.

For locals, the decorator might capture the locals of the previous
stack frame at the moment the decorator was called, but that's
potentially a pretty heavy thing to be retaining for this purpose; the
definition of a @latearg function would indefinitely keep a reference
to every single object that was bound to a variable in that scope, not
just the things it needs. For better specificity you could parse the
expression and then just grab the names that it uses. Even so, this
would still act somewhat like early binding in that it would reference
the local variables at the time of definition rather than evaluation.

Nonlocals? Just forget about it.

> This does implement late binding, but:
> 1) The adornment is the rather verbose "lambda:", where I'd much
> rather have something shorter
> 2) Since there's no way to recognize "the ones that were adorned", the
> decorator checks for "anything callable"

A parameter annotation could be used in conjunction with the decorator.

@latearg
def x(y: latearg = lambda: []):
...

But that's even more verbose. In the simple case where all the
defaults should be late, one could have something like:

@latearg('*')
def x(y=lambda: []):
...

The argument could be generalized to pass a set of parameter names as
an alternative to the annotation.

> 3) Keyword args aren't handled - they're passed through as-is (and
> keyword-only arg defaults aren't rendered)

I would expect that Python 3 Signature objects would make this a lot
simpler to handle.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-21 Thread Ian Kelly
On Sat, Nov 21, 2015 at 1:46 AM, Chris Angelico  wrote:
> On Sat, Nov 21, 2015 at 7:38 PM, Todd  wrote:
>> Rather than a dedicated syntax, might this be something that could be
>> handled by a built-in decorator?
>>
>> Maybe something like:
>>
>> @late_binding
>> def myfunc(x, y=[]):
>
> No, it can't; by the time the decorator runs, the expression has
> already been evaluated. Without syntax, this can only be done with
> gross hacks like lambda functions.
>
> It could be done thus:
>
> @late_binding
> def myfunc(x, y=lambda: []):
>
> and then the decorator could wrap the function. I'm not entirely sure
> I could implement it reliably, but even leaving that aside, having to
> put "lambda:" in front of everything is pretty ugly.

Note that "lambda: []" can also be spelled "list".
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-21 Thread Chris Angelico
On Sun, Nov 22, 2015 at 2:01 AM, Ian Kelly  wrote:
>> and then the decorator could wrap the function. I'm not entirely sure
>> I could implement it reliably, but even leaving that aside, having to
>> put "lambda:" in front of everything is pretty ugly.
>
> Note that "lambda: []" can also be spelled "list".

In that particular example, yes. I kept it in the large form to
maintain the parallel with the version I was quoting. But if the
decorator were to be written, it would probably be something along the
lines of "if the default is callable, do the late-binding magic", so
'list' would work just fine.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-21 Thread Todd
On Nov 19, 2015 20:48, "Chris Angelico"  wrote:
>
> On Fri, Nov 20, 2015 at 5:42 AM, Ian Kelly  wrote:
> > BartC on the other hand is just complaining about an aspect of Python
> > that is legitimately controversial.
>
> IMO it's controversial mainly because there's an easy and obvious
> syntax for early binding, but late binding doesn't have syntactic
> support, and all the options are imperfect. Consider:
>
> def late1(x=None):
> """Terse but buggy"""
> do_stuff_with(x or [])
>
> def late2(x=None):
> """Not bad but has an extra line for each default. Also, can't take
None."""
> if x is None: x = []
> do_stuff_with(x)
>
> _SENTINEL = object()
> def late3(x=_SENTINEL):
> """Has the same global-pollution problem you get when you
> try to construct early binding from late; you can share the
> sentinel among multiple args, even multiple funcs, though"""
> if x is _SENTINEL: x = []
> do_stuff_with(x)
>
> def late4(x=object()):
> """Depends on its own name remaining bound in its scope,
> and will break if you change argument order"""
> if x is late4.__defaults__[0]: x = []
> do_stuff_with(x)
>
> And there might be other techniques, too. They all share one important
> flaw, too: When you ask for help about the function, you can't see
> what the default really is. All you see is:
>
> late1(x=None)
> late3(x=)
>
> In the first two cases, it's not too bad; you can specify a timeout as
> either a number or as None, and if it's None (the default), the
> timeout is three times the currently estimated round trip time. No
> problem. But how would you implement something like next() in pure
> Python? If you provide _any second argument at all_, it returns that
> instead of raising StopIteration. The ONLY way that I can think of is
> to use *args notation:
>
> def next(iterator, *default):
> try:
> return iterator.__next__()
> except StopIteration:
> if default: return default[0]
> raise
>
> And while that isn't TOO bad for just one argument, it scales poorly:
>
> def foo(fixed_arg, *args):
> """Foo the fixed_arg against the spam mapping, the
> ham sequence, and the jam file."""
> args.reverse()
> spam = args.pop() if args else {}
> ham = args.pop() if args else []
> jam = args.pop() if args else open("jam.txt")
>
> Suppose, instead, that Python had a syntax like this:
>
> def foo(fixed_arg, spam=>{}, ham=>[], jam=>open("jam.txt")):
> """Foo the fixed_arg against the spam mapping, the
> ham sequence, and the jam file."""
>
> The expressions would be evaluated as closures, using the same scope
> that the function's own definition used. (This won't keep things alive
> unnecessarily, as the function's body will be nested within that same
> scope anyway.) Bikeshed the syntax all you like, but this would be
> something to point people to: "here's how to get late-binding
> semantics". For the purposes of documentation, the exact text of the
> parameter definition could be retained, and like docstrings, they
> could be discarded in -OO mode.
>
> Would this satisfy the people who get confused about "=[]"?
>
> ChrisA

Rather than a dedicated syntax, might this be something that could be
handled by a built-in decorator?

Maybe something like:

@late_binding
def myfunc(x, y=[]):

@late_binding('z')
def myfunc(x, y=expensive(), z=[]):

M = 5
@late_binding('z', vars_early=True)
def myfunc(x, y=expensive(), z=list(range(n))):

The big advantage, as shown in the last example, is that it could be
possible to specify early our late binding for variables as well.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-21 Thread Chris Angelico
On Sat, Nov 21, 2015 at 7:38 PM, Todd  wrote:
> Rather than a dedicated syntax, might this be something that could be
> handled by a built-in decorator?
>
> Maybe something like:
>
> @late_binding
> def myfunc(x, y=[]):

No, it can't; by the time the decorator runs, the expression has
already been evaluated. Without syntax, this can only be done with
gross hacks like lambda functions.

It could be done thus:

@late_binding
def myfunc(x, y=lambda: []):

and then the decorator could wrap the function. I'm not entirely sure
I could implement it reliably, but even leaving that aside, having to
put "lambda:" in front of everything is pretty ugly.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-20 Thread BartC

On 19/11/2015 22:41, Laura Creighton wrote:

In a message of Thu, 19 Nov 2015 22:57:10 +0200, Marko Rauhamaa writes:



Note: Ned Bachelder (who is probably reading this on python-list
anyway added cc on this mail, as if I am to discuss somebody, however
briefly, they deserve to hear about it.  Which may irritate him to
get 2 copies instead of one, but so it goes.  I am talking about
BartC as well, but since this is his thread, I assume he is here.)


Actually that thread was started by 'fl'.


Sometimes you want to understand what you are doing.  Sometimes
you just want to do it.  And sometimes, well, the only real way
to get an understanding of what you are doing is to do it more.
This is, in my opinion, Bartc's problem. He doesn't program in
python enough to understand it more.


That's true. I'll have to do a substantial project soon. But a lot of my 
interest is about comparisons between Python and the languages I work on.


(Especially of speed. Up to now my interpreters have been comfortably 
faster. But with PyPy I might now have do do a bit more work on mine 
next year. This is where a proper application is needed for comparison 
and not small benchmarks.)


I'm also interested in what handy features I can 'borrow' from Python. 
Enough that I was planning a big upgrade earlier this year to bring it 
more into line with how Python works. (/That/ is a good way of learning 
about a language! To try and implement a lookalike.)


But that was changing my language too much (I was losing too many 
features of my own) so it was abandoned. (Perhaps it can be a separate, 
higher level language at some point as I quite like the Python style 
even if I have misgivings about some features.)



They have the opposite problem of BartC -- they want to be excellent
programmers without understanding anything, while he wants to
understand everything before he knows how to write decent python code.


I can already tell you that I will never be able to write 'Pythonic' 
code if that is what you mean by 'decent'. But at least everyone will be 
able to understand it!


--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-20 Thread Jussi Piitulainen
dieter writes:
> Chris Angelico writes:
>
>> IMO it's controversial mainly because there's an easy and obvious
>> syntax for early binding, but late binding doesn't have syntactic
>> support, and all the options are imperfect.
>
> I do not think that we should get additional syntax for lately bound
> default values. It would explicitely introduce the concepts early
> versus late binding which are likely difficult to understand by many
> users.

I'm confused by the term. I don't like it one bit.

"Early binding" of a default value seems to mean that the expression
that produces the default value of a function parameter is evaluated
when the function is defined. "Late binding" seems to mean that the
expression is evaluated when the function is called.

In both cases the actual binding of the parameter to the value (either
the default or an actual argument) is established when the function is
called. Several different bindings of that same parameter to different
values can hold simultaneously, so the *binding* has to be conceptually
"late". Because recursion.

Why isn't the evaluation of the default expression called evaluation?
Or at least something that doesn't already mean something else that is
as crucially important as, well, I've already given up on talking about
REDACTED and REDACTED in connection with Python, and here I see related
established terminology used for something else *for no reason that I
can see*.

I see no *need* to call this other thing "binding".
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-20 Thread dieter
Jussi Piitulainen  writes:
> dieter writes:
>> Chris Angelico writes:
>>
>>> IMO it's controversial mainly because there's an easy and obvious
>>> syntax for early binding, but late binding doesn't have syntactic
>>> support, and all the options are imperfect.
>>
>> I do not think that we should get additional syntax for lately bound
>> default values. It would explicitely introduce the concepts early
>> versus late binding which are likely difficult to understand by many
>> users.
>
> I'm confused by the term. I don't like it one bit.
>
> "Early binding" of a default value seems to mean that the expression
> that produces the default value of a function parameter is evaluated
> when the function is defined. "Late binding" seems to mean that the
> expression is evaluated when the function is called.
>
> In both cases the actual binding of the parameter to the value (either
> the default or an actual argument) is established when the function is
> called. Several different bindings of that same parameter to different
> values can hold simultaneously, so the *binding* has to be conceptually
> "late". Because recursion.

Conventionally, "binding" is the association of a "value" with a "name".

In this sense, you can call "early binding" the current Python behavior
with respect to default parameters: the expression is evaluated into
a "value" at function definition time and bound to the parameter name.
A later call may rebind the parameter name (if it provides its own value).

In the case of "late binding", the function definition would also
bind at function definition time the "name"
to something (but not a "value"): an expression,
maybe together with some binding. This expression would then
be evaluated at a later time (and we only then get the typical
binding of a "name" to a "value").


> Why isn't the evaluation of the default expression called evaluation?

I do not mind if you prefer to use the term "evaluation"
instead of "binding". Nothing important in my previous message
would be changed by the term exchange: you must specify how (and when)
the variables referenced in the expression get their values. And
this will give new difficulties - more serious than
Python's current handling of default parameters.


-- 
https://mail.python.org/mailman/listinfo/python-list


Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-19 Thread Chris Angelico
On Fri, Nov 20, 2015 at 5:42 AM, Ian Kelly  wrote:
> BartC on the other hand is just complaining about an aspect of Python
> that is legitimately controversial.

IMO it's controversial mainly because there's an easy and obvious
syntax for early binding, but late binding doesn't have syntactic
support, and all the options are imperfect. Consider:

def late1(x=None):
"""Terse but buggy"""
do_stuff_with(x or [])

def late2(x=None):
"""Not bad but has an extra line for each default. Also, can't take None."""
if x is None: x = []
do_stuff_with(x)

_SENTINEL = object()
def late3(x=_SENTINEL):
"""Has the same global-pollution problem you get when you
try to construct early binding from late; you can share the
sentinel among multiple args, even multiple funcs, though"""
if x is _SENTINEL: x = []
do_stuff_with(x)

def late4(x=object()):
"""Depends on its own name remaining bound in its scope,
and will break if you change argument order"""
if x is late4.__defaults__[0]: x = []
do_stuff_with(x)

And there might be other techniques, too. They all share one important
flaw, too: When you ask for help about the function, you can't see
what the default really is. All you see is:

late1(x=None)
late3(x=)

In the first two cases, it's not too bad; you can specify a timeout as
either a number or as None, and if it's None (the default), the
timeout is three times the currently estimated round trip time. No
problem. But how would you implement something like next() in pure
Python? If you provide _any second argument at all_, it returns that
instead of raising StopIteration. The ONLY way that I can think of is
to use *args notation:

def next(iterator, *default):
try:
return iterator.__next__()
except StopIteration:
if default: return default[0]
raise

And while that isn't TOO bad for just one argument, it scales poorly:

def foo(fixed_arg, *args):
"""Foo the fixed_arg against the spam mapping, the
ham sequence, and the jam file."""
args.reverse()
spam = args.pop() if args else {}
ham = args.pop() if args else []
jam = args.pop() if args else open("jam.txt")

Suppose, instead, that Python had a syntax like this:

def foo(fixed_arg, spam=>{}, ham=>[], jam=>open("jam.txt")):
"""Foo the fixed_arg against the spam mapping, the
ham sequence, and the jam file."""

The expressions would be evaluated as closures, using the same scope
that the function's own definition used. (This won't keep things alive
unnecessarily, as the function's body will be nested within that same
scope anyway.) Bikeshed the syntax all you like, but this would be
something to point people to: "here's how to get late-binding
semantics". For the purposes of documentation, the exact text of the
parameter definition could be retained, and like docstrings, they
could be discarded in -OO mode.

Would this satisfy the people who get confused about "=[]"?

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-19 Thread Steven D'Aprano
On Fri, 20 Nov 2015 07:57 am, Marko Rauhamaa wrote:

> Laura Creighton :
> 
>> My experience says that the people who are confused want lists to
>> behave like tuples. period. i.e. they don't want lists to be mutable.
> 
> I think it's simpler than that. When you have:
> 
>def f(x=[]):
>y = []
> 
> the first [] is evaluated when "def" is executed, while the latter [] is
> evaluated whenever "f" is executed. It's easy to be confused.

It shouldn't be. The function declaration 

def f(x=[]):

is executed only once. The function body, conveniently indented to make it
stand out:

y = []

is executed every time you call the function. 


[Aside: that nice clean design is somewhat muddied by docstrings. Despite
being indented, docstrings are actually part of the declaration in the
sense that they are handled only once, at function definition time.]


-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-19 Thread Marko Rauhamaa
Laura Creighton :

> My experience says that the people who are confused want lists to
> behave like tuples. period. i.e. they don't want lists to be mutable.

I think it's simpler than that. When you have:

   def f(x=[]):
   y = []

the first [] is evaluated when "def" is executed, while the latter [] is
evaluated whenever "f" is executed. It's easy to be confused.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-19 Thread Laura Creighton
In a message of Fri, 20 Nov 2015 06:46:42 +1100, Chris Angelico writes:

>Would this satisfy the people who get confused about "=[]"?
>
>ChrisA

My experience says that the people who are confused want lists to
behave like tuples.  period.  i.e. they don't want lists to be 
mutable.  Which means when I say 'use a tuple instead' they go
away happy. Lots of very occasional programmers in my world (children)
just use tuples instead of lists and never get surprises and 
never go on to learn about lists and why they are a good idea.

But then there are those who come back with the problem:
'my python program is too slow'.  From a perspective of
'Let us understand why this is so and what could we do to make
things faster', I can get them to come up with the idea of a 
python list all on their own.  But this requires the sort of
brain that is interested in how interpreters work, otherwise
this conversation will not happen.

Without the actual problem biting them, the whole idea of
mutable objects seems, ah, hazardous.  I wonder if we do people
a disservice by introducing them straight off in teaching python
to absolute beginners, and if the learning would go easier if
we taught tuples and made them all use them a while before we
gave them lists.

At any rate, 'what is a mutable object' is a conversation that I 
have had too many times with people who really aren't interested.
I now think that 'use a tuple instead' is the way to go, with the
addition -- come back and talk to me about this at any time if you
want to learn why this is so.

Laura

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-19 Thread Laura Creighton
In a message of Thu, 19 Nov 2015 22:57:10 +0200, Marko Rauhamaa writes:
>Laura Creighton :
>
>> My experience says that the people who are confused want lists to
>> behave like tuples. period. i.e. they don't want lists to be mutable.
>
>I think it's simpler than that. When you have:
>
>   def f(x=[]):
>   y = []
>
>the first [] is evaluated when "def" is executed, while the latter [] is
>evaluated whenever "f" is executed. It's easy to be confused.
>
>
>Marko

Note: Ned Bachelder (who is probably reading this on python-list
anyway added cc on this mail, as if I am to discuss somebody, however
briefly, they deserve to hear about it.  Which may irritate him to
get 2 copies instead of one, but so it goes.  I am talking about
BartC as well, but since this is his thread, I assume he is here.)

Now back to what Marko said:

This is one of the times when it is nice to be dealing with children.
The whole notion of 'when def is executed' is not on their radar
at all.  It is all a matter of 'I write this, I want that'. :)

And with reasonable amount of authority from experience, I can
tell you that 'write it with round brackets not square ones'
makes the code *just work* for a large number of students who
only have a limited amount of patience for 'understanding 
what they are doing'.  They want to be able to do it first,
and have understanding come later (if at all).

This is the learning approach of 'training' as opposed to
'educating'.  And, for all that we _talk_ of 'educating our
children' -- what we really do, a whole lot of the time, is
train them.  The very basic skills of reading, writing (typing?) 
and arithmetic and foreign languages  need to be trained, and no
amount of understanding the theory behind such things will
ever directly translate into being able to do it.

Indeed, the best authority on the planet on 13th century French court
dances is a one-legged Frenchman, (whose name I now forget).
Although he has (or maybe had, he is likely dead by now, he lost
his leg in WW2) the education and the theory and the scholasticism, 
anybody with 2 legs, however ignorant, can dance the court dances
better. 

Sometimes you want to understand what you are doing.  Sometimes
you just want to do it.  And sometimes, well, the only real way 
to get an understanding of what you are doing is to do it more.
This is, in my opinion, Bartc's problem. He doesn't program in
python enough to understand it more.  He wants us to give him
a better theoretical understanding of Python, but for me, at 
any rate he is hitting the wrong audience.  And Ned Batchelder
is unlikely to help.  Both of us come from the practical end
of things, and write lessons and talks like the one ChrisA
recommended -- which is wonderful.  And how I wish I could 
write like that -- but they are aimed at telling a practical
python programmer 'now that you know how to do it, here is how
to understand what you do'.  And then, pedagogically, you can 
move to 'and now you understand what you have been doing, here
are some awesome cool tricks you can do to make your life easier
(and impress your friends, for a particularly nerdy set of
freinds).

I don't think that Ned works for the untrained python programmer.
And until Bart writes a bunch of code in python, for many weeks
or even months, I will not be able to help him, either.

But in my life, I end up teaching programming, often to some very
smart young people who are specialists at being trained. They want me
to train them, not educate them.  When you are 9 years old,
approaching all of life with the attitude of 'how do I get 
to spit out the results I want' is enormously adaptive.

They have the opposite problem of BartC -- they want to be excellent
programmers without understanding anything, while he wants to 
understand everything before he knows how to write decent python code.

It's a pedagogical problem.

Laura
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?) (fwd)

2015-11-19 Thread Laura Creighton
Arrgh!

I got Ned Batchelder's email wrong.  Forgot the t.
(for somebody whose irc nick is nedbat.  )

sending this to him again.   warning any repliers that the
mail address is wrong

apologies,
Laura


--- Forwarded Message

From: Laura Creighton 
Subject: Re: Late-binding of function defaults (was Re: What is a function
 parameter =[] for?)
In-reply-to: <87d1v5emhl@elektro.pacujo.net>
References: 

Re: Late-binding of function defaults (was Re: What is a function parameter =[] for?)

2015-11-19 Thread dieter
Chris Angelico  writes:

> On Fri, Nov 20, 2015 at 5:42 AM, Ian Kelly  wrote:
>> BartC on the other hand is just complaining about an aspect of Python
>> that is legitimately controversial.
>
> IMO it's controversial mainly because there's an easy and obvious
> syntax for early binding, but late binding doesn't have syntactic
> support, and all the options are imperfect.

I do not think that we should get additional syntax for lately bound
default values. It would explicitely introduce the concepts
early versus late binding which are likely difficult to understand
by many users.

In addition, the last few days have had two discussions in this list
demonstrating the conceptial difficulties of late binding -- one of them:

  Why does "[lambda x: i * x for i in range(4)]" gives
  a list of essentially the same functions?


Note as well, that it is difficult to define what "late binding"
should mean in non-trivial cases:

   def f(..., a=)

   If "a" is lately bound, when are bound the variables involved
   in its defining expression?

   If they are early bound, you get the same effect as with realy
   bound default parameters: calling the function can change non local
   objects which may lead to surprises.

   If they are lately bound, the references may no longer be
   resolvable or (worse) may resolve to unexpected objects.


If you need late binding, you might use something like this:

   class Late(object):
 def __init__(self, obj): self.obj = obj
 def bind:
   from copy import deepcopy
   return deepcopy(obj)
 def __repr__: ...

   def f(..., a=Late()):
 ...
 a = a.bind()
 ...

Of course, you could define a decorator which performs the
"bind" calls automatically.




-- 
https://mail.python.org/mailman/listinfo/python-list