Style qeustion: Multiple return values

2021-04-12 Thread Steve Keller
Just a short style question: When returning multiple return values, do
you use parenthesis?

E.g. would you write

def foo():
return 1, 2

a, b = foo()

or do you prefer

def foo():
return (1, 2)

(a, b) = foo()


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


Different "look and feel" of some built-in functions

2021-09-24 Thread Steve Keller
Why do some built-in Python functions feel so differently:

For example sum(), all(), any() expect exactly one argument which is a
sequence to operate on, i.e. a list, an iterator or a generator etc.

sum([1,2,3,4])
sum(range(1, 101))
sum(2**i for i in range(10))
all([True, False])
any(even, {1,2,3,4})

while other functions like set.union() and set.intersection() work on
a list of arguments but not on a sequence:

set.intersection({1,2,3}, {3,4,5})

but

set.union(map(...))   # does not work
set.intersection(list(...))   # does not work

and you have to use a * instead

set.union(*map(...))

etc.

Is this just for historical reason?  And wouldn't it be possible and
desirable to have more consistency?

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


Re: Different "look and feel" of some built-in functions

2021-09-24 Thread Steve Keller
"Dieter Maurer"  writes:

> Steve Keller wrote at 2021-9-24 11:48 +0200:
> >Why do some built-in Python functions feel so differently:
> 
> Because the typical use cases are different
> 
> [...]
> 
> >while other functions like set.union() and set.intersection() work on
> >a list of arguments but not on a sequence:
> >
> >set.intersection({1,2,3}, {3,4,5})
> 
> Those operations are typically applied to a small number
> of operands. You would need to build an iterator in that
> case should the functions only accept iterators.

In my experience I need intersection and union on a list of sets, set
of sets or a map() returning sets much more often.  E.g. in some
mathematical problems, and in automaton theory (IIRC, computing of LR
or LALR sets, converting NFA to DFA, minimizing DFA), many graph
algorithms traversing the nodes (shortest path, ...), and so on).

Intersection and union of two sets is actually often seen in naïve
programming in loops like

for t in (some_sequence):
s.union(t)

where set.union(*(some_sequence)) would be much more elegant.

BTW, I like how the min() and max() functions allow both ways of being
called.

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


sum() vs. loop

2021-10-11 Thread Steve Keller
I have found the sum() function to be much slower than to loop over the
operands myself:

def sum_products(seq1, seq2):
return sum([a * b for a, b in zip(seq1, seq2)])

def sum_products2(seq1, seq2):
sum = 0
for a, b in zip(seq1, seq2):
sum += a * b
return sum

In a program I generate about 14 million pairs of sequences of ints each
of length 15 which need to be summed.  The first version with sum() needs
44 seconds while the second version runs in 37 seconds.

Can someone explain this difference?

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


Re: sum() vs. loop

2021-10-11 Thread Steve Keller
Christian Gollwitzer  writes:

> > def sum_products(seq1, seq2):
> >  return sum([a * b for a, b in zip(seq1, seq2)])
> > def sum_products2(seq1, seq2):
> >  sum = 0
> >  for a, b in zip(seq1, seq2):
> >  sum += a * b
> >  return sum
> > [...]
>
> The first version constructs a list, sums it up and throws the list
> away, while the second version only keeps the running sum in
> memory. How about a generator expression instead, i.e.
> 
> 
>  sum((a * b for a, b in zip(seq1, seq2)))

Ah, of course.  Much cleaner and I should have seen that myself.
Thanks.

BUT

> (untested) ?

I have tested it and with () instead of [] it's even slower:

   explicit loop:   37s   ± .5s
   sum([...])   44s   ± .5s
   sum((...))   47.5s ± .5s

Now completely surprised.

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


Why do integers compare equal to booleans?

2018-11-16 Thread Steve Keller
Why do the integers 0 and 1 compare equal to the boolean values False
and True and all other integers to neither of them?

$ python3
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 0 == False
True
>>> 1 == True
True
>>> 2 == False
False
>>> 2 == True
False
>>> -1 == False
False
>>> -1 == True
False
>>>

Since these are objects of different types I would expect they cannot
be equal.  I know that 0 means false and != 0 means true in C, C++,
etc. but in Python that surprises me.

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


