Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Steven D'Aprano
On Sun, 25 Feb 2018 21:19:19 -0800, Rick Johnson wrote:


> I agree with your sarcasm. And that's why these types of auto
> conversions should be optional. I agree that most times it's more
> practical to let python handle the dirty details. But in some cases,
> where you need to squeeze out a few more drops of speed juice, you won't
> mind the extra trouble.

And that's where you call out to a library like numpy, or write a C 
extension, or use a tool like Numba or Cython to optimise your Python 
code to use native ints. (Numba is still a work in progress, but Cython 
is a mature working product.)

Or to put it another way... if you want machine ints in Python, the way 
you get them is something like:

from numba import jit

@jit
def myfunction(): ...



The core language doesn't have to support these things when there is a 
healthy language ecosystem that can do it.


-- 
Steve

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


help me ?

2018-02-26 Thread sotaro237
Define 2 lists. The first one must contain the integer values 1, 2 and 3 and 
the second one the string values a, b and c. Iterate through both lists to 
create another list that contains all the combinations of the A and B elements. 
The final list should look like one of the 2 lists:
1. [1a, 1b, 1c, 2a, 2b, 2c, 3a, 3b, 3c]
2. [a1, a2. a3, b1, b2, b3, c1, c2, c3]
BONUS: Make the final list contain all possible combinations : [1a, a1, 1b, b1, 
1c, c1, 2a, a2, 2b, b2, 2c, c2, 3a, a3, 3b, b3, 3c, c3] 

Help me !
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: help me ?

2018-02-26 Thread Christian Gollwitzer

Am 26.02.18 um 10:40 schrieb sotaro...@gmail.com:

Define 2 lists. The first one must contain the integer values 1, 2 and 3 and 
the second one the string values a, b and c. Iterate through both lists to 
create another list that contains all the combinations of the A and B elements. 
The final list should look like one of the 2 lists:
1. [1a, 1b, 1c, 2a, 2b, 2c, 3a, 3b, 3c


Look up list comprehensions.

Christian

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Steven D'Aprano
On Sun, 25 Feb 2018 20:22:17 -0800, Rick Johnson wrote:

> So of course, speed is not and should not be the
> primary concern, but to say that execution speed is of _no_ concern is
> quite absurd indeed.

I'm pretty sure that nobody here has said that speed is of no concern.

Rather, I would argue that the position we're taking is that *in general* 
Python is fast enough for the sorts of tasks we use it for (except, of 
course, when it isn't, in which case you have our sympathy, and if we can 
suggest some solutions we will).

Of course we'd take speed optimizations if they were free, but they're 
never free:

- they often require more memory to run;

- they usually require more code, which adds to the maintenance burden
  and increases the interpreter bloat;

- and increases the risk of bugs;

- somebody has to write, debug, document and maintain the code, 
  and developer time and effort is in short supply;

- or the optimization requires changes to the way Python operates;

- even if we wanted to make that change, it will break backwards
  compatibility;

- and often what people imagine is a simple optimization (because
  they haven't tried it) isn't simple at all;

- or simply doesn't work;

- and most importantly, just saying "Make it go faster!" doesn't work,
  we actually need to care about the details of *how* to make it faster.

(We tried painting Go Faster stripes on the server, and it didn't work.)

There's no point suggesting such major changes to Python that requires 
going back to the drawing board, to Python 0.1 or earlier, and changing 
the entire execution and memory model of the language.

That would just mean we've swapped from a successful, solid, reliable 
version 3.6 of the language to an untried, unstable, unproven, bug-ridden 
version 0.1 of New Python.

And like New Coke, it won't attract new users (they're already using 
Javascript or Go or whatever...) and it will alienate existing users (if 
they wanted Javascript or Go they'd already be using it).

There have been at least two (maybe three) attempts to remove the GIL 
from CPython. They've all turned out to increase complexity by a huge 
amount, and not actually provide the hoped-for speed increase. Under many 
common scenarios, the GIL-less CPython actually ran *slower*.

(I say "hoped for", but it was more wishful thinking than a rational 
expectation that removing the GIL would speed things up. I don't believe 
any of the core developers were surprised that removing the GIL didn't 
increase speeds much, if at all, and sometimes slowed things down. The 
believe that the GIL slows Python down is mostly due to a really 
simplistic understanding of how threading works.)

Besides, if you want Python with no GIL so you can run threaded code, why 
aren't you using IronPython or Jython?

Another example: UnladenSwallow. That (mostly) failed to meet 
expectations because the compiler tool chain being used wasn't mature 
enough. If somebody were to re-do the project again now, the results 
might be different.

But it turns out that not that many people care enough to make Python 
faster to actually invest money in it. Everyone wants to just stamp their 
foot and get it for free.

(If it weren't for the EU government funding it, PyPy would probably be 
languishing in oblivion. Everyone wants a faster Python so long as they 
don't have to pay for it, or do the work.)

A third example: Victor Stinner's FatPython, which seemed really 
promising in theory, but turned out to not make enough progress fast 
enough and he lost interest.

I have mentioned FatPython here a number of times. All you people who 
complain that Python is "too slow" and that the core devs ought to do 
something about it... did any of you volunteer any time to the FatPython 
project?



-- 
Steve

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


Detection of ultrasonic side channels in mobile devices with Python?

2018-02-26 Thread Etienne Robillard

Hi,

I would like to know if its possible to detect or decode ultrasonic 
signals in mobiles devices like Android with Python?


For a introduction to ultrasonic tracking, see: 
https://www.wired.com/2016/11/block-ultrasonic-signals-didnt-know-tracking/


Thank you,

Etienne

--
Etienne Robillard
tkad...@yandex.com
https://www.isotopesoftware.ca/

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Steven D'Aprano
On Sun, 25 Feb 2018 19:26:12 -0800, Rick Johnson wrote:

> On Friday, February 23, 2018 at 8:48:55 PM UTC-6, Steven D'Aprano wrote:
> [...]
>> Take the Fibonacci double-recursion benchmark. Okay, it tests how well
>> your language does at making millions of function calls. Why?
> 
> Because making "millons of function calls" is what software *DOES*!

You're right -- I worded that badly, and ended up saying something I 
didn't really mean. Mea culpa.

Of course over the course of the entire program run, most non-trivial 
programmers will end up having millions (if not billions) of function 
calls *in total*. But they're not all happening *together*.

What I tried to get across is, how often do we use millions of function 
calls to get one value? By default, Python will only allow one thousand 
function calls in a stack before raising RecursionError.

py> def bad():
... return bad()
...
py> bad()
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in bad
  [ previous line repeats 998 times ]
RecursionError: maximum recursion depth exceeded


There's nothing unique about recursion that will trigger this error. Any 
call stack of more than 1000 function calls will do it. So forget about 
code getting a million functions deep. The average is probably more like 
a dozen, perhaps a hundred tops.


[...]
>> For most application code, executing the function is far more costly
>> than the overhead of calling it,
> 
> What? Your functions are only called _once_ during the lifetime of your
> code execution? Enough with the leg pulling.

Let me explain what I intended to say.

Here is a really poor estimate of the overhead of calling a function on 
my computer, measured in iPython.

In [50]: def call():
   : pass
   :
In [51]: %timeit call()
100 loops, best of 3: 717 ns per loop

So, on my computer, in iPython, it takes 717ns to call a function that 
does nothing. How long does it take to do the tiniest smidgen of useful 
work?

In [52]: def do_something():
   : a = 1
   : b = a+1
   : return b
   :

In [53]: %timeit do_something()
100 loops, best of 3: 923 ns per loop

Only an extra 200 ns! Wow, function calls are expensive!!!

(Well, yes, I knew that.) However, let's do some *real* work, not a 
Mickey Mouse function like do_something().

In [54]: import pyprimes

In [55]: %timeit pyprimes.nth_prime(10)
1 loops, best of 3: 2.6 s per loop


I happen to know that calling nth_prime ends up making a couple of 
hundred function calls. (Because I wrote it.) Let's call it 10,000 
function calls, to be on the safe side. So 10,000 x 800 nanoseconds is 
0.008 second, let's call it 0.01 second, which is just 0.4% of the total 
cost of calculating the number I was after.

(For the record, that's 1299709.)

So just a trivial fraction of the total cost of the function.

Now I know that this is not always the case. But I maintain that for 
*most* (but not all) practical, real-world code that actually does 
something useful, the overhead of calling the functions is *usually* (but 
not always) low compared to the cost of actually doing whatever it is 
that the functions do.



-- 
Steve

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


Re: help me ?

2018-02-26 Thread Peter Otten
Christian Gollwitzer wrote:

> Am 26.02.18 um 10:40 schrieb sotaro...@gmail.com:
>> Define 2 lists. The first one must contain the integer values 1, 2 and 3
>> and the second one the string values a, b and c. Iterate through both
>> lists to create another list that contains all the combinations of the A
>> and B elements. The final list should look like one of the 2 lists: 1.
>> [1a, 1b, 1c, 2a, 2b, 2c, 3a, 3b, 3c
> 
> Look up list comprehensions.

Hm, this will teach the OP a concise way to rewrite the solution once he has 
solved the problem with the conventional nested for loops, list.append(), 
and str.format()...

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 09:22, Steven D'Aprano wrote:

On Sun, 25 Feb 2018 21:19:19 -0800, Rick Johnson wrote:



I agree with your sarcasm. And that's why these types of auto
conversions should be optional. I agree that most times it's more
practical to let python handle the dirty details. But in some cases,
where you need to squeeze out a few more drops of speed juice, you won't
mind the extra trouble.


And that's where you call out to a library like numpy, or write a C
extension, or use a tool like Numba or Cython to optimise your Python
code to use native ints. (Numba is still a work in progress, but Cython
is a mature working product.)

Or to put it another way... if you want machine ints in Python, the way
you get them is something like:

from numba import jit

@jit
def myfunction(): ...



The core language doesn't have to support these things when there is a
healthy language ecosystem that can do it.


Below is the first draft of a Python port of a program to do with random 
numbers. (Ported from my language, which in turned ported it from a C 
program by George Marsaglia, the random number guy.)


However, running it quickly exhausts the memory in my machine. The 
reason is that Python unhelpfully widens all results to bignums as 
needed. The code relies on calculations being modulo 2^64.


Note that restricting integer ops to 64 bits probably still won't work, 
as I believe the numbers need to be unsigned.


--

Q=0
carry=36243678541
xcng=12367890123456
xs=521288629546311
indx=20632

def refill():
global Q, carry, indx
for i in range(20632):
h = carry & 1
z = ((Q[i]<<41)>>1)+((Q[i]<<39)>>1)+(carry>>1)
carry = (Q[i]>>23)+(Q[i]>>25)+(z>>63)
Q[i] = ~((z<<1)+h)
indx=1
return Q[0]

def start():
global Q, carry, xcng, xs, indx
Q=[0,]*20632

for i in range(20632):

xcng=6906969069 * xcng + 123

xs ^= (xs<<13)
xs ^= (xs>>17)
xs ^= (xs<<43)

Q[i] = xcng + xs

N = 10
for i in range(N):
if indx<20632:
s = Q[indx]
indx+=1
else:
s = refill()
xcng=6906969069 * xcng + 123
xs ^= (xs<<13)
xs ^= (xs>>17)
xs ^= (xs<<43)
x = s+xcng+xs
print ("Does x= 4013566000157423768")
print (" x=",x)

start()

--

(The code performs N iterations of a random number generator. You get 
the result expected, ie. x=401...768, when N is a billion.)


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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Chris Angelico
On Mon, Feb 26, 2018 at 8:57 PM, Steven D'Aprano
 wrote:
> On Sun, 25 Feb 2018 20:22:17 -0800, Rick Johnson wrote:
>
>> So of course, speed is not and should not be the
>> primary concern, but to say that execution speed is of _no_ concern is
>> quite absurd indeed.
>
> I'm pretty sure that nobody here has said that speed is of no concern.
>
> Rather, I would argue that the position we're taking is that *in general*
> Python is fast enough for the sorts of tasks we use it for (except, of
> course, when it isn't, in which case you have our sympathy, and if we can
> suggest some solutions we will).
>
> Of course we'd take speed optimizations if they were free, but they're
> never free:
>
> - they often require more memory to run;
>
> - they usually require more code, which adds to the maintenance burden
>   and increases the interpreter bloat;
>
> - and increases the risk of bugs;
>
> - somebody has to write, debug, document and maintain the code,
>   and developer time and effort is in short supply;
>
> - or the optimization requires changes to the way Python operates;
>
> - even if we wanted to make that change, it will break backwards
>   compatibility;
>
> - and often what people imagine is a simple optimization (because
>   they haven't tried it) isn't simple at all;
>
> - or simply doesn't work;
>
> - and most importantly, just saying "Make it go faster!" doesn't work,
>   we actually need to care about the details of *how* to make it faster.

Or it reduces memory usage, improves performance, and makes things
easier on the programmer... but might place unexpected (or unwanted)
demands on other implementations of Python. CPython, by virtue of
being the "default" Python interpreter, has to be careful of appearing
to mandate something. That's why buy-in from other Python
implementation teams (I believe Jython was the most notable here) was
important in the discussion about the recent compact dict update. Even
what looks like a no-brainer still can have unwanted consequences.

> (We tried painting Go Faster stripes on the server, and it didn't work.)

Steven Middlename D'Aprano! You should know better than that. "It
didn't work" is not good enough. What actually happened? Did the
stripes smoulder and smoke until you powered down the server? Did the
server raise NotImplementedError when you touched it with the
paintbrush? Did your boss walk up behind you and hand you a pink slip?
Be specific!

> There have been at least two (maybe three) attempts to remove the GIL
> from CPython. They've all turned out to increase complexity by a huge
> amount, and not actually provide the hoped-for speed increase. Under many
> common scenarios, the GIL-less CPython actually ran *slower*.
>
> (I say "hoped for", but it was more wishful thinking than a rational
> expectation that removing the GIL would speed things up. I don't believe
> any of the core developers were surprised that removing the GIL didn't
> increase speeds much, if at all, and sometimes slowed things down. The
> believe that the GIL slows Python down is mostly due to a really
> simplistic understanding of how threading works.)

Removing the GIL from CPython is not about "speeding up" the language
or the interpreter, but about improving parallelism. And I think all
the core devs understand this (hence the lack of surprise there), but
people who call for it often don't.

> (If it weren't for the EU government funding it, PyPy would probably be
> languishing in oblivion. Everyone wants a faster Python so long as they
> don't have to pay for it, or do the work.)

Hm, I didn't know the EU was funding PyPy. Okay. Cool.

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Chris Angelico
On Mon, Feb 26, 2018 at 10:13 PM, bartc  wrote:
> Below is the first draft of a Python port of a program to do with random
> numbers. (Ported from my language, which in turned ported it from a C
> program by George Marsaglia, the random number guy.)
>
> However, running it quickly exhausts the memory in my machine. The reason is
> that Python unhelpfully widens all results to bignums as needed. The code
> relies on calculations being modulo 2^64.
>
> Note that restricting integer ops to 64 bits probably still won't work, as I
> believe the numbers need to be unsigned.

No, it's because the original implementation assumed integer
wrap-around (at least, I think that's what's happening; I haven't
analyzed the code in great detail). That means all your integer
operations are doing two jobs: the one they claim to, and then a
masking to 64 bits signed. That's two abstract operations that happen,
due to the nature of the CPU, to work efficiently together. If you
don't implement both halves of that in your Python port, you have
failed at porting. What if you were porting a program from a 72-bit
chip that assumed Binary Coded Decimal? Would you complain that C's
integers are badly behaved?

And that's without even asking whether a C program that assumes
integer wrap-around counts as portable. At least with Python, you have
a guarantee that integer operations are going to behave the same way
on all compliant implementations of the language.

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Antoon Pardon
On 23-02-18 02:27, Steven D'Aprano wrote:
> Why do you care about the 50 million calls? That's crazy -- the important 
> thing is *calculating the Fibonacci numbers as efficiently as possible*.

No necessarily.

David Beazley in his talks sometimes uses an ineffecient algorithm for 
calculating
fibonacci numbers because he needs something that uses the cpu intensively.
calculating the fibonacci numbers in that context as efficiently as possible 
would
defeat that purpose.

So in a context of a benchmark it is not unreasonable to assume those 50 million
calls are the purpose and not calculating the Fibonacci numbers as efficiently 
as
possible.

-- 
Antoon. 
 

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 11:40, Chris Angelico wrote:

On Mon, Feb 26, 2018 at 10:13 PM, bartc  wrote:

Below is the first draft of a Python port of a program to do with random
numbers. (Ported from my language, which in turned ported it from a C
program by George Marsaglia, the random number guy.)

However, running it quickly exhausts the memory in my machine. The reason is
that Python unhelpfully widens all results to bignums as needed. The code
relies on calculations being modulo 2^64.

Note that restricting integer ops to 64 bits probably still won't work, as I
believe the numbers need to be unsigned.


No, it's because the original implementation assumed integer
wrap-around (at least, I think that's what's happening; I haven't
analyzed the code in great detail). That means all your integer
operations are doing two jobs: the one they claim to, and then a
masking to 64 bits signed. That's two abstract operations that happen,
due to the nature of the CPU, to work efficiently together. If you
don't implement both halves of that in your Python port, you have
failed at porting. What if you were porting a program from a 72-bit
chip that assumed Binary Coded Decimal? Would you complain that C's
integers are badly behaved?

And that's without even asking whether a C program that assumes
integer wrap-around counts as portable. At least with Python, you have
a guarantee that integer operations are going to behave the same way
on all compliant implementations of the language.



A C version is given below. (One I may have messed around with, which 
I'm not sure works properly. For an original, google for Marsaglia and 
KISS64 or SUPRKISS64.)


Most integers are unsigned, which have well-defined overflow in C (they 
just wrap as expected). In C, a mixed signed/unsigned op is performed as 
unsigned.


-

/*   SUPRKISS64.c, period 5*2^1320480*(2^64-1)   */
#include 
#include 
#include "timer.c"
 static signed long long Q[20632],
 carry=36243678541LL,
 xcng=12367890123456LL,
 xs=521288629546311LL,
 indx=20632;

 #define CNG ( xcng=6906969069LL*xcng+123 )
 #define XS  ( xs^=xs<<13,xs^=xs>>17,xs^=xs<<43 )
 #define SUPR ( indx<20632 ? Q[indx++] : refill() )
 #define KISS SUPR+CNG+XS

 signed long long refill(void) {
  int i; signed long long z,h;
  for(i=0;i<20632;i++) {
h = (carry&1);
z = ((Q[i]<<41)>>1)+((Q[i]<<39)>>1)+(carry>>1);
carry = (Q[i]>>23)+(Q[i]>>25)+(z>>63);
Q[i] = ~((z<<1)+h);
  }
  indx=1;
  return (Q[0]);
 }

 int main() {
  int i; signed long long x;

  for(i=0;i<20632;i++) Q[i]=CNG+XS;

  for(i=0;i<10;i++) x=KISS;

  printf("Does x=4013566000157423768\n x=%llu.\n",x);
}

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Antoon Pardon
On 24-02-18 06:18, Terry Reedy wrote:
> On 2/23/2018 11:32 AM, Python wrote:
>>
>> Doing that would completely fail to accomplish the task of comparing
>> the performance of recursive function calls in the two languages,
>> which is what the benchmark was designed to do.
>
> That is an non goal because *languages* do not have clock-time speeds,
> only programs written in concrete implementations run on real hardware.
>
> Why do you think it fair to compare function call times using the
> slowest rather than the fastest implementation of Python function
> calls?  Real Python programmers who are seriously concerned about time
> try to use the fastest implementation appropriate to the situation.

If the slowest happens to be the standard implementation I see nothing wrong 
with it.

>
> >  So, no actually, it shouldn't.
>
> To me, it is 'not using the fasted Python' that fails to make apples
> to apples comparisons.
>
> It has been said here that comparisons should use the same algorithm
> doing the much the same work in both implementation.  However, a
> Python function call does *much more work* than in most languages,
> because the meaning of 'function call' is much more flexible in Python
> than most languages.

So? I don't see what is wrong when is pointed out that all that extra
work, that a lot of people don't care about
is costing performance.

> The usual comparison is like lemons (other language calls) to oranges
> (Python language calls, much more flexible).  To be fair, the
> comparison should be to a Python implementation that either notices or
> accepts a declaration that, for instance, fib(n) only needs to pass an
> int by position.
>
> Comparing int addition to python object addition also compares unlike
> operations.  To compare using the same addition algorithm, one must
> use an implementation that can restrict '+' to just int addition.

I don't agree, if the performance loss comes from the standard implementation
of the language unable of doing that then people testing languages shouldn't
be burdened with going to search for some implementation that can.

-- 
Antoon Pardon


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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 12:06, Antoon Pardon wrote:

On 23-02-18 02:27, Steven D'Aprano wrote:

Why do you care about the 50 million calls? That's crazy -- the important
thing is *calculating the Fibonacci numbers as efficiently as possible*.


No necessarily.

David Beazley in his talks sometimes uses an ineffecient algorithm for 
calculating
fibonacci numbers because he needs something that uses the cpu intensively.
calculating the fibonacci numbers in that context as efficiently as possible 
would
defeat that purpose.

So in a context of a benchmark it is not unreasonable to assume those 50 million
calls are the purpose and not calculating the Fibonacci numbers as efficiently 
as
possible.


I don't think Steven is ever going to concede this point.

Because Python performs badly compared to Julia or C, and it's not 
possible to conveniently offload the task to some fast library because 
it only uses a handful of primitive byte-codes.


(I have the same trouble with my own interpreted language. Although 
somewhat brisker than CPython, it will always be much slower than a 
C-like language on such micro-benchmarks.


But I accept that; I don't have an army of people working on 
acceleration projects and tracing JIT compilers. To those people 
however, such a benchmark can be a useful yardstick of progress.)


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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Steven D'Aprano
On Mon, 26 Feb 2018 22:34:00 +1100, Chris Angelico wrote:

[...]
>> (We tried painting Go Faster stripes on the server, and it didn't
>> work.)
> 
> Steven Middlename D'Aprano! You should know better than that. "It didn't
> work" is not good enough. What actually happened?

A truck crashed into the power pole outside our building and the power 
went off. Then the UPS ran down and the server crashed.

Clearly this is a bug in the go-faster stripes. We tried reporting it:

Expected behaviour: server goes faster.

Actual behaviour: a truck crashes into the power pole 
across the street and the lights go out.

but the maintainers closed the issue "Works for me". Very disappointed!


[...]
> Removing the GIL from CPython is not about "speeding up" the language or
> the interpreter, but about improving parallelism.

It is about speeding up threaded code which is CPU-bound. I call that 
speeding up the language :-)

Hypothetically, it could also speed up even unthreaded code.

Some language features could internally launch threads and operate using 
implicit parallelism. For instance, map(func, seq) could run in parallel 
in separate threads whenever Python knew that func had no side-effects, 
say for built-ins. There are also parallel algorithms for bignum 
arithmetic. If threads were quick enough, I'm sure we could come up with 
many more examples. Hypothetically speaking.

(In practice, the old hope that parallel computing would speed everything 
up turned out to be flawed. Relatively few tasks are embarrassingly 
parallel, most have sequential bottlenecks, and many are inherently 
sequential.)


>> (If it weren't for the EU government funding it, PyPy would probably be
>> languishing in oblivion. Everyone wants a faster Python so long as they
>> don't have to pay for it, or do the work.)
> 
> Hm, I didn't know the EU was funding PyPy. Okay. Cool.

I don't know if they still receive funding, but I know that PyPy really 
only got going in a big way when they got a grant from the EU. I think it 
paid for at least one developer to work on it full time for a year. 
DuckDuckGo is probably your friend if you care about the details.



-- 
Steve

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Ned Batchelder

On 2/26/18 7:13 AM, bartc wrote:

On 26/02/2018 11:40, Chris Angelico wrote:

On Mon, Feb 26, 2018 at 10:13 PM, bartc  wrote:
Below is the first draft of a Python port of a program to do with 
random

numbers. (Ported from my language, which in turned ported it from a C
program by George Marsaglia, the random number guy.)

However, running it quickly exhausts the memory in my machine. The 
reason is
that Python unhelpfully widens all results to bignums as needed. The 
code

relies on calculations being modulo 2^64.

Note that restricting integer ops to 64 bits probably still won't 
work, as I

believe the numbers need to be unsigned.


No, it's because the original implementation assumed integer
wrap-around (at least, I think that's what's happening; I haven't
analyzed the code in great detail). That means all your integer
operations are doing two jobs: the one they claim to, and then a
masking to 64 bits signed. That's two abstract operations that happen,
due to the nature of the CPU, to work efficiently together. If you
don't implement both halves of that in your Python port, you have
failed at porting. What if you were porting a program from a 72-bit
chip that assumed Binary Coded Decimal? Would you complain that C's
integers are badly behaved?

And that's without even asking whether a C program that assumes
integer wrap-around counts as portable. At least with Python, you have
a guarantee that integer operations are going to behave the same way
on all compliant implementations of the language.



A C version is given below. (One I may have messed around with, which 
I'm not sure works properly. For an original, google for Marsaglia and 
KISS64 or SUPRKISS64.)


Most integers are unsigned, which have well-defined overflow in C 
(they just wrap as expected). In C, a mixed signed/unsigned op is 
performed as unsigned.


-

/*   SUPRKISS64.c, period 5*2^1320480*(2^64-1)   */
#include 
#include 
#include "timer.c"
 static signed long long Q[20632],
 carry=36243678541LL,
 xcng=12367890123456LL,
 xs=521288629546311LL,
 indx=20632;

 #define CNG ( xcng=6906969069LL*xcng+123 )
 #define XS  ( xs^=xs<<13,xs^=xs>>17,xs^=xs<<43 )
 #define SUPR ( indx<20632 ? Q[indx++] : refill() )
 #define KISS SUPR+CNG+XS

 signed long long refill(void) {
  int i; signed long long z,h;
  for(i=0;i<20632;i++) {
    h = (carry&1);
    z = ((Q[i]<<41)>>1)+((Q[i]<<39)>>1)+(carry>>1);
    carry = (Q[i]>>23)+(Q[i]>>25)+(z>>63);
    Q[i] = ~((z<<1)+h);
  }
  indx=1;
  return (Q[0]);
 }

 int main() {
  int i; signed long long x;

  for(i=0;i<20632;i++) Q[i]=CNG+XS;

  for(i=0;i<10;i++) x=KISS;

  printf("Does x=4013566000157423768\n x=%llu.\n",x);
}



With proper 64-bit masking (def only64(x): return x & 
0x), the Python version produces the correct answer 
using a reasonable amount of memory. Well, once you notice that the 
Python code had N=1e5, and the C code had N=1e9 :)   If you want to 
experiment, with N=1e5, the final number should be 5255210926702073855.


Also, I note that you said, "Most integers are unsigned", but the C code 
has them all declared as signed?  It doesn't seem to have mattered to 
your result, but I'm not an expert on C portability guarantees.


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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Rhodri James

On 26/02/18 13:42, Ned Batchelder wrote:
Also, I note that you said, "Most integers are unsigned", but the C code 
has them all declared as signed?  It doesn't seem to have mattered to 
your result, but I'm not an expert on C portability guarantees.


C explicitly leaves the behaviour of signed arithmetic overflow 
undefined, so you have no portability guarantees there.


--
Rhodri James *-* Kynesim Ltd
--
https://mail.python.org/mailman/listinfo/python-list


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 13:42, Ned Batchelder wrote:

On 2/26/18 7:13 AM, bartc wrote:


A C version is given below. (One I may have messed around with, which 
I'm not sure works properly. For an original, google for Marsaglia and 
KISS64 or SUPRKISS64.)


Most integers are unsigned, which have well-defined overflow in C 


With proper 64-bit masking (def only64(x): return x & 
0x), the Python version produces the correct answer 
using a reasonable amount of memory.


I did try sometime like that, but I must have missed something because I 
didn't get quite the same results as a working version.


And with interpreted code, you tend not to test using loops of a billion 
iterations.


 Well, once you notice that the
Python code had N=1e5, and the C code had N=1e9 :)   If you want to 
experiment, with N=1e5, the final number should be 5255210926702073855.


OK, I'll try that.

Also, I note that you said, "Most integers are unsigned", but the C code 
has them all declared as signed?  It doesn't seem to have mattered to 
your result, but I'm not an expert on C portability guarantees.


The C code I first pasted used 'unsigned', but the main program logic 
wasn't right, and I found another version that looked better. That one 
used 'signed' for some reason, which I completely missed.


Even if with C it works with either, the signed version might have 
'undefined behaviour'. As said, google for the original; the ones I can 
see have 'unsigned'. But I can also see a Fortran version that just uses 
'integer*8', which I believe is signed 64-bit.


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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 12:03 AM, Steven D'Aprano
 wrote:
> On Mon, 26 Feb 2018 22:34:00 +1100, Chris Angelico wrote:
>> Removing the GIL from CPython is not about "speeding up" the language or
>> the interpreter, but about improving parallelism.
>
> It is about speeding up threaded code which is CPU-bound. I call that
> speeding up the language :-)
>
> Hypothetically, it could also speed up even unthreaded code.

In its purest sense, no, it cannot speed up unthreaded code. Since
many Python programs are single-threaded, this restricts the benefits
to those programs which can actually parallelize, but the penalties
(mainly overhead) usually apply to all programs.

> Some language features could internally launch threads and operate using
> implicit parallelism. For instance, map(func, seq) could run in parallel
> in separate threads whenever Python knew that func had no side-effects,
> say for built-ins. There are also parallel algorithms for bignum
> arithmetic. If threads were quick enough, I'm sure we could come up with
> many more examples. Hypothetically speaking.

These are ways of converting single-threaded code into multi-threaded
code, which could then benefit from parallelization, which can reduce
wall-time for the process as a whole.

> (In practice, the old hope that parallel computing would speed everything
> up turned out to be flawed. Relatively few tasks are embarrassingly
> parallel, most have sequential bottlenecks, and many are inherently
> sequential.)

Exactly; and it goes further: many modern programmers do not think in
terms of parallelism. Even event-driven code takes a bit of getting
your head around. Why are async functions preferred over threads? It's
not JUST because today's OSes have thread count limits far below
socket limits - if that were the sole justification, we wouldn't have
language-level support for async/await - it'd be a niche technique
used only in the highest-throughput applications. No, async functions
are preferred because they *reduce the points where context switching
can occur*, thus making it easier *for the programmer*. If there were
a way for the language to automatically run things in parallel, the
biggest risk is that the programmer who wrote it can no longer
understand it.

>>> (If it weren't for the EU government funding it, PyPy would probably be
>>> languishing in oblivion. Everyone wants a faster Python so long as they
>>> don't have to pay for it, or do the work.)
>>
>> Hm, I didn't know the EU was funding PyPy. Okay. Cool.
>
> I don't know if they still receive funding, but I know that PyPy really
> only got going in a big way when they got a grant from the EU. I think it
> paid for at least one developer to work on it full time for a year.
> DuckDuckGo is probably your friend if you care about the details.

Meh, I don't care that much about what the EU does or doesn't fund.
Was just a mild case of curiosity. I had about as much interest as my
savings account accrued last year.

I'm glad _someone_ funded PyPy, anyhow. It's a great demonstration of
what can be done.

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


Re: help me ?

2018-02-26 Thread Lutz Horn

Define 2 lists. ...

[...]

Help me !


Sounds like homework. Have you tried anything? Does it work?
--
https://mail.python.org/mailman/listinfo/python-list


Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Steven D'Aprano
I have a class with a large number of parameters (about ten) assigned in 
`__init__`. The class then has a number of methods which accept 
*optional* arguments with the same names as the constructor/initialiser 
parameters. If those arguments are None, the defaults are taken from the 
instance attributes.

An example might be something like this:


class Foo:
def __init__(self, bashful, doc, dopey, grumpy, 
   happy, sleepy, sneezy):
self.bashful = bashful  # etc

def spam(self, bashful=None, doc=None, dopey=None, 
   grumpy=None, happy=None, sleepy=None,
   sneezy=None):
if bashful is None:
bashful = self.bashful
if doc is None:
doc = self.doc
if dopey is None:
dopey = self.dopey
if grumpy is None:
grumpy = self.grumpy
if happy is None:
happy = self.happy
if sleepy is None:
sleepy = self.sleepy
if sneezy is None:
sneezy = self.sneezy
# now do the real work...

def eggs(self, bashful=None, # etc... 
   ):
if bashful is None:
bashful = self.bashful
# and so on
 

There's a lot of tedious boilerplate repetition in this, and to add 
insult to injury the class is still under active development with an 
unstable API, so every time I change one of the parameters, or add a new 
one, I have to change it in over a dozen places.

Is there a good fix for this to reduce the amount of boilerplate?


Thanks,



-- 
Steve

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 14:34, Chris Angelico wrote:


I'm glad _someone_ funded PyPy, anyhow. It's a great demonstration of
what can be done.


And it's good that /someone/ at least understands how PyPy works, as I 
don't think many people do.


Apparently it doesn't optimise 'hot paths' within a Python program, but 
optimises hot paths in the special Python interpreter. One written in 
[R]Python. Or something...


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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Antoon Pardon
On 26-02-18 15:41, Steven D'Aprano wrote:
> I have a class with a large number of parameters (about ten) assigned in 
> `__init__`. The class then has a number of methods which accept 
> *optional* arguments with the same names as the constructor/initialiser 
> parameters. If those arguments are None, the defaults are taken from the 
> instance attributes.
>
> An example might be something like this:
>
>
> class Foo:
> def __init__(self, bashful, doc, dopey, grumpy, 
>happy, sleepy, sneezy):
> self.bashful = bashful  # etc
>
> def spam(self, bashful=None, doc=None, dopey=None, 
>grumpy=None, happy=None, sleepy=None,
>sneezy=None):
> if bashful is None:
> bashful = self.bashful
> if doc is None:
> doc = self.doc
> if dopey is None:
> dopey = self.dopey
> if grumpy is None:
> grumpy = self.grumpy
> if happy is None:
> happy = self.happy
> if sleepy is None:
> sleepy = self.sleepy
> if sneezy is None:
> sneezy = self.sneezy
> # now do the real work...

Just throwing out an idea, but would it be possible to do what you want with
a decorator? You let the wrapper do this kind of control and then pass
control to the actual function with all values filled in?

I'll try to work something out later.

-- 
Antoon.


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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 14:04, bartc wrote:

On 26/02/2018 13:42, Ned Batchelder wrote:



  Well, once you notice that the
Python code had N=1e5, and the C code had N=1e9 :)   If you want to 
experiment, with N=1e5, the final number should be 5255210926702073855.


OK, I'll try that.


I have that Python version working now. It's necessary to apply that 
masking function to wherever numbers can get bigger.


I don't know how long a 1-billion loop will take, but a 10-million loop 
took 46 seconds on Python 3.6, and 21 seconds on PyPy 2.7 from a couple 
of years ago. (And on Windows, which has a somewhat slower CPython than 
Linux.)


Result should be x=11240129907685265998.

By comparison, the C version compiled with -O3 took 0.11 seconds.

(The C version I posted will work, if adjusted to a 1000 loop, but 
you have to change 'signed' to 'unsigned'. Apparently they weren't 
interchangeable after all. I've no idea why I used 'signed' there.


That version is rather cryptic, but it can be better written and without 
the macros, and it will run just as fast. (Marsaglia may have been hot 
with random number routines, but his C could have done with some work...)


My interpreter, using 64-bit numbers, managed 4.8 seconds. But unsigned 
arithmetic, which is uncommon, is not accelerated.)


---

Q=0
carry=36243678541
xcng=12367890123456
xs=521288629546311
indx=20632

def i64(x): return x & 0x

def refill():
global Q, carry, indx
for i in range(20632):
h = carry & 1
z = i64((  i64((Q[i]<<41))>>1)+(i64((Q[i]<<39))>>1)+(carry>>1))
carry = i64((Q[i]>>23)+(Q[i]>>25)+(z>>63))
Q[i] = i64(~(i64(i64(z<<1)+h)))

indx=1
return Q[0]

def start():
global Q, carry, xcng, xs, indx
Q=[0,]*20632

for i in range(20632):

xcng=i64(6906969069 * xcng + 123)

xs = i64(xs ^ (xs<<13))
xs = i64(xs ^ (xs>>17))
xs = i64(xs ^ (xs<<43))

Q[i] = i64(xcng + xs)

N = 1000
for i in range(N):
if indx<20632:
s = Q[indx]
indx+=1
else:
s = refill()
xcng=i64(6906969069 * xcng + 123)
xs = i64(xs ^ (xs<<13))
xs = i64(xs ^ (xs>>17))
xs = i64(xs ^ (xs<<43))
x = i64(s+xcng+xs)
print ("Does x= 4013566000157423768")
print (" x=",x)

start()

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 1:41 AM, Steven D'Aprano
 wrote:
> I have a class with a large number of parameters (about ten) assigned in
> `__init__`. The class then has a number of methods which accept
> *optional* arguments with the same names as the constructor/initialiser
> parameters. If those arguments are None, the defaults are taken from the
> instance attributes.

I have a very similar problem in a project of mine, and it's currently
an unsolved problem. My current best theory is to basically just
accept **kwargs for everything (so there's no None defaults), and then
use chain_map for all lookups. Seems inefficient, but at least it'd be
functional. Haven't implemented it though.

If you get any better ideas, I'll be reading them too.

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 2:02 AM, bartc  wrote:
> On 26/02/2018 14:04, bartc wrote:
>>
>> On 26/02/2018 13:42, Ned Batchelder wrote:
>
>
>>   Well, once you notice that the
>>>
>>> Python code had N=1e5, and the C code had N=1e9 :)   If you want to
>>> experiment, with N=1e5, the final number should be 5255210926702073855.
>>
>>
>> OK, I'll try that.
>
>
> I have that Python version working now. It's necessary to apply that masking
> function to wherever numbers can get bigger.
>
> I don't know how long a 1-billion loop will take, but a 10-million loop took
> 46 seconds on Python 3.6, and 21 seconds on PyPy 2.7 from a couple of years
> ago. (And on Windows, which has a somewhat slower CPython than Linux.)

You're still reimplementing the C code in Python, which is
inefficient. Have you considered going back to the *actual algorithm*
and implementing that idiomatically in Python? I think you'll find
that (a) the code is more readable, and (b) the run time is much
lower.

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Vincent Vande Vyvre

Le 26/02/18 à 15:41, Steven D'Aprano a écrit :

I have a class with a large number of parameters (about ten) assigned in
`__init__`. The class then has a number of methods which accept
*optional* arguments with the same names as the constructor/initialiser
parameters. If those arguments are None, the defaults are taken from the
instance attributes.

An example might be something like this:


class Foo:
 def __init__(self, bashful, doc, dopey, grumpy,
happy, sleepy, sneezy):
 self.bashful = bashful  # etc

 def spam(self, bashful=None, doc=None, dopey=None,
grumpy=None, happy=None, sleepy=None,
sneezy=None):
 if bashful is None:
 bashful = self.bashful
 if doc is None:
 doc = self.doc
 if dopey is None:
 dopey = self.dopey
 if grumpy is None:
 grumpy = self.grumpy
 if happy is None:
 happy = self.happy
 if sleepy is None:
 sleepy = self.sleepy
 if sneezy is None:
 sneezy = self.sneezy
 # now do the real work...

 def eggs(self, bashful=None, # etc...
):
 if bashful is None:
 bashful = self.bashful
 # and so on
  


There's a lot of tedious boilerplate repetition in this, and to add
insult to injury the class is still under active development with an
unstable API, so every time I change one of the parameters, or add a new
one, I have to change it in over a dozen places.

Is there a good fix for this to reduce the amount of boilerplate?


Thanks,




Maybe something like this:

    def config(self, **kwargs):
    for key, value in kwargs.items():
    if value is not None:
    setattr(self, key, value)

    def spam(self, **kwargs):
    self.config(kwargs)


Vincent

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Antoon Pardon
On 26-02-18 15:41, Steven D'Aprano wrote:
> I have a class with a large number of parameters (about ten) assigned in 
> `__init__`. The class then has a number of methods which accept 
> *optional* arguments with the same names as the constructor/initialiser 
> parameters. If those arguments are None, the defaults are taken from the 
> instance attributes.
>
This is what I came up with at short notice:

def passthrough(func):
def wrapper(self, **kwds):
for argn in "bashful doc dopey grumpy happy sleepy sneezy".split():
if argn not in kwds:
kwds[argn] = getattr(self, argn)
func(self, **kwds)
return wrapper


class Foo:
def __init__(self, bashful, doc, dopey, grumpy, 
   happy, sleepy, sneezy):
self.bashful = bashful
self.doc = doc
self.dopey = dopey
self.grumpy = grumpy
self.happy = happy
self.sleepy = sleepy
self.sneezy = sneezy

@passthrough
def spam(self, bashful=None, doc=None, dopey=None, 
   grumpy=None, happy=None, sleepy=None,
   sneezy=None):
print(bashful, doc, dopey, grumpy, happy, sleepy, sneezy)

foo = Foo('a', 'b', 'c', 'd', 'e', 'f', 'g')
foo.spam(happy = 1) # prints => a b c d 1 f g


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


Re: For Loop Dilema [python-list]

2018-02-26 Thread Ian Kelly
On Sun, Feb 25, 2018 at 8:05 PM, INADA Naoki  wrote:
> https://docs.python.org/3.6/library/itertools.html#itertools.product

I don't see how you would use itertools.product to do what the OP
asked for. You could use itertools.chain.from_iterable, though:

py> names = ['Jack', 'Susan']
py> list(chain.from_iterable(names))
['J', 'a', 'c', 'k', 'S', 'u', 's', 'a', 'n']
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Rhodri James

On 26/02/18 14:41, Steven D'Aprano wrote:

I have a class with a large number of parameters (about ten) assigned in
`__init__`. The class then has a number of methods which accept
*optional* arguments with the same names as the constructor/initialiser
parameters. If those arguments are None, the defaults are taken from the
instance attributes.

An example might be something like this:


class Foo:
 def __init__(self, bashful, doc, dopey, grumpy,
happy, sleepy, sneezy):
 self.bashful = bashful  # etc

 def spam(self, bashful=None, doc=None, dopey=None,
grumpy=None, happy=None, sleepy=None,
sneezy=None):
 if bashful is None:
 bashful = self.bashful
 if doc is None:
 doc = self.doc
 if dopey is None:
 dopey = self.dopey
 if grumpy is None:
 grumpy = self.grumpy
 if happy is None:
 happy = self.happy
 if sleepy is None:
 sleepy = self.sleepy
 if sneezy is None:
 sneezy = self.sneezy
 # now do the real work...

 def eggs(self, bashful=None, # etc...
):
 if bashful is None:
 bashful = self.bashful
 # and so on
  


There's a lot of tedious boilerplate repetition in this, and to add
insult to injury the class is still under active development with an
unstable API, so every time I change one of the parameters, or add a new
one, I have to change it in over a dozen places.

Is there a good fix for this to reduce the amount of boilerplate?


You could use dicts?  Untested code:

class Foo:
def __init__(self, **kwds):
self.defaults = kwds

def spam(self, **kwds):
vars = self.defaults.copy()
vars.update(kwds)
# Do the work with vars['bashful'] etc


--
Rhodri James *-* Kynesim Ltd
--
https://mail.python.org/mailman/listinfo/python-list


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Ned Batchelder

On 2/26/18 10:09 AM, Chris Angelico wrote:

On Tue, Feb 27, 2018 at 2:02 AM, bartc  wrote:

On 26/02/2018 14:04, bartc wrote:

On 26/02/2018 13:42, Ned Batchelder wrote:



   Well, once you notice that the

Python code had N=1e5, and the C code had N=1e9 :)   If you want to
experiment, with N=1e5, the final number should be 5255210926702073855.


OK, I'll try that.


I have that Python version working now. It's necessary to apply that masking
function to wherever numbers can get bigger.

I don't know how long a 1-billion loop will take, but a 10-million loop took
46 seconds on Python 3.6, and 21 seconds on PyPy 2.7 from a couple of years
ago. (And on Windows, which has a somewhat slower CPython than Linux.)

You're still reimplementing the C code in Python, which is
inefficient. Have you considered going back to the *actual algorithm*
and implementing that idiomatically in Python? I think you'll find
that (a) the code is more readable, and (b) the run time is much
lower.




Don't bother: C will win this kind of race every time.

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Rob Gaddi

On 02/26/2018 07:28 AM, Rhodri James wrote:

On 26/02/18 14:41, Steven D'Aprano wrote:

I have a class with a large number of parameters (about ten) assigned in
`__init__`. The class then has a number of methods which accept
*optional* arguments with the same names as the constructor/initialiser
parameters. If those arguments are None, the defaults are taken from the
instance attributes.

An example might be something like this:


class Foo:
 def __init__(self, bashful, doc, dopey, grumpy,
    happy, sleepy, sneezy):
 self.bashful = bashful  # etc

 def spam(self, bashful=None, doc=None, dopey=None,
    grumpy=None, happy=None, sleepy=None,
    sneezy=None):
 if bashful is None:
 bashful = self.bashful
 if doc is None:
 doc = self.doc
 if dopey is None:
 dopey = self.dopey
 if grumpy is None:
 grumpy = self.grumpy
 if happy is None:
 happy = self.happy
 if sleepy is None:
 sleepy = self.sleepy
 if sneezy is None:
 sneezy = self.sneezy
 # now do the real work...

 def eggs(self, bashful=None, # etc...
    ):
 if bashful is None:
 bashful = self.bashful
 # and so on

There's a lot of tedious boilerplate repetition in this, and to add
insult to injury the class is still under active development with an
unstable API, so every time I change one of the parameters, or add a new
one, I have to change it in over a dozen places.

Is there a good fix for this to reduce the amount of boilerplate?


You could use dicts?  Untested code:

class Foo:
     def __init__(self, **kwds):
     self.defaults = kwds

     def spam(self, **kwds):
     vars = self.defaults.copy()
     vars.update(kwds)
 # Do the work with vars['bashful'] etc




That's what I was about to suggest (and equally fail to test).  It at 
least segregates the set of "instance variables I want to have 
auto-default behavior" from the rest of them.  Yeah, **kwargs is clumsy, 
but it gets the job done.


--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order.  See above to fix.
--
https://mail.python.org/mailman/listinfo/python-list


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 15:09, Chris Angelico wrote:

On Tue, Feb 27, 2018 at 2:02 AM, bartc  wrote:

On 26/02/2018 14:04, bartc wrote:


On 26/02/2018 13:42, Ned Batchelder wrote:




   Well, once you notice that the


Python code had N=1e5, and the C code had N=1e9 :)   If you want to
experiment, with N=1e5, the final number should be 5255210926702073855.



OK, I'll try that.



I have that Python version working now. It's necessary to apply that masking
function to wherever numbers can get bigger.

I don't know how long a 1-billion loop will take, but a 10-million loop took
46 seconds on Python 3.6, and 21 seconds on PyPy 2.7 from a couple of years
ago. (And on Windows, which has a somewhat slower CPython than Linux.)


You're still reimplementing the C code in Python, which is
inefficient. Have you considered going back to the *actual algorithm*
and implementing that idiomatically in Python? I think you'll find
that (a) the code is more readable, and (b) the run time is much
lower.


Do you really think that?

The algorithm seems to require this sequence of calculations to be gone 
through. Otherwise anything more efficient can also be done in any language.


So how would idiomatic Python help, by seeing if such a routine already 
exists in some library? That wouldn't be playing the game.


If it helps, I remember playing with a version in Algol 68 Genie 
(interpreted). Still buggy as the output is different, it does about the 
same amount of work.


A 10-million loop would take an estimated 1000 seconds, on the same 
machine that CPython took 46 seconds. So four magnitudes slower than C.


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


Re: matrix multiplication

2018-02-26 Thread Seb
On Sun, 25 Feb 2018 18:52:14 -0500,
Terry Reedy  wrote:

[...]

> numpy has a matrix multiply function and now the '@' matrix multiply
> operator.

Yes, but what I was wondering is whether there's a faster way of
multiplying each row (1x3) of a matrix by another matrix (3x3), compared
to looping through the matrix row by row as shown in the code.  Perhaps
I'm not understanding how to use the broadcasting features of `matmul`.

-- 
Seb

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Peter Otten
Steven D'Aprano wrote:

> I have a class with a large number of parameters (about ten) assigned in
> `__init__`. The class then has a number of methods which accept
> *optional* arguments with the same names as the constructor/initialiser
> parameters. If those arguments are None, the defaults are taken from the
> instance attributes.
> 
> An example might be something like this:
> 
> 
> class Foo:
> def __init__(self, bashful, doc, dopey, grumpy,
>happy, sleepy, sneezy):
> self.bashful = bashful  # etc
> 
> def spam(self, bashful=None, doc=None, dopey=None,
>grumpy=None, happy=None, sleepy=None,
>sneezy=None):
> if bashful is None:
> bashful = self.bashful
> if doc is None:
> doc = self.doc
> if dopey is None:
> dopey = self.dopey
> if grumpy is None:
> grumpy = self.grumpy
> if happy is None:
> happy = self.happy
> if sleepy is None:
> sleepy = self.sleepy
> if sneezy is None:
> sneezy = self.sneezy
> # now do the real work...
> 
> def eggs(self, bashful=None, # etc...
>):
> if bashful is None:
> bashful = self.bashful
> # and so on
>  
> 
> There's a lot of tedious boilerplate repetition in this, and to add
> insult to injury the class is still under active development with an
> unstable API, so every time I change one of the parameters, or add a new
> one, I have to change it in over a dozen places.
> 
> Is there a good fix for this to reduce the amount of boilerplate?

I have not yet looked into dataclasses. Don't they handle the __init__() 
part? Anyway, here's my attempt to make spam() less spammy:

$ cat attrs_to_args_decorator.py 
import functools
import inspect

def add_defaults(f):
argnames = inspect.getfullargspec(f).args[1:]

@functools.wraps(f)
def wrapper(self, *args, **kw):
args = [
getattr(self, name) if value is None else value
for name, value in zip(argnames, args)
]
for name in argnames[len(args):]:
if name not in kw or kw[name] is None:
kw[name] = getattr(self, name)
return f(self, *args, **kw)
return wrapper


def update_attrs(kw):
self = kw.pop("self")
for name, value in kw.items():
setattr(self, name, value)


class Foo:
def __init__(self, bashful, doc, dopey, grumpy, 
   happy, sleepy, sneezy):
update_attrs(locals())

@add_defaults
def spam(self, bashful=None, doc=None, dopey=None, 
   grumpy=None, happy=None, sleepy=None,
   sneezy=None):
return "{}-{}-{}".format(bashful, doc, sneezy)

def __repr__(self):
return "Foo({})".format(
", ".join(
"{}={!r}".format(*pair)
for pair in sorted(self.__dict__.items())
)
)

if __name__ == "__main__":
foo = Foo("bashful", "doc", "dopey", "grumpy", "happy", "sleepy", 
"sneezy")
print(foo)
print(foo.spam())
print(foo.spam(bashful="BASHFUL"))
print(foo.spam(bashful="BASHFUL", doc="DOC"))
print(foo.spam("BASHFUL"))
print(foo.spam("BASHFUL", "DOC"))
print(foo.spam("BASHFUL", "DOC", sneezy="SNEEZY"))
$ python3 attrs_to_args_decorator.py 
Foo(bashful='bashful', doc='doc', dopey='dopey', grumpy='grumpy', 
happy='happy', sleepy='sleepy', sneezy='sneezy')
bashful-doc-sneezy
BASHFUL-doc-sneezy
BASHFUL-DOC-sneezy
BASHFUL-doc-sneezy
BASHFUL-DOC-sneezy
BASHFUL-DOC-SNEEZY
$

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Ben Bacarisse
bartc  writes:

> A C version is given below. (One I may have messed around with, which
> I'm not sure works properly. For an original, google for Marsaglia and
> KISS64 or SUPRKISS64.)

The version I know uses unsigned integers.  Did you change then to signed?

For a Python version, go back to the original C and work from there.

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


Re: matrix multiplication

2018-02-26 Thread Ian Kelly
On Mon, Feb 26, 2018 at 9:53 AM, Seb  wrote:
> On Sun, 25 Feb 2018 18:52:14 -0500,
> Terry Reedy  wrote:
>
> [...]
>
>> numpy has a matrix multiply function and now the '@' matrix multiply
>> operator.
>
> Yes, but what I was wondering is whether there's a faster way of
> multiplying each row (1x3) of a matrix by another matrix (3x3), compared
> to looping through the matrix row by row as shown in the code.  Perhaps
> I'm not understanding how to use the broadcasting features of `matmul`.

>From the matmul documentation:

"If either argument is N-D, N > 2, it is treated as a stack of
matrices residing in the last two indexes and broadcast accordingly."

So you probably want your uvw array to be 1000x1x3 instead of 1000x3.
Then the result of multiplying them should be 1000 1x3 matrices.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Rick Johnson
On Monday, February 26, 2018 at 3:59:40 AM UTC-6, Steven D'Aprano wrote:
> On Sun, 25 Feb 2018 20:22:17 -0800, Rick Johnson wrote:

> (We tried painting Go Faster stripes on the server, and it
> didn't work.)

Well of course the server won't work after you drip water-
based paint all over the circuit boards. Way to go! In the
future i would suggest draping some old linens over the
electrical bits before throwing your paint around (just be
sure to consult with the wife before rummaging through her
linen closet, as men have been known to meet an untimely
demise for doing much less) . And might i suggest some
skulls and faux flames? Hey, it may not make the thing go
any faster, but it will surely make the other kids jealous.
There's no reason why apple and microsoft should be allowed
to suck up every last merchandising dollar.

> There's no point suggesting such major changes to Python
> that requires going back to the drawing board, to Python
> 0.1 or earlier, and changing the entire execution and
> memory model of the language.

Absolutely not. Probably too late for that now.  I'm only
suggesting that we, when at all possible, provide a switch
to disable these lazy-features in those rare cases when they
do create bottlenecks. Lazy iterators and dict-views are
great ideas, but i'm sure there are instances which prove
them to be PITA and even a bottleneck.


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


Re: For Loop Dilema [python-list]

2018-02-26 Thread arya . kumar2494
On Monday, February 26, 2018 at 8:51:35 PM UTC+5:30, Ian wrote:
> On Sun, Feb 25, 2018 at 8:05 PM, INADA Naoki  wrote:
> > https://docs.python.org/3.6/library/itertools.html#itertools.product
> 
> I don't see how you would use itertools.product to do what the OP
> asked for. You could use itertools.chain.from_iterable, though:
> 
> py> names = ['Jack', 'Susan']
> py> list(chain.from_iterable(names))
> ['J', 'a', 'c', 'k', 'S', 'u', 's', 'a', 'n']

if you want to access a dict per say insisde a list or maybe some data i.e deep 
nested in some mixture of ds wont it be relevant to use a single for statement 
to query the data out.(Just a thought)
Students = [{"name":John,"age":16},{"name":Maria,"age":18}]

for info in student in Students:
 print(student[info])



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


Re: For Loop Dilema [python-list]

2018-02-26 Thread arya . kumar2494
On Monday, February 26, 2018 at 6:20:06 AM UTC+5:30, Ian wrote:
> On Sun, Feb 25, 2018 at 11:19 AM,   wrote:
> > Why we don’t use:
> >
> > for _ in _ in _
> >
> > Instead of
> >
> > for _ in _:
> > for _ in _:
> >
> > Ex:
> >
> > Names = ["Arya","Pupun"]
> >
> > for name in Names:
> >for c in name:
> >print(c)
> >
> > instead use:
> >
> > for c in name in Names:
> > print(c)
> 
> It doesn't seem very intuitive (doesn't follow proper English
> phrasing, for instance) and I don't think it's a common enough
> situation to warrant adding a special syntax for it. But if you really
> want it, you could use something like this:
> 
> def double_for(iterable):
> for outer in iterable:
> yield from outer
> 
> for c in double_for(Names):
> print(c)
> 
> But I don't think this is any clearer than making the loops explicit.

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


Re: For Loop Dilema [python-list]

2018-02-26 Thread arya . kumar2494
On Monday, February 26, 2018 at 6:23:24 AM UTC+5:30, Rick Johnson wrote:
> On Sunday, February 25, 2018 at 12:19:56 PM UTC-6, arya.ku...@gmail.com wrote:
> 
> > Ex:
> > 
> > Names = ["Arya","Pupun"]
> > 
> > for name in Names:
> >for c in name:
> >print(c)
> > 
> > instead use:
> > 
> > for c in name in Names:
> > print(c)
> 
> Hmm. Why stop there?
> 
> bit = ["kibbles"]
> bits = [bit, bit]
> bitts = [bits, bits]
> for kibbles in bit in bits in bitts:
> do_something(kibbles)

My thought exactly.. :)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Ian Kelly
On Mon, Feb 26, 2018 at 8:06 AM, Chris Angelico  wrote:
> On Tue, Feb 27, 2018 at 1:41 AM, Steven D'Aprano
>  wrote:
>> I have a class with a large number of parameters (about ten) assigned in
>> `__init__`. The class then has a number of methods which accept
>> *optional* arguments with the same names as the constructor/initialiser
>> parameters. If those arguments are None, the defaults are taken from the
>> instance attributes.
>
> I have a very similar problem in a project of mine, and it's currently
> an unsolved problem. My current best theory is to basically just
> accept **kwargs for everything (so there's no None defaults), and then
> use chain_map for all lookups. Seems inefficient, but at least it'd be
> functional. Haven't implemented it though.
>
> If you get any better ideas, I'll be reading them too.

I would be tempted to take this and then formalize it into a Context
class that would be passed to the various methods and initializers
rather than passing all the sundry arguments directly. Similar to what
the decimal class uses although perhaps without the idea of a global
context (which just leads to trouble down the road).
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 17:05, Ben Bacarisse wrote:

bartc  writes:


A C version is given below. (One I may have messed around with, which
I'm not sure works properly. For an original, google for Marsaglia and
KISS64 or SUPRKISS64.)


The version I know uses unsigned integers.  Did you change then to signed?


Yeah, I don't know what I was doing with that version.


For a Python version, go back to the original C and work from there.


The original C makes confusing use of macros and comma operators.

A version without macros or comma expressions is here (tweaked from 
generated C):


  https://pastebin.com/raw/k4jFK5TN

This runs the 1-billion loop in 6 seconds.

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


Questions about `locals` builtin

2018-02-26 Thread Kirill Balunov
Hi,

I am a little bit confused with `locals` builtin in these moments:

1. The documentation says that _free varaibles_ are returned, which seems
incorrect description. In my mind the term free variable refers to
variables used in a function that are not local variables nor parameters of
that function.

In docs: "Update and return a dictionary representing the current local
symbol table. Free variables are returned by `locals()` when it is called
in function blocks, but not in class blocks."

>>> def func():

b = 12

print(locals(), ' : ', id(locals))

c = 13

print(locals(), ' : ', id(locals))


>>> print("Free variables: ", func.__code__.co_names)
>>> print("Local variables: ", func.__code__.co_varnames)

Free variables: ('print', 'locals', 'id')
Local variables: ('b', 'c')


2. The documentation has a note that "The contents of this dictionary
should not be modified". Which implies that it is a read only mapping. So
the question why it is `dict` instead of `types.MappingProxyType`?

3. There is one more moment: local variables had been determined when
function was compiled. But `locals` returns _some_ current runtime copy. I
find this also confusing:


>>> def func1():

loc = locals()

b = 12

return loc


>>> def func2():

b = 12

loc = locals()

return loc


>>> func1()
{ }
>>> func2()
{'b': 12}


With kind regards,
-gdg
-- 
https://mail.python.org/mailman/listinfo/python-list


Implicit conversion to str in str.join method?

2018-02-26 Thread Kirill Balunov
Currently `str.join` raises `TypeError` if there are any non-string values
in iterable, including `bytes` objects. Is it an awful idea to implicitly
_cast_ elements in iterable to their `str` or `repr` representation? Was
this question adressed before?

As for me there are two valid points: On one hand "Explicit is beter than
implicit" and on the other "Practicality beats purity". May be I'm the only
one who finds that it is rather boring to write somehting like:

", ".join(str(i) for i in iterable)

when iterable contains non-string values, instead of:

", ".join(iterable)

I don't know how much overhead will yield for the case when iterable
contains only strings...and if it is possible to optimize this case. This
change is backward compatible, but as I wrote above, it can be perceived
badly and yield a huge overhead for general case that it is not even worth
discussing. What do you think?

With kind regards,
-gdg
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Rick Johnson
On Monday, February 26, 2018 at 4:39:22 AM UTC-6, Steven D'Aprano wrote:
> On Sun, 25 Feb 2018 19:26:12 -0800, Rick Johnson wrote:
>
> > On Friday, February 23, 2018 at 8:48:55 PM UTC-6, Steven D'Aprano wrote:
> > [...]
> > > Take the Fibonacci double-recursion benchmark. Okay, it
> > > tests how well your language does at making millions of
> > > function calls. Why?
> >
> > Because making "millons of function calls" is what
> > software *DOES*!
>
> You're right -- I worded that badly, and ended up saying
> something I didn't really mean. Mea culpa.  Of course over
> the course of the entire program run, most non-trivial
> programmers will end up having millions (if not billions)
> of function calls *in total*. But they're not all happening
> *together*.

So what? Latency is latency. And whether it occurs over the
course of one heavily recursive algorithm that constitutes
the depth and breadth of an entire program (a la fib()), or
it is the incremental cumulative consequence of the entire
program execution, the fact remains that function call
overhead contributes to a significant portion of the latency
inherent in some trivial, and *ALL* non-trivial, modern
software.

>
> What I tried to get across is, how often do we use millions
> of function calls to get one value?

All the time! For, in the abstract, the fundamental function
of software is to extract a "value" from one or more inputs
-- is it not? So, whether that "value" be: (1) a document in
an office productivity suite, or (2) a flight path for a
mars lander or a jumbo jet or child's quad-copter, or (3) a
modified image in a image processing program, or (4) a
design drawing or technical schematic for a mars rover bot,
or (5) an HD quality streaming porno flick, or yes, (6) even
a recursive function which unwittingly underscores some of
the less attractive aspects of the Python language (aka:
function call overhead!) -- all of these examples, and
countless others, extract a value from inputs. Of course,
much like physical traits i suppose, some "values" are more
desirable than others.

>
> By default, Python will only allow one thousand function
> calls in a stack before raising RecursionError.

By _default_, yes.

>
> py> def bad():
> ... return bad()
> ...
> py> bad()
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "", line 2, in bad
>   [ previous line repeats 998 times ]
> RecursionError: maximum recursion depth exceeded
>
>
> There's nothing unique about recursion that will trigger
> this error. Any call stack of more than 1000 function calls
> will do it. So forget about code getting a million
> functions deep. The average is probably more like a dozen,
> perhaps a hundred tops.

I'm very glad you brought this up, because it proves my main
point that, Python's maximum recursion error is one feature
they got _right_. If you don't like the default recursion
limit of 1000, or maybe 1000 recursions is breaking a valid
recursive algorithm, you can set the recursion limit to
whatever you like...

## Python 2 ##
>>> import sys
>>> sys.setrecursionlimit

>>> sys.setrecursionlimit(10)
>>> count = 1
>>> def bad():
... global count
... print count
... count += 1
... bad()
...
>>> bad()
1
2
3
4
5
6
7
8
9
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 5, in bad
  File "", line 5, in bad
  File "", line 5, in bad
  File "", line 5, in bad
  File "", line 5, in bad
  File "", line 5, in bad
  File "", line 5, in bad
  File "", line 5, in bad
  File "", line 5, in bad
RuntimeError: maximum recursion depth exceeded

It is however unfortunate that we get slamed with N
recursive exception messages :-(, but hey, at least we can
modify the maximum recursion limit! It's a step in the right
direction. :-)

> [...]
> > > For most application code, executing the function is far
> > > more costly than the overhead of calling it,
> >
> > What? Your functions are only called _once_ during the
> > lifetime of your code execution? Enough with the leg
> > pulling.
>
> Let me explain what I intended to say.  Here is a really
> poor estimate of the overhead of calling a function on my
> computer, measured in iPython.
>
> [...snip valid examples...]
>
> Now I know that this is not always the case. But I maintain
> that for *most* (but not all) practical, real-world code
> that actually does something useful, the overhead of
> calling the functions is *usually* (but not always) low
> compared to the cost of actually doing whatever it is that
> the functions do.

True. But again you failed to address my main point that:
"Lazy features (when feasible) must be offered
_optionally_".

Yes, function call overhead may be tiny in relation to the
code encapsulated within (at least for non-trivial code),
but the fact remains that function calls are inherent in
modern software, and as 

Re: Implicit conversion to str in str.join method?

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 6:38 AM, Kirill Balunov  wrote:
> Currently `str.join` raises `TypeError` if there are any non-string values
> in iterable, including `bytes` objects. Is it an awful idea to implicitly
> _cast_ elements in iterable to their `str` or `repr` representation? Was
> this question adressed before?
>
> As for me there are two valid points: On one hand "Explicit is beter than
> implicit" and on the other "Practicality beats purity". May be I'm the only
> one who finds that it is rather boring to write somehting like:
>
> ", ".join(str(i) for i in iterable)
>
> when iterable contains non-string values, instead of:
>
> ", ".join(iterable)
>
> I don't know how much overhead will yield for the case when iterable
> contains only strings...and if it is possible to optimize this case. This
> change is backward compatible, but as I wrote above, it can be perceived
> badly and yield a huge overhead for general case that it is not even worth
> discussing. What do you think?

This would be a perfect job for map.

", ".join(map(str, iterable))

If this is for display, you could also just print the values directly:

print(*iterable, sep=", ")

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 6:37 AM, Rick Johnson
 wrote:
> On Monday, February 26, 2018 at 4:39:22 AM UTC-6, Steven D'Aprano wrote:
>> On Sun, 25 Feb 2018 19:26:12 -0800, Rick Johnson wrote:
>>
>> > On Friday, February 23, 2018 at 8:48:55 PM UTC-6, Steven D'Aprano wrote:
>> > [...]
>> > > Take the Fibonacci double-recursion benchmark. Okay, it
>> > > tests how well your language does at making millions of
>> > > function calls. Why?
>> >
>> > Because making "millons of function calls" is what
>> > software *DOES*!
>>
>> You're right -- I worded that badly, and ended up saying
>> something I didn't really mean. Mea culpa.  Of course over
>> the course of the entire program run, most non-trivial
>> programmers will end up having millions (if not billions)
>> of function calls *in total*. But they're not all happening
>> *together*.
>
> So what? Latency is latency. And whether it occurs over the
> course of one heavily recursive algorithm that constitutes
> the depth and breadth of an entire program (a la fib()), or
> it is the incremental cumulative consequence of the entire
> program execution, the fact remains that function call
> overhead contributes to a significant portion of the latency
> inherent in some trivial, and *ALL* non-trivial, modern
> software.

By saying "the fact remains", you're handwaving away the work of
actually measuring that function call overhead is "significant". Can
you show me those numbers? Steve's point is that it is NOT
significant, because non-toy functions have non-trivial bodies. If you
wish to disagree, you have to demonstrate that the function call is
*itself* costly, even when there's a real body to it.

> I'm very glad you brought this up, because it proves my main
> point that, Python's maximum recursion error is one feature
> they got _right_. If you don't like the default recursion
> limit of 1000, or maybe 1000 recursions is breaking a valid
> recursive algorithm, you can set the recursion limit to
> whatever you like...
>
> ## Python 2 ##
> >>> import sys
> >>> sys.setrecursionlimit
> 
> >>> sys.setrecursionlimit(10)
> >>> count = 1
> >>> def bad():
> ... global count
> ... print count
> ... count += 1
> ... bad()
> ...
> >>> bad()
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> 8
> 9
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "", line 5, in bad
>   File "", line 5, in bad
>   File "", line 5, in bad
>   File "", line 5, in bad
>   File "", line 5, in bad
>   File "", line 5, in bad
>   File "", line 5, in bad
>   File "", line 5, in bad
>   File "", line 5, in bad
> RuntimeError: maximum recursion depth exceeded
>
> It is however unfortunate that we get slamed with N
> recursive exception messages :-(, but hey, at least we can
> modify the maximum recursion limit! It's a step in the right
> direction. :-)

Ah, been a while since you tried Python 3, is it? :)

  [Previous line repeated X more times]

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


Re: Implicit conversion to str in str.join method?

2018-02-26 Thread Kirill Balunov
>
> print(*iterable, sep=", ")


Thanks, I apologize :-) and why I always manage to find complicated ways...

With kind regards,
-gdg

2018-02-26 22:43 GMT+03:00 Chris Angelico :

> On Tue, Feb 27, 2018 at 6:38 AM, Kirill Balunov 
> wrote:
> > Currently `str.join` raises `TypeError` if there are any non-string
> values
> > in iterable, including `bytes` objects. Is it an awful idea to implicitly
> > _cast_ elements in iterable to their `str` or `repr` representation? Was
> > this question adressed before?
> >
> > As for me there are two valid points: On one hand "Explicit is beter than
> > implicit" and on the other "Practicality beats purity". May be I'm the
> only
> > one who finds that it is rather boring to write somehting like:
> >
> > ", ".join(str(i) for i in iterable)
> >
> > when iterable contains non-string values, instead of:
> >
> > ", ".join(iterable)
> >
> > I don't know how much overhead will yield for the case when iterable
> > contains only strings...and if it is possible to optimize this case. This
> > change is backward compatible, but as I wrote above, it can be perceived
> > badly and yield a huge overhead for general case that it is not even
> worth
> > discussing. What do you think?
>
> This would be a perfect job for map.
>
> ", ".join(map(str, iterable))
>
> If this is for display, you could also just print the values directly:
>
> print(*iterable, sep=", ")
>
> ChrisA
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Implicit conversion to str in str.join method?

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 6:54 AM, Kirill Balunov  wrote:
>> print(*iterable, sep=", ")
>
>
> Thanks, I apologize :-) and why I always manage to find complicated ways...

Hey, that's why we have the list :) I call this a success.

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


Re: Implicit conversion to str in str.join method?

2018-02-26 Thread Grant Edwards

On 2018-02-26, Kirill Balunov  wrote:
> Currently `str.join` raises `TypeError` if there are any non-string values
> in iterable, including `bytes` objects. Is it an awful idea to implicitly
> _cast_ elements in iterable to their `str` or `repr` representation?

Yes, that's an awful idea.  PHP pulls stunts like that behind your
back, and it's a huge source of bugs.

-- 
Grant Edwards   grant.b.edwardsYow! Let's all show human
  at   CONCERN for REVERAND MOON's
  gmail.comlegal difficulties!!

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread marco . nawijn
On Monday, February 26, 2018 at 3:44:14 PM UTC+1, Steven D'Aprano wrote:
> I have a class with a large number of parameters (about ten) assigned in 
> `__init__`. The class then has a number of methods which accept 
> *optional* arguments with the same names as the constructor/initialiser 
> parameters. If those arguments are None, the defaults are taken from the 
> instance attributes.
> 
> An example might be something like this:
> 
> 
> class Foo:
> def __init__(self, bashful, doc, dopey, grumpy, 
>happy, sleepy, sneezy):
> self.bashful = bashful  # etc
> 
> def spam(self, bashful=None, doc=None, dopey=None, 
>grumpy=None, happy=None, sleepy=None,
>sneezy=None):
> if bashful is None:
> bashful = self.bashful
> if doc is None:
> doc = self.doc
> if dopey is None:
> dopey = self.dopey
> if grumpy is None:
> grumpy = self.grumpy
> if happy is None:
> happy = self.happy
> if sleepy is None:
> sleepy = self.sleepy
> if sneezy is None:
> sneezy = self.sneezy
> # now do the real work...
> 
> def eggs(self, bashful=None, # etc... 
>):
> if bashful is None:
> bashful = self.bashful
> # and so on
>  
> 
> There's a lot of tedious boilerplate repetition in this, and to add 
> insult to injury the class is still under active development with an 
> unstable API, so every time I change one of the parameters, or add a new 
> one, I have to change it in over a dozen places.
> 
> Is there a good fix for this to reduce the amount of boilerplate?
> 
> 
> Thanks,
> 
> 
> 
> -- 
> Steve

What about something along these lines:

from inspect import getargspec, getargvalues


class Demo(object):

def __init__(self, a=None, b=10, c='oops'):
spec = getargspec(self.__init__)
for key, value in zip(spec.args[1:], spec.defaults):
setattr(self, key, value)

def foo(self, *args, **kwargs):
assert len(args) == 0

for k, v in kwargs.items():
try:
getattr(self, k)
except AttributeError:
print('*** error: attribute {} does not exist.'.format(k))

setattr(self, k, v)


d = Demo()
print(d.a)
d.foo(a=3.14)
print(d.a)

d.foo(q='this will raise')

So, use the inspect module to detect the valid arguments
from the class initializer. Then use **kwargs in every 
class method. It would be nice if the full method signature
can be kept, but I have not yet figured out if this is
possible. 

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 19:50, Chris Angelico wrote:

On Tue, Feb 27, 2018 at 6:37 AM, Rick Johnson



So what? Latency is latency. And whether it occurs over the
course of one heavily recursive algorithm that constitutes
the depth and breadth of an entire program (a la fib()), or
it is the incremental cumulative consequence of the entire
program execution, the fact remains that function call
overhead contributes to a significant portion of the latency
inherent in some trivial, and *ALL* non-trivial, modern
software.


Take the last bit of Python I posted, which was that RNG test.

It uses this function:

  def i64(x): return x & 0x

This is a small function, but it can't be a toy one as it was suggested 
by Ned Batchelder. And the test program wasn't at all recursive.



Running the program with N=10_000_000 took 46 seconds.

Replacing the i64() call with '&m' (where m is a global set to 
0x), it took 38 seconds.


So putting that fix into a function, which is convenient for coding, 
maintenance and readability, cost 20% in runtime.


Going the other way, having i64() call another function i64a() which 
does the work, common when using wrapper functions, it took 60 seconds. 
A 30% slowdown, even though most of the work is doing numeric shifts and 
adds.


So function calls do seem to be expensive operations in CPython, and any 
benchmarks which highlight that fact should be welcomed.


(Note than none of this seems to affect PyPy, which ran at the same 
speed with i64(), without it, or with both i64() and i64a().)


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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 26/02/2018 20:27, bartc wrote:

On 26/02/2018 19:50, Chris Angelico wrote:

On Tue, Feb 27, 2018 at 6:37 AM, Rick Johnson



So what? Latency is latency. And whether it occurs over the
course of one heavily recursive algorithm that constitutes
the depth and breadth of an entire program (a la fib()), or
it is the incremental cumulative consequence of the entire
program execution, the fact remains that function call
overhead contributes to a significant portion of the latency
inherent in some trivial, and *ALL* non-trivial, modern
software.


[Sorry, the bit of your (Chris') post I replied to got chopped by 
mistake. Here is my post again with the right context:]


CA:
> By saying "the fact remains", you're handwaving away the work of
> actually measuring that function call overhead is "significant". Can
> you show me those numbers? Steve's point is that it is NOT
> significant, because non-toy functions have non-trivial bodies. If you
> wish to disagree, you have to demonstrate that the function call is
> *itself* costly, even when there's a real body to it.
>

Take the last bit of Python I posted, which was that RNG test.

It uses this function:

  def i64(x): return x & 0x

This is a small function, but it can't be a toy one as it was suggested 
by Ned Batchelder. And the test program wasn't at all recursive.



Running the program with N=10_000_000 took 46 seconds.

Replacing the i64() call with '&m' (where m is a global set to 
0x), it took 38 seconds.


So putting that fix into a function, which is convenient for coding, 
maintenance and readability, cost 20% in runtime.


Going the other way, having i64() call another function i64a() which 
does the work, common when using wrapper functions, it took 60 seconds. 
A 30% slowdown, even though most of the work is doing numeric shifts and 
adds.


So function calls do seem to be expensive operations in CPython, and any 
benchmarks which highlight that fact should be welcomed.


(Note than none of this seems to affect PyPy, which ran at the same 
speed with i64(), without it, or with both i64() and i64a().)


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


Re: For Loop Dilema [python-list]

2018-02-26 Thread arya . kumar2494
On Monday, February 26, 2018 at 12:57:25 PM UTC+5:30, Chris Angelico wrote:
> On Mon, Feb 26, 2018 at 5:19 AM,   wrote:
> > Why we don’t use:
> >
> > for _ in _ in _
> >
> > Instead of
> >
> > for _ in _:
> > for _ in _:
> >
> > Ex:
> >
> > Names = ["Arya","Pupun"]
> >
> > for name in Names:
> >for c in name:
> >print(c)
> >
> > instead use:
> >
> > for c in name in Names:
> > print(c)
> 
> Because programming is all about building up a program from
> primitives. The number of times when we need this kind of nested loop
> (with absolutely nothing in between the loops) is way too small to
> justify dedicated syntax.
> 
> ChrisA

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Rick Johnson
On Monday, February 26, 2018 at 8:44:14 AM UTC-6, Steven D'Aprano wrote:
> I have a class with a large number of parameters (about
> ten) assigned in `__init__`. The class then has a number of
> methods which accept *optional* arguments with the same
> names as the constructor/initialiser parameters. If those
> arguments are None, the defaults are taken from the
> instance attributes.
>
> An example might be something like this:
>
> class Foo:
> def __init__(self, bashful, doc, dopey, grumpy,
>happy, sleepy, sneezy):
> self.bashful = bashful  # etc
>
> def spam(self, bashful=None, doc=None, dopey=None,
>grumpy=None, happy=None, sleepy=None,
>sneezy=None):
> if bashful is None:
> bashful = self.bashful
> if doc is None:
> doc = self.doc
> if dopey is None:
> dopey = self.dopey
> if grumpy is None:
> grumpy = self.grumpy
> if happy is None:
> happy = self.happy
> if sleepy is None:
> sleepy = self.sleepy
> if sneezy is None:
> sneezy = self.sneezy
> # now do the real work...
>
> def eggs(self, bashful=None, # etc...
>):
> if bashful is None:
> bashful = self.bashful
> # and so on


Steven... even if this example code is absolutely atrocious
(because it is!), and even *IF* i have a uneasy suspicion
that this "inquiry" masks some dastardly malicious plan
(because i do!), I must admit, I am happy to see that you
are _finally_ embracing the OOP paradigm.

For starters, I would suggest replacing those ugly if-
clauses with some short-circuit or'd-logic. But obviously
you need to run that "paragraph of arguments" through a
single helper function, as the point of "DRY" is "Don't
Repeat Yourself".



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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Ian Kelly
On Mon, Feb 26, 2018 at 1:09 PM,   wrote:
> def foo(self, *args, **kwargs):
> assert len(args) == 0

Better:

def foo(self, **kwargs):

> So, use the inspect module to detect the valid arguments
> from the class initializer. Then use **kwargs in every
> class method. It would be nice if the full method signature
> can be kept, but I have not yet figured out if this is
> possible.

https://pypi.python.org/pypi/decorator/4.2.1
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: matrix multiplication

2018-02-26 Thread Dan Stromberg
On Mon, Feb 26, 2018 at 8:53 AM, Seb  wrote:
> On Sun, 25 Feb 2018 18:52:14 -0500,
> Terry Reedy  wrote:
>
> [...]
>
>> numpy has a matrix multiply function and now the '@' matrix multiply
>> operator.
>
> Yes, but what I was wondering is whether there's a faster way of
> multiplying each row (1x3) of a matrix by another matrix (3x3), compared
> to looping through the matrix row by row as shown in the code.  Perhaps
> I'm not understanding how to use the broadcasting features of `matmul`.

I'm a bit of a numpy newb, but this sounds like numpy's "broadcasting" feature:
http://lmgtfy.com/?q=numpy+broadcasting
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Ian Kelly
On Mon, Feb 26, 2018 at 2:37 PM, Ian Kelly  wrote:
> On Mon, Feb 26, 2018 at 1:09 PM,   wrote:
>> def foo(self, *args, **kwargs):
>> assert len(args) == 0
>
> Better:
>
> def foo(self, **kwargs):
>
>> So, use the inspect module to detect the valid arguments
>> from the class initializer. Then use **kwargs in every
>> class method. It would be nice if the full method signature
>> can be kept, but I have not yet figured out if this is
>> possible.
>
> https://pypi.python.org/pypi/decorator/4.2.1

Also, in Python 3.4+ you can just create a Signature object (either
from scratch or by calling inspect.signature()) and then assign it to
the function's __signature__ attribute.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: matrix multiplication

2018-02-26 Thread Ian Kelly
On Mon, Feb 26, 2018 at 2:40 PM, Dan Stromberg  wrote:
> On Mon, Feb 26, 2018 at 8:53 AM, Seb  wrote:
>> On Sun, 25 Feb 2018 18:52:14 -0500,
>> Terry Reedy  wrote:
>>
>> [...]
>>
>>> numpy has a matrix multiply function and now the '@' matrix multiply
>>> operator.
>>
>> Yes, but what I was wondering is whether there's a faster way of
>> multiplying each row (1x3) of a matrix by another matrix (3x3), compared
>> to looping through the matrix row by row as shown in the code.  Perhaps
>> I'm not understanding how to use the broadcasting features of `matmul`.
>
> I'm a bit of a numpy newb, but this sounds like numpy's "broadcasting" 
> feature:
> http://lmgtfy.com/?q=numpy+broadcasting

Taking LMGTFY to a whole new level of rudeness by obviously not even
bothering to read the entire paragraph before responding.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: matrix multiplication

2018-02-26 Thread Dan Stromberg
On Mon, Feb 26, 2018 at 2:07 PM, Ian Kelly  wrote:
> On Mon, Feb 26, 2018 at 2:40 PM, Dan Stromberg  wrote:
>> On Mon, Feb 26, 2018 at 8:53 AM, Seb  wrote:
>>> On Sun, 25 Feb 2018 18:52:14 -0500,
>>> Terry Reedy  wrote:
>>>
>>> [...]
>>>
 numpy has a matrix multiply function and now the '@' matrix multiply
 operator.
>>>
>>> Yes, but what I was wondering is whether there's a faster way of
>>> multiplying each row (1x3) of a matrix by another matrix (3x3), compared
>>> to looping through the matrix row by row as shown in the code.  Perhaps
>>> I'm not understanding how to use the broadcasting features of `matmul`.
>>
>> I'm a bit of a numpy newb, but this sounds like numpy's "broadcasting" 
>> feature:
>> http://lmgtfy.com/?q=numpy+broadcasting
>
> Taking LMGTFY to a whole new level of rudeness by obviously not even
> bothering to read the entire paragraph before responding.

Is LMGTFY rude?  I think maybe it was back when it said "Now, was that
so hard?", but today there's no snarkiness to be found on the site,
AFAIK.

Also, like I said, I'm a numpy newbie.  If I misunderstood the
question, that's probably why.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Ben Finney
Steven D'Aprano  writes:

> I have a class with a large number of parameters (about ten) assigned
> in `__init__`. The class then has a number of methods which accept
> *optional* arguments with the same names as the
> constructor/initialiser parameters. If those arguments are None, the
> defaults are taken from the instance attributes.

The catalogue in Refactoring identifies what you need:

Introduce Parameter Object

You have a group of parameters that naturally go together.

Replace them with an object.

https://refactoring.com/catalog/introduceParameterObject.html>

Applying that to your example::

class Foo:

def __init__(self, wibble_param, dwarves, wobble_param):
do_stuff_with(wibble_param)
self.dwarves = dwarves
do_other_stuff_with(wobble_param)

def spam(self, dwarves=None):
if dwarves is None:
dwarves = self.dwarves

# … now do the real spam work …

def eggs(self, dwarves=None):
if dwarves is None:
dwarves = self.dwarves

# … now do the real eggs work …

> […] to add insult to injury the class is still under active
> development with an unstable API, so every time I change one of the
> parameters, or add a new one, I have to change it in over a dozen
> places.

By encapsulating those parameters that all belong together, you can
change that set of parameters (by changing what ‘dwarves’ gets passed
around) and the function signatures don't change.

-- 
 \“All opinions are not equal. Some are a very great deal more |
  `\   robust, sophisticated, and well supported in logic and argument |
_o__) than others.” —Douglas Adams |
Ben Finney

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


Re: matrix multiplication

2018-02-26 Thread Ian Kelly
On Mon, Feb 26, 2018 at 3:12 PM, Dan Stromberg  wrote:
> On Mon, Feb 26, 2018 at 2:07 PM, Ian Kelly  wrote:
>> Taking LMGTFY to a whole new level of rudeness by obviously not even
>> bothering to read the entire paragraph before responding.
>
> Is LMGTFY rude?  I think maybe it was back when it said "Now, was that
> so hard?", but today there's no snarkiness to be found on the site,
> AFAIK.

Maybe it's gotten less condescending since the last time I followed
such a link. It is notably disallowed on Stack Overflow for the reason
of being considered impolite.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: help me ?

2018-02-26 Thread ziggyvimar
On Monday, February 26, 2018 at 9:40:54 AM UTC, Negru Popi wrote:
> Define 2 lists. The first one must contain the integer values 1, 2 and 3 and 
> the second one the string values a, b and c. Iterate through both lists to 
> create another list that contains all the combinations of the A and B 
> elements. The final list should look like one of the 2 lists:
> 1. [1a, 1b, 1c, 2a, 2b, 2c, 3a, 3b, 3c]
> 2. [a1, a2. a3, b1, b2, b3, c1, c2, c3]
> BONUS: Make the final list contain all possible combinations : [1a, a1, 1b, 
> b1, 1c, c1, 2a, a2, 2b, b2, 2c, c2, 3a, a3, 3b, b3, 3c, c3] 
> 
> Help me !

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


Re: matrix multiplication

2018-02-26 Thread Gregory Ewing

Seb wrote:

I was wondering is whether there's a faster way of
multiplying each row (1x3) of a matrix by another matrix (3x3), compared
to looping through the matrix row by row as shown in the code.


Just multiply the two matrices together.

If A is an nx3 matrix and B is a 3x3 matrix, then
C = A @ B is an nx3 matrix where C[i] = A[i] @ B.

(This is a property of matrix multiplication in
general, nothing special about numpy.)

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread MRAB

On 2018-02-26 21:12, Rick Johnson wrote:

On Monday, February 26, 2018 at 8:44:14 AM UTC-6, Steven D'Aprano wrote:

I have a class with a large number of parameters (about
ten) assigned in `__init__`. The class then has a number of
methods which accept *optional* arguments with the same
names as the constructor/initialiser parameters. If those
arguments are None, the defaults are taken from the
instance attributes.

An example might be something like this:

class Foo:
def __init__(self, bashful, doc, dopey, grumpy,
   happy, sleepy, sneezy):
self.bashful = bashful  # etc

def spam(self, bashful=None, doc=None, dopey=None,
   grumpy=None, happy=None, sleepy=None,
   sneezy=None):
if bashful is None:
bashful = self.bashful
if doc is None:
doc = self.doc
if dopey is None:
dopey = self.dopey
if grumpy is None:
grumpy = self.grumpy
if happy is None:
happy = self.happy
if sleepy is None:
sleepy = self.sleepy
if sneezy is None:
sneezy = self.sneezy
# now do the real work...

def eggs(self, bashful=None, # etc...
   ):
if bashful is None:
bashful = self.bashful
# and so on



Steven... even if this example code is absolutely atrocious
(because it is!), and even *IF* i have a uneasy suspicion
that this "inquiry" masks some dastardly malicious plan
(because i do!), I must admit, I am happy to see that you
are _finally_ embracing the OOP paradigm.

For starters, I would suggest replacing those ugly if-
clauses with some short-circuit or'd-logic. But obviously
you need to run that "paragraph of arguments" through a
single helper function, as the point of "DRY" is "Don't
Repeat Yourself".

Before using or'd-logic, you need to know whether the value could be 
falsey, e.g. 0.






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


Re: Questions about `locals` builtin

2018-02-26 Thread Terry Reedy

On 2/26/2018 1:55 PM, Kirill Balunov wrote:

Hi,

I am a little bit confused with `locals` builtin in these moments:

1. The documentation says that _free varaibles_ are returned, which seems
incorrect description. In my mind the term free variable refers to
variables used in a function that are not local variables nor parameters of
that function.


I disagree with the terminology used in this section of the docs, so I 
won't defend or explain.


The important points are that 1. *Python* code is that executed in the 
context of multiple directly accessible namespaces; 2. there is more 
than one way to implement a namespace; 3. the Python namespace system 
has grown in complexity since the beginning; and 4. some details depend 
on the implementation (CPython versus others) and Python and therefore 
implementation version.


The point of point 3 is that terminology and details would likely be 
different if Python were freshly designed more or less as it is today, 
and some things only make more or less sense in historical context. 
Learn what you need to know to write code that works.


The program namespace is called 'builtins'.  Treat it as readonly.  The 
namespace, as opposed to its contents, cannot be accessed unless imported.


Each module namespace is accessed as globals().  It must be a dict.  The 
names of builtins are accessed as it they were in globals, even though, 
in CPython, they are not.  (I believe 'globals' predates multi-module 
programs.)


The local namespace is the default recipient of name bindings from 
assignment, class, and def statements.


At module scope, the local namespace is the module or global namespace. 
A binding in module locals == globals can mask a builtin.  'def print(): 
pass'.  Deletion of that binding unmasks the builtin.  'del print'.  (If 
an implementation actually initialized each globals() by copying 
builtins, then each deletion would have to check for possible unmasking.)


Class statements get a new local namespace, which defaults to some sort 
of mapping.  When the class statement finishes, the local names become 
class attributes.


Be default, function local namespaces in CPython are implemented as 
arrays, with local names compiles as indexes in the array.


Calling surrounding function local names collectively 'nonlocals' is the 
result of months of bikeshedding.


--
Terry Jan Reedy

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


Re: Questions about `locals` builtin

2018-02-26 Thread Steven D'Aprano
On Mon, 26 Feb 2018 21:55:35 +0300, Kirill Balunov wrote:

> Hi,
> 
> I am a little bit confused with `locals` builtin in these moments:
> 
> 1. The documentation says that _free varaibles_ are returned, which
> seems incorrect description.

I can't answer that, sorry.


> 2. The documentation has a note that "The contents of this dictionary
> should not be modified". Which implies that it is a read only mapping.
> So the question why it is `dict` instead of `types.MappingProxyType`?

Mostly because locals() predates MappingProxyType by many years, and also 
because that restriction doesn't apply to other implementations of Python 
such as Jython and IronPython.

In CPython, the dict returned by locals() is a copy of the local 
namespace, so modifying the dict doesn't modify the real local variables.

(Well, sometimes it does, but not always. The story in Python 2 is really 
complex.)

But in Jython and IronPython, it actually is the namespace, so writing to 
it works like writing to globals.

So writing to locals *sometimes* works, and cannot be prohibited 
outright, but if you want portable code, you have to avoid it.


> 3. There is one more moment: local variables had been determined when
> function was compiled. But `locals` returns _some_ current runtime copy.

Have you tried it in Python 2 or 3? The behaviour may be less confusing 
in 3.



-- 
Steve

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Rick Johnson
On Monday, February 26, 2018 at 5:44:18 PM UTC-6, MRAB wrote:
[...]
> Before using or'd-logic, you need to know whether the value
> could be falsey, e.g. 0.

True. However. Steven failed to provide any info that might
help us determine the types of these parameters, and as
such, i was forced to take the liberty of assumption. Now,
while it's quite possible someone could assign dwarfy-named-
symbols to implicit or explicit boolean values, i find it
highly unlikely, and totally unintuitive. But then again, i
have my suspicions about ths thread. ;-)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Steven D'Aprano
On Tue, 27 Feb 2018 02:09:53 +1100, Chris Angelico wrote:

> You're still reimplementing the C code in Python, which is inefficient.
> Have you considered going back to the *actual algorithm* and
> implementing that idiomatically in Python? I think you'll find that (a)
> the code is more readable, and (b) the run time is much lower.

Chris, I think this is incredibly optimistic, if not naive. We're talking 
about a PRNG by Marsaglia, so my guess is that the "original algorithm" 
*is* the C code. Or possibly Fortran.

Even if not, even if there is actually a language-neutral algorithm, its 
a PRNG which means its going to be filled with bit-twiddling and number-
crunching operations. Pure Python without a JIT is never going to be 
competitive with C or Fortran for code like that.


-- 
Steve

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 11:17 AM, Steven D'Aprano
 wrote:
> On Tue, 27 Feb 2018 02:09:53 +1100, Chris Angelico wrote:
>
>> You're still reimplementing the C code in Python, which is inefficient.
>> Have you considered going back to the *actual algorithm* and
>> implementing that idiomatically in Python? I think you'll find that (a)
>> the code is more readable, and (b) the run time is much lower.
>
> Chris, I think this is incredibly optimistic, if not naive. We're talking
> about a PRNG by Marsaglia, so my guess is that the "original algorithm"
> *is* the C code. Or possibly Fortran.
>
> Even if not, even if there is actually a language-neutral algorithm, its
> a PRNG which means its going to be filled with bit-twiddling and number-
> crunching operations. Pure Python without a JIT is never going to be
> competitive with C or Fortran for code like that.
>

I may have been a little unclear. It's highly unlikely that the run
time of the properly-implemented Python code will be lower than the
original C or Fortran. But it most certainly CAN be more efficient
than the Python reimplementation of the C implementation, which would
narrow the gap considerably. Implementing Python idiotically instead
of idiomatically gives you suboptimal performance.

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


Re: Questions about `locals` builtin

2018-02-26 Thread Dan Stromberg
On Mon, Feb 26, 2018 at 4:25 PM, Steven D'Aprano
 wrote:
> On Mon, 26 Feb 2018 21:55:35 +0300, Kirill Balunov wrote:
>> 2. The documentation has a note that "The contents of this dictionary
>> should not be modified". Which implies that it is a read only mapping.
>> So the question why it is `dict` instead of `types.MappingProxyType`?
>
> Mostly because locals() predates MappingProxyType by many years, and also
> because that restriction doesn't apply to other implementations of Python
> such as Jython and IronPython.
>
> In CPython, the dict returned by locals() is a copy of the local
> namespace, so modifying the dict doesn't modify the real local variables.
>
> (Well, sometimes it does, but not always. The story in Python 2 is really
> complex.)
>
> But in Jython and IronPython, it actually is the namespace, so writing to
> it works like writing to globals.
>
> So writing to locals *sometimes* works, and cannot be prohibited
> outright, but if you want portable code, you have to avoid it.

I find this interesting.

So I decided to write a little test program, to see it first hand.

I don't have IronPython handy, but according my (quite possibly
flawed) test program, locals() is a copy on CPython 3, CPython 2,
Pypy3, Pypy, Jython and MicroPython.

I didn't see any interpreters that returned the namespace itself.

What am I missing?

Here's the test program.  Perhaps there's something wrong in it?

#!/usr/local/cpython-3.6/bin/python3

"""Test whether locals() is a copy of the local namespace, or a reference."""

import sys


def main():
"""Run the test."""
var = 1

locs = locals()
locs['var'] = 2

if var == 2:
sys.stdout.write('locals not just a copy\n')
else:
sys.stdout.write('locals is just a copy\n')


main()
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Are the critiques in "All the things I hate about Python" valid?

2018-02-26 Thread Rick Johnson
On Tuesday, February 20, 2018 at 5:45:36 PM UTC-6, Steven D'Aprano wrote:
> On Tue, 20 Feb 2018 12:42:23 -0800, Rick Johnson wrote:
>
> > For instance, if the age is queried many times a second,
> > it would be a much wiser design to set-up an event that
> > will advance the age at the end of the last second of
> > every year
>
> Do you really mean to say that everybody in the world has
> their birthday on January 1st? We're not racehorses you
> know.


No, silly rabbit. I was thinking about the problem from a
_relative_ perspective, whereas you were thinking about the
problem from a _global_ perspective. Neither perspective is
wrong.

If you read my exact words again:

"a much wiser design to set-up an event that will advance
the age at the end of the last second of every year"

...you'll notice that i mentioned no specific date.

Therefore, "the last day of the year" (in relativistic
terms) is 11:59:59PM on the calendar day which _precedes_
the day of the month for which you were born.

So, for instance: if your birthday is January 25th 1969, the
last second of the last day of your _first_ year is January
24th 1970 @ 11:59:59PM. And the last second of the last day
of your _second_ year is January 24th 1971 @ 11:59:59PM. And
so forth...

Does this make sense?


>
> Under your scheme, 99.7% of records will return the wrong
> age (off by one) at least once per year. Statistically, 50%
> of queries will be wrong.


Can you whip-up a small code example which proves your
assertion? Hey, and feel free to include the seven dwarfs if
you like. ;-)

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


Re: matrix multiplication

2018-02-26 Thread Seb
On Tue, 27 Feb 2018 12:25:30 +1300,
Gregory Ewing  wrote:

> Seb wrote:
>> I was wondering is whether there's a faster way of multiplying each
>> row (1x3) of a matrix by another matrix (3x3), compared to looping
>> through the matrix row by row as shown in the code.

> Just multiply the two matrices together.

> If A is an nx3 matrix and B is a 3x3 matrix, then C = A @ B is an nx3
> matrix where C[i] = A[i] @ B.

> (This is a property of matrix multiplication in general, nothing
> special about numpy.)

I think that's only true if B is the same for every row in A.  In the
code I posted, B varies by row of A.

-- 
Seb

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread bartc

On 27/02/2018 00:35, Chris Angelico wrote:

On Tue, Feb 27, 2018 at 11:17 AM, Steven D'Aprano
 wrote:

On Tue, 27 Feb 2018 02:09:53 +1100, Chris Angelico wrote:


You're still reimplementing the C code in Python, which is inefficient.
Have you considered going back to the *actual algorithm* and
implementing that idiomatically in Python? I think you'll find that (a)
the code is more readable, and (b) the run time is much lower.


Chris, I think this is incredibly optimistic, if not naive. We're talking
about a PRNG by Marsaglia, so my guess is that the "original algorithm"
*is* the C code. Or possibly Fortran.

Even if not, even if there is actually a language-neutral algorithm, its
a PRNG which means its going to be filled with bit-twiddling and number-
crunching operations. Pure Python without a JIT is never going to be
competitive with C or Fortran for code like that.



I may have been a little unclear. It's highly unlikely that the run
time of the properly-implemented Python code will be lower than the
original C or Fortran. But it most certainly CAN be more efficient
than the Python reimplementation of the C implementation, which would
narrow the gap considerably. Implementing Python idiotically instead
of idiomatically gives you suboptimal performance.


Nonsense. You shouldn't need to care about such things. An algorithm is 
an algorithm. And the better ones should be easily written in any language.


This particular one, which was of interest because the calculations 
tended to overflow into undesirable bignums, is just a bunch of 
calculations. 'Bit-twiddling'.


Anyway, even this pure Python version can deliver pseudo random numbers 
at some 200,000 per second, while the built-in generator does 450,000 
per second, so it's not bad going.


Of course, the C version will generate them at over 100 million per second.

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


Re: How to make Python run as fast (or faster) than Julia

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 12:57 PM, bartc  wrote:
> On 27/02/2018 00:35, Chris Angelico wrote:
>>
>> On Tue, Feb 27, 2018 at 11:17 AM, Steven D'Aprano
>>  wrote:
>>>
>>> On Tue, 27 Feb 2018 02:09:53 +1100, Chris Angelico wrote:
>>>
 You're still reimplementing the C code in Python, which is inefficient.
 Have you considered going back to the *actual algorithm* and
 implementing that idiomatically in Python? I think you'll find that (a)
 the code is more readable, and (b) the run time is much lower.
>>>
>>>
>>> Chris, I think this is incredibly optimistic, if not naive. We're talking
>>> about a PRNG by Marsaglia, so my guess is that the "original algorithm"
>>> *is* the C code. Or possibly Fortran.
>>>
>>> Even if not, even if there is actually a language-neutral algorithm, its
>>> a PRNG which means its going to be filled with bit-twiddling and number-
>>> crunching operations. Pure Python without a JIT is never going to be
>>> competitive with C or Fortran for code like that.
>>>
>>
>> I may have been a little unclear. It's highly unlikely that the run
>> time of the properly-implemented Python code will be lower than the
>> original C or Fortran. But it most certainly CAN be more efficient
>> than the Python reimplementation of the C implementation, which would
>> narrow the gap considerably. Implementing Python idiotically instead
>> of idiomatically gives you suboptimal performance.
>
>
> Nonsense. You shouldn't need to care about such things. An algorithm is an
> algorithm. And the better ones should be easily written in any language.
>
> This particular one, which was of interest because the calculations tended
> to overflow into undesirable bignums, is just a bunch of calculations.
> 'Bit-twiddling'.
>
> Anyway, even this pure Python version can deliver pseudo random numbers at
> some 200,000 per second, while the built-in generator does 450,000 per
> second, so it's not bad going.

The built-in generator is using a completely different algorithm
though, so rate of generation isn't the entire story. How long is the
period of the one you're using? (How long before it loops?) If you
churn the generator to an arbitrary number and then take the next 100
values it generates, are they randomly distributed? Can you
reconstruct the RNG's internal state by watching it generate numbers
for a short while?

Obviously no PRNG is going to be perfect at this, but there are
certainly degrees of quality to be compared.

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


Re: Are the critiques in "All the things I hate about Python" valid?

2018-02-26 Thread Steven D'Aprano
On Mon, 26 Feb 2018 17:18:38 -0800, Rick Johnson wrote:

> On Tuesday, February 20, 2018 at 5:45:36 PM UTC-6, Steven D'Aprano
> wrote:
>> On Tue, 20 Feb 2018 12:42:23 -0800, Rick Johnson wrote:
>>
>> > For instance, if the age is queried many times a second, it would be
>> > a much wiser design to set-up an event that will advance the age at
>> > the end of the last second of every year
>>
>> Do you really mean to say that everybody in the world has their
>> birthday on January 1st? We're not racehorses you know.

[...]
 
> If you read my exact words again:
> 
> "a much wiser design to set-up an event that will advance the age at
> the end of the last second of every year"

Oh, you mean the exact same words already quoted above?

> ...you'll notice that i mentioned no specific date.

Yes you did: "the last second of every year" is always 23:59:59 of 31st 
December, and it is always the same time and date "every year". Just 
because you didn't explicitly state the name of a month doesn't mean you 
didn't implicitly specify one.

Perhaps you didn't *intend* to specify the last day of the year, in which 
case you ought to just accept that your writing wasn't as clear as you 
intended, instead of blaming others for failing to read your mind.



> Therefore, "the last day of the year" (in relativistic terms) is
> 11:59:59PM on the calendar day which _precedes_ the day of the month for
> which you were born.

Relativistic terms? You mean when travelling at 90% of the speed of light 
or in close orbit around a neutron star?

There are those language skills letting you down again :-P 

I think you mean *relative* terms.


[...]
>> Under your scheme, 99.7% of records will return the wrong age (off by
>> one) at least once per year. Statistically, 50% of queries will be
>> wrong.
> 
> 
> Can you whip-up a small code example which proves your assertion? Hey,
> and feel free to include the seven dwarfs if you like. ;-)

Under the racehorse scheme, 1/365 of your data will be born on the 1st of 
Jan, 1/365 on the 2nd Jan, and so on through 31st Dec. (Ignoring leap 
years.) Half of the data records will be updated early, and half will be 
updated late. Only those born on New Years Day (about 0.3% of the 
records) will be updated on the correct day. Hence 99.7% will be wrong 
for at least one day per year. If queries are made randomly, they'll be 
off by one 50% of the time.

Why 50%? 1/365 of your records will never be wrong, 1/365 will be wrong 
one day of the year, 1/365 will be wrong two days of the year, 1/365 will 
be wrong three days of the year, ... 1/365 will be wrong 364 days of the 
year. So on average, records are wrong 182 days of the year, which is 
close enough to half of 365. So if you query a random record on a random 
day, there's close enough to a fifty percent chance it will be off by one.

Now that I understand that you didn't intend this racehorse scheme, I'm 
not going to bother writing a simulation. But it is just simple 
statistics, assuming that the actual birthday is distributed randomly 
across the year, and assuming that queries for records come in at random 
times.

(And to be pedantic, I mean a uniform random distribution, and that 
queries and birthdays are independent.)



-- 
Steve

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


Re: Are the critiques in "All the things I hate about Python" valid?

2018-02-26 Thread Steven D'Aprano
On Mon, 26 Feb 2018 17:18:38 -0800, Rick Johnson wrote:

[...]
> So, for instance: if your birthday is January 25th 1969, the last second
> of the last day of your _first_ year is January 24th 1970 @ 11:59:59PM.
> And the last second of the last day of your _second_ year is January
> 24th 1971 @ 11:59:59PM. And so forth...
> 
> Does this make sense?

Indeed it does, and frankly, the Racehorse scheme is better.

At least with the Racehorse scheme, you only need to update the database 
once a year, at midnight on the new year, which hopefully is the quietest 
time of the year for you. You can lock access to the database, run the 
update, and hopefully be up and running again before anyone notices 
anything other than a minor outage.

With your scheme, well, I can think of a few ways to do it, none of which 
are good. A database expert might be able to think of some better ideas, 
but you might:

1. Run a separate scheduled job for each record, which does nothing but 
advance the age by one at a certain time, then sleep for a year. If you 
have ten million records, you need ten million scheduled jobs; I doubt 
many scheduling systems can cope with that many jobs. (But I welcome 
correction.)

Also, few scheduling systems guarantee that jobs will execute at 
*precisely* the time you expect. If the system is down at the time the 
job was scheduled to run, they may never run at all. So there is likely 
to be a lag between when you want the records updated, and when they 
actually are updated.

No, using scheduled jobs is fragile, and expensive.


Plan 2: have a single job that does nothing but scan the database, 
continuously in a loop, and if a record's birthdate is more than a year 
in the past, and hasn't been updated in the last year, update the age by 
one.

Actually, I think this sucks worse than the ten-million-scheduled-jobs 
idea. Hopefully it will be obvious why this idea is so awful.


Plan 3: have a trigger that runs whenever a record is queried or 
accessed. If the birthdate is more than a year in the past, and it has 
been more than a year since the last access, then update the age.

This at least doesn't *entirely* suck. But if you're going to go to the 
trouble of doing this on *every* access to the record, isn't it simpler 
to just make the age a computed field that calculates the age when needed?

The cost of computing the age is not that expensive, especially if you 
store the birthdate in seconds. It's just a subtraction, maybe followed 
by a division if you want the age in years. It hardly seems worthwhile 
storing the age as a pre-computed integer if you then need a cunning 
scheme to possibly update that integer on every access to the record.

I think that Rick's "optimization" here is a perfect example of 
pessimisation (making a program slower in the mistaken belief that you're 
making it faster). To quote W.A. Wulf:

"More computing sins are committed in the name of efficiency (without 
necessarily achieving it) than for any other single reason — including 
blind stupidity."



-- 
Steve

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


Re: Are the critiques in "All the things I hate about Python" valid?

2018-02-26 Thread Ian Kelly
On Mon, Feb 26, 2018 at 8:09 PM, Steven D'Aprano
 wrote:
> Yes you did: "the last second of every year" is always 23:59:59 of 31st
> December, and it is always the same time and date "every year".

Except when it's 23:59:60 or 23:59:61 (which hasn't yet happened but could).
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Are the critiques in "All the things I hate about Python" valid?

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 12:18 PM, Rick Johnson
 wrote:
> On Tuesday, February 20, 2018 at 5:45:36 PM UTC-6, Steven D'Aprano wrote:
>> On Tue, 20 Feb 2018 12:42:23 -0800, Rick Johnson wrote:
>>
>> > For instance, if the age is queried many times a second,
>> > it would be a much wiser design to set-up an event that
>> > will advance the age at the end of the last second of
>> > every year
>>
>> Do you really mean to say that everybody in the world has
>> their birthday on January 1st? We're not racehorses you
>> know.
>
>
> No, silly rabbit. I was thinking about the problem from a
> _relative_ perspective, whereas you were thinking about the
> problem from a _global_ perspective. Neither perspective is
> wrong.
>
> If you read my exact words again:
>
> "a much wiser design to set-up an event that will advance
> the age at the end of the last second of every year"
>
> ...you'll notice that i mentioned no specific date.
>
> Therefore, "the last day of the year" (in relativistic
> terms) is 11:59:59PM on the calendar day which _precedes_
> the day of the month for which you were born.
>
> So, for instance: if your birthday is January 25th 1969, the
> last second of the last day of your _first_ year is January
> 24th 1970 @ 11:59:59PM. And the last second of the last day
> of your _second_ year is January 24th 1971 @ 11:59:59PM. And
> so forth...
>
> Does this make sense?

Yes! It does. All you have to do is run a batch job in exactly the
very last second of *every single day*. Totally not a problem!

Have you ever run a database in your life?

Tip: When you're in a hole, stop digging.

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


Re: Are the critiques in "All the things I hate about Python" valid?

2018-02-26 Thread Chris Angelico
On Tue, Feb 27, 2018 at 2:55 PM, Ian Kelly  wrote:
> On Mon, Feb 26, 2018 at 8:09 PM, Steven D'Aprano
>  wrote:
>> Yes you did: "the last second of every year" is always 23:59:59 of 31st
>> December, and it is always the same time and date "every year".
>
> Except when it's 23:59:60 or 23:59:61 (which hasn't yet happened but could).

Unless you use a leap smear to avoid it.

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


Re: Are the critiques in "All the things I hate about Python" valid?

2018-02-26 Thread Ian Kelly
On Mon, Feb 26, 2018 at 8:55 PM, Ian Kelly  wrote:
> On Mon, Feb 26, 2018 at 8:09 PM, Steven D'Aprano
>  wrote:
>> Yes you did: "the last second of every year" is always 23:59:59 of 31st
>> December, and it is always the same time and date "every year".
>
> Except when it's 23:59:60 or 23:59:61 (which hasn't yet happened but could).

Actually, after doing some reading on the subject just now, I learned
that double leap seconds don't actually exist! They were accidentally
invented by the drafters of the ANSI C standard and later propagated
to the POSIX standard and the ANSI SQL standard.

https://www.ucolick.org/~sla/leapsecs/timescales.html#UTC

So the actual last second of the year must always be one of 23:59:58,
23:59:59 or 23:59:60.

(Hint: although we've never had a negative leap second to date, don't
schedule your database update for 23:59:59 if you want to ensure that
it actually happens.)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Steven D'Aprano
On Mon, 26 Feb 2018 17:39:43 +0100, Peter Otten wrote:

[...]
> I have not yet looked into dataclasses. Don't they handle the __init__()
> part? Anyway, here's my attempt to make spam() less spammy:

I'm not too concerned about __init__, it's only one method :-)



> $ cat attrs_to_args_decorator.py
> import functools
> import inspect
> 
> def add_defaults(f):
> argnames = inspect.getfullargspec(f).args[1:]
> 
> @functools.wraps(f)
> def wrapper(self, *args, **kw):
> args = [
> getattr(self, name) if value is None else value for name,
> value in zip(argnames, args)
> ]
> for name in argnames[len(args):]:
> if name not in kw or kw[name] is None:
> kw[name] = getattr(self, name)
> return f(self, *args, **kw)
> return wrapper
[...]

Interesting, this does look promising, thanks.



-- 
Steve

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Steven D'Aprano
On Mon, 26 Feb 2018 16:23:39 -0800, Rick Johnson wrote:

> On Monday, February 26, 2018 at 5:44:18 PM UTC-6, MRAB wrote: [...]
>> Before using or'd-logic, you need to know whether the value could be
>> falsey, e.g. 0.
> 
> True. However. Steven failed to provide any info that might help us
> determine the types of these parameters, and as such, i was forced to
> take the liberty of assumption. 

Someone held a gun to your head?


> Now, while it's quite possible someone
> could assign dwarfy-named- symbols to implicit or explicit boolean
> values, i find it highly unlikely, and totally unintuitive. But then
> again, i have my suspicions about ths thread. ;-)

You mean things like passing 0 as an int argument, or "" as a string 
argument? Yeah, I see what you mean -- that would be such a weird thing 
to do...

/s



-- 
Steve

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Steven D'Aprano
On Tue, 27 Feb 2018 09:15:12 +1100, Ben Finney wrote:

> Steven D'Aprano  writes:
> 
>> I have a class with a large number of parameters (about ten) assigned
>> in `__init__`. The class then has a number of methods which accept
>> *optional* arguments with the same names as the constructor/initialiser
>> parameters. If those arguments are None, the defaults are taken from
>> the instance attributes.
> 
> The catalogue in Refactoring identifies what you need:
> 
> Introduce Parameter Object
> 
> You have a group of parameters that naturally go together.
> 
> Replace them with an object.
> 
> https://refactoring.com/catalog/introduceParameterObject.html>

Interesting, I'll certainly have a good read of that, thanks. But I fear 
I mislead you: you seem to have understood that either all the parameters 
are None, or none of them are, whereas what I meant was that they can 
vary independently of each other.

So it isn't enough to check whether the Parameter object is None, I'd 
need to check each field within the object.

On the other hand, at least I could put the logic of that inside the 
Parameter object, instead of repeating it everywhere it is needed.

On the gripping hand, I *think* that means the caller is responsible for 
creating and populating the Parameter object, instead of just passing 
keyword arguments... let me think about that one.

Either way, thanks for the suggestion.


-- 
Steve

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


Re: Is there are good DRY fix for this painful design pattern?

2018-02-26 Thread Ben Finney
Steven D'Aprano  writes:

> Interesting, I'll certainly have a good read of that, thanks. But I
> fear I mislead you: you seem to have understood that either all the
> parameters are None, or none of them are, whereas what I meant was
> that they can vary independently of each other.

I think that issue – independent defaults for the values – is
orthogonal.

For avoiding the large set of parameters repeated everywhere, you
evidently consider that cluster of values a single concept, to be passed
around as a unit.

That's what the “Introduce Parameter Object” refactor operation is for:
Now that you recognise this cluster is an implicit conceptual unit that
different methods share, define an explicit type for it, and pass around
an instance of that between the functions.

> So it isn't enough to check whether the Parameter object is None, I'd
> need to check each field within the object.

No problem. You can do that within the methods, as before.
Alternatively, you can define it as behaviour of the type. The
“Introduce Parameter Object” refactor leaves that and other options
open, because it's an unrelated issue.

> On the gripping hand, I *think* that means the caller is responsible
> for creating and populating the Parameter object, instead of just
> passing keyword arguments... let me think about that one.

One good effect of this refactor is you're forced to explicitly *name*
this concept of cluster-of-values-with-some-specific-meaning. Once you
have a name – which will confont you with a decision about the meaning
of this specific cluster of values – you then get to thinking about how
the values should be initialised, etc.

All of that is hidden from the methods that just want to pass around the
cluster of values to each other. You then get to freely change it while
development continues.

> Either way, thanks for the suggestion.

Happy hacking.

-- 
 \“I think it would be a good idea.” —Mohandas K. Gandhi (when |
  `\asked what he thought of Western civilization) |
_o__)  |
Ben Finney

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


Re: Questions about `locals` builtin

2018-02-26 Thread dieter
Kirill Balunov  writes:
> I am a little bit confused with `locals` builtin in these moments:
>
> 1. The documentation says that _free varaibles_ are returned, which seems
> incorrect description. In my mind the term free variable refers to
> variables used in a function that are not local variables nor parameters of
> that function.
>
> In docs: "Update and return a dictionary representing the current local
> symbol table. Free variables are returned by `locals()` when it is called
> in function blocks, but not in class blocks."

I agree with your definition of "free variable" and I think that
the documentation partially speaks of it.

In a function body, you have two kinds of "free variables":
implicitly used free variables and explicitly declared (via "global",
"nonlocal") free variables.

I think the documentation wants to make clear, that "locals"
does not treat "free variables" in a completely consistent way
(there is a difference between class and function blocks).

I assume that "locals" may return some (but not necessary all)
free variables in a function block -- depending on the actual
implementation.

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