osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

printing to stdout


On 19Aug2018 15:09, richard lucassen <mailinglists at lucassen.org> wrote:
>On Sun, 19 Aug 2018 19:53:04 +1000
>Cameron Simpson <cs at cskk.id.au> wrote:
>Although I do not understand what zip is doing exactly here (I presume
>I switch to use pointers instead of the values),

Someone else has descibed zip tersely: it pairs it the elements of 2 lists. In 
fact it joins up matching elements of an arbitrary number of iterables. Here is 
a 3 iterable example:

    >>> zip( (1,2,3), (4,5,6), (7,8,9) )
    <zip object at 0x10aa4ce88>
    >>> list( zip( (1,2,3), (4,5,6), (7,8,9) ) )
    [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

See that is has collected the first element of each tuple, then the second and 
so forth?

In my sentence above, "iterable" means any object you can iterate over - any 
object you could use in a for-loop. So, obviously, a list as in your programme.  
And also a tuple like (1,2,3) as in the example above (a tuple is an 
unmodifiable list). ANd any number of other things that will yield a sequence 
of values.

In Python 3 (which you're using) zip returns a lazy object, which does the 
zipping as you request the values. That is why the example shows a base "zip()" 
returning a "zip object" - we hand it to list() to get an actual list of all 
the values. This is fast (instant return of the zip object without doing much 
work) and cheap in memory (no need to make a huge result if you're zipping big 
lists) and cheap in time (no need to make the whole result if you're only using 
the first part of it).

So, to the code using the zip:

  for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf, list_pcf_value)):

The inner zip yields (pcf, pcf_value) pairs from zipping list_pcf and 
list_pcf_value, an iterable of:

  (pcf[0], pcf-value[0]), (pcf[1], pcf_value[1]), ...

and you can write a for loop like this:

  for pcf, pcf_value in zip(list_pcf, list_pcf_value):

to deal with each of those pairs in turn.

However, since you also need the index (device_nr) in order to update 
list_pcf_value:

  list_pcf_value[device_nr] = output

we then hand the whole thing to enumerate:

  for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf, list_pcf_value)):

The enumerate does just what the previous one did, yields pairs of (index, 
value). Each value is a pair from the zip, so it yields:

  (0, (pcf[0], pcf-value[0])),
  (1, (pcf[1], pcf_value[1])),
  ...

and Python's tuple unpacking syntax is fairly generous, so you want write:

  device_nr, (pcf, pcf_value) = (0, (pcf[0], pcf-value[0]))

and you can stick that in the for loop, getting the syntax you're using in the 
programme:

  for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf, list_pcf_value)):

>The code is now as follows:

Much nicer. A few tiny nit picks:

>#!/usr/bin/env python3
>
>import sys
>from smbus import SMBus
>from time import sleep
>import RPi.GPIO as GPIO
>
>list_pcf = [0x38, 0x39, 0x3a, 0x3b]
>list_pcf_value = []

Just convention: you could call these pcfs and pcf_values and perhaps have more 
readable code. Using plural names kind of indicates that they're lists (or 
tuples or some other sequence of values) and reads more like prose.

># initialisation of the input devices:
>print ("[INFO] initialisation input devices")

"print" is just a regular function. We tend not to put a space before the "(" 
with other functions, and print isn't special. You might have this trailing 
space left over from Python 2 (either your own or some example code), where 
print _wasn't_ a function. So:

  print("[INFO] initialisation input devices")

>for pcf in list_pcf:
>  try:
>    bus.write_byte(pcf, 0xff) # set device to 0xff
>  except IOError as e:
>    print ("[ALERT] I/O problem device 0x%x (init): %s" % (pcf, e))
>  output = bus.read_byte(pcf)

You presumably also want a try/except around the bus.read_byte. You could use a 
distinct try/except (rather wordy) or, since they're adjacent and your 
exception action is the same, just put them both inside the try/except.

The advice to keep things as small as possible within the try/except has to do 
with knowing exactly what kind of thing threw the exception. But they're both 
bus operations and handled the same - including both is reasonable.

>  list_pcf_value.append(output) # append value to list
>  print ("found pcf8574 at 0x%x, input value: 0x%x" % (pcf, output))
>  sys.stdout.flush()
># GPIO 23 set up as input. It is pulled up to stop false signals
>GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
>loopcntr = 0 # detects if INT is kept low
>
>while True:
>  if GPIO.input(23) == 1: # if still 0, another event has occurred
>    GPIO.wait_for_edge(23, GPIO.FALLING)

Can the GPIO ops also raise IOErrors? Just wondering.

Cheers,
Cameron Simpson <cs at cskk.id.au>

Stepwise Refinement n.  A sequence of kludges K, neither distinct or finite,
applied to a program P aimed at transforming it into the target program Q.