Generators, generator expressions, and loops

2018-11-16 Thread Steve Keller
I have looked at generators, generator expressions, and iterators and
I try to get more familiar with these.

1. How would I loop over all (with no upper bound) integers or all
powers of two, for example?

In C it would be

   for (int i = 0; ; i++) { ... }  or  for (int i = 1; ; i *= 2) { ... }

In Python, I could define a generator

def powers():
i = 1
while True:
yield(i)
i *= 2

for i in powers():
...

More elegant are generator expressions but I cannot think of a way
without giving an upper limit:

for i in (2 ** i for i in range(100)):
...

which looks ugly.  Also, the double for-loop (and also the two loops
in the above exmaple, for + while in the generator) look unnatural,
somehow, i.e. loop over all elements which are created by a loop.

Is there a more beautyful way?

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


Generators, generator expressions, and loops

2018-11-16 Thread Steve Keller
I have looked at generators, generator expressions, and iterators and
I try to get more familiar with these.

1. How would I loop over all (with no upper bound) integers or all
powers of two, for example?

In C it would be

   for (int i = 0; ; i++) { ... }  or  for (int i = 1; ; i *= 2) { ... }

In Python, I could define a generator

def powers():
i = 1
while True:
yield(i)
i *= 2

for i in powers():
...

More elegant are generator expressions but I cannot think of a way
without giving an upper limit:

for i in (2 ** i for i in range(100)):
...

which looks ugly.  Also, the double for-loop (and also the two loops
in the above exmaple, for + while in the generator) look unnatural,
somehow, i.e. loop over all elements which are created by a loop.

Is there a more beautyful way?

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


Iterators of iterators

2018-11-16 Thread Steve Keller
I wonder why iterators do have an __iter__() method?  I thought
iterable objects would have an __iter__() method (but no __next__())
to create an iterator for it, and that would have the __next__()
method but no __iter__().

$ python3
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> l = [1,2,3]
>>> next(l)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'list' object is not an iterator

This is expected, of course.

>>> iter(l)

>>> iter(iter(l))

>>> iter(iter(iter(l)))

>>> i = iter(iter(iter(l)))
>>> list(i)
[1, 2, 3]

Is there any reason or usage for this?

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


Generators, generator expressions, and loops

2018-11-16 Thread Steve Keller
Cancel ill-formated article
-- 
https://mail.python.org/mailman/listinfo/python-list


Animated functions with matplotlib

2020-06-03 Thread Steve Keller
I am trying to plot a live signal using matplotlib and it really
drives me crazy.  I have tried dozens of variants, with and without
interactive (plt.ion()), with animation.FuncAnimation and doing things
by hand, calling plt.show() and/or plt.draw() but nothing works as
expected.  One problem is that running commands in the interactive
python shell behaves differently from the behavior when using the same
commands in a script, so trying out different versions is very
confusing.

I'd like to do something like this:

fig, ax = plt.subplots()

ival = .1
now  = 0
t = list(numpy.linspace(now, now, 500))
y = [0] * len(t)
while True:
time.sleep(ival)
now += ival
val = get_sample_from_some_signal()
t = t[1:] + [now]
y = y[1:] + [val]
ax.clear()
ax.plot(t, y)
plt.pause(1e-9)

This works but is *very* slow and it seems the plot window is closed
and opened again or raised for each new value to plot.

I have tried to call plt.show(block=False) only once and then
repeatedly only change data with ax.lines[0].set_xdata(),
ax.lines[0].set_ydata(), and ax.set_xlim() and then calling
plt.draw().  That works in the interactive python shell but not in a
script.  When calling set[xy]_data() and set_xlim() in an amimate()
function passed to animation.FuncAnimation, but I haven't managed to
redraw the x scale values (although ax.xlim() is called).

Also, with animation.FuncAnimation() I loose control of the main
thread of execution.  When calling plt.show() the function doesn't
return.

I may want to change the loop so that instead of

time.sleep(ival)
val = get_sample_from_some_signal()

I would have

val = wait_for_next_same_from_some_signal()

and I think this doesn't work with FuncAnimation since that calls the
passed function with a fixed time interval.

I am completely lost, can someone help?

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