printing to stdout
I can run a shell script from the commandline as root in which I start a python script as user "ha". The output to stdout and stderr generated by the python script is visible in an xterm: #!/bin/dash exec 2>&1 chpst -u ha:ha:i2c -U ha /usr/local/ha/init.sh exec chpst -u ha:ha:i2c:gpio /usr/local/ha/wait4int.py So far so good. But when I run the script supervised by runit, I can see the output generated by the shell script "init.sh", but the output of the python script is not transferred to the supervised logging. The python script itself works, it reads out some I/O expanders on a Raspberry Pi. But the output of the "print" commands seems to disappear: [..] while True: if GPIO.input(23) == 1: # if still 0, another event has occurred GPIO.wait_for_edge(23, GPIO.FALLING) print ('---') while GPIO.input(23) == 0: for pcf in pcf_present: output = bus.read_byte(pcf) print ("%x: %x" % (pcf, output)) if GPIO.input(23) == 1: loopcntr = 0 break else: loopcntr += 1 if loopcntr >=20: print ('[ALERT] possible INT loop, disable 10 seconds') sleep (10) GPIO.cleanup() Anyone a hint? Note: I'm a newbie to python. -- richard lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On 16Aug2018 22:37, richard lucassen wrote: I can run a shell script from the commandline as root in which I start a python script as user "ha". The output to stdout and stderr generated by the python script is visible in an xterm: #!/bin/dash exec 2>&1 chpst -u ha:ha:i2c -U ha /usr/local/ha/init.sh exec chpst -u ha:ha:i2c:gpio /usr/local/ha/wait4int.py So far so good. But when I run the script supervised by runit, I can see the output generated by the shell script "init.sh", but the output of the python script is not transferred to the supervised logging. The python script itself works, it reads out some I/O expanders on a Raspberry Pi. But the output of the "print" commands seems to disappear: [...] This isn't specific to Python, you'll find it with most programmes. (The shell's builtin "echo" command is an exception.) Some discussion: most output streams are buffered: this means that when you issue some kind of "write" operation to them, the output data are copied to a buffer area in memory, and only actually written out to the operating system (which mediates the data between programmes) at certain times. This reduces the OS level data transfers, which is generally a performance win overall. When are the data sent on to the OS? That depends on the buffered arrangement. When the buffer fills, the data are always sent on because otherwise there's no room for more data. But otherwise, the data are sent on at specific times. An unbuffered stream sends the data on immediately. The standard error stream is usually unbuffered, so that error messages get out immediately. A fully buffered stream is sent on only when the buffer fills. A line buffered stream is sent on when a newline lands in the buffer. You can of course devise whatever system you like, but these three are the common presupplied automatic ones. Also, you can usually force any buffered data to be send on by flushing the buffer. On UNIX systems, the _default_ behaviour of the standard output stream depends on what it is connected to. Stdout is line buffered when connected to a terminal and fully buffered otherwise. This generally makes for nice interactive behaviour (you see timely output when working interactively) and better overall performance when the output is going to a file or a pipe. So let's look at your script: print ("%x: %x" % (pcf, output)) [...] print ('[ALERT] possible INT loop, disable 10 seconds') Your programme will be writing into a buffer. Your messages only go out when enough have accrued to fill the buffer. To force te messages to go out in a timely manner you need to flush the buffer. You have two choices here: call sys.stdout.flush() or pass "flush=True" with the print call, eg: print(, flush=True) Just looking at your loop I would be inclined to just call flush once at the bottom, _before_ the sleep() call: sys.stdout.flush() Your call; the performance difference will be small, so it tends to come down to keeping your code readable and maintainable. Cheers, Cameron Simpson -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Fri, 17 Aug 2018 08:31:22 +1000 Cameron Simpson wrote: > This isn't specific to Python, you'll find it with most programmes. > (The shell's builtin "echo" command is an exception.) [buffer explanation] I already suspectec a buffered output and to check if it was the buffer, I created a lot of output by pressing the button that generates an INT quite a lot of times. But apparently this wasn't enough. After all, the output is small: --- 38: ff 39: ff 3a: ff 3b: fb I fear I generated 4095 bytes instead of 4096. Some wise human being once said "Murphy was an optimist" :) > So let's look at your script: > > > print ("%x: %x" % (pcf, output)) > [...] > > print ('[ALERT] possible INT loop, disable 10 seconds') > > Your programme will be writing into a buffer. Your messages only go > out when enough have accrued to fill the buffer. > > To force te messages to go out in a timely manner you need to flush > the buffer. You have two choices here: call sys.stdout.flush() or > pass "flush=True" with the print call, eg: > > print(, flush=True) > > Just looking at your loop I would be inclined to just call flush once > at the bottom, _before_ the sleep() call: > > sys.stdout.flush() > > Your call; the performance difference will be small, so it tends to > come down to keeping your code readable and maintainable. Yep, the "sys.stdout.flush()" did the job :) I had already been mucking about with file=sys.stderr, but without result, just because of the fact that stderr is never buffered AFAIK (the supervised script "run" has an "exec 2>&1") Anyroad, it works :) Thnx! -- richard lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Fri, 17 Aug 2018 08:31:22 +1000 Cameron Simpson wrote: > Just looking at your loop I would be inclined to just call flush once > at the bottom, _before_ the sleep() call: > > sys.stdout.flush() > > Your call; the performance difference will be small, so it tends to > come down to keeping your code readable and maintainable. This is a working script I made. It initializes the I/O expanders, then it waits for an INT from these I/O expanders on GPIO23, reads the contents and sends which bit on which chip went up or down to a fifo (and stdout for logging) As I'm new to Python, just this question: are there any unPythony things in this code? ## #!/usr/bin/env python3 list_pcf = [0x38, 0x39, 0x3a, 0x3b] list_pcf_value = [] import sys from smbus import SMBus from time import sleep import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) bus = SMBus(1) # initialisation of the input devices: print ("[INFO] initialisation input devices") for i in range(len(list_pcf)): try: bus.write_byte(list_pcf[i], 0xff) # set device to 0xff output = bus.read_byte(list_pcf[i]) list_pcf_value.append(output) # append value to list print ("found: %d, input value: 0x%x" % (list_pcf[i], output)) except IOError: print ("[ALERT] I/O problem device 0x%x (init)" % pcf) 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) print ('---') while GPIO.input(23) == 0: for i in range(len(list_pcf)): try: output = bus.read_byte(list_pcf[i]) if output != list_pcf_value[i]: xor = list_pcf_value[i] ^ output for l in range(8): if xor & 0x1: updown = (output >> l) & 0x1 print ("%d bit %d: to %d" % (list_pcf[i],l,updown)) print("%d %d %d" % (list_pcf[i],l,updown), file=open('/mnt/ramdisk/var/lib/ha/events.fifo', 'w')) xor = xor >> 1 list_pcf_value[i] = output except IOError: print ("[ALERT] I/O problem device 0x%x" % list_pcf[i]) if GPIO.input(23) == 1: loopcntr = 0 break else: loopcntr += 1 if loopcntr >=20: print ('[ALERT] possible INT loop, disable 10 seconds') sleep (10) sys.stdout.flush() GPIO.cleanup() -- richard lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
richard lucassen : > As I'm new to Python, just this question: are there any unPythony > things in this code? Your code looks neat. > except IOError: > print ("[ALERT] I/O problem device 0x%x" % list_pcf[i]) Just double check that simply printing the alert is the correct recovery from the exception. Should there be additional logic instead of the fallthrough? Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On 19Aug2018 09:32, richard lucassen wrote: This is a working script I made. It initializes the I/O expanders, then it waits for an INT from these I/O expanders on GPIO23, reads the contents and sends which bit on which chip went up or down to a fifo (and stdout for logging) As I'm new to Python, just this question: are there any unPythony things in this code? There are always unPythonic bits. Even after you've cleaned them all up, since people will disagree about the finer points of Pythonicism there will be bits both over and under cleaned. ## #!/usr/bin/env python3 list_pcf = [0x38, 0x39, 0x3a, 0x3b] list_pcf_value = [] import sys from smbus import SMBus from time import sleep import RPi.GPIO as GPIO Imports should come before any other code. GPIO.setmode(GPIO.BCM) bus = SMBus(1) # initialisation of the input devices: print ("[INFO] initialisation input devices") for i in range(len(list_pcf)): This is better written as: for i, pcf in enumerate(list_pcf): then you can replace every mention of "list_pcf[i] with "pcf" within the loop. And in fact, since you're not using "i" for anything else you can just go: for pcf in list_pcf: try: bus.write_byte(list_pcf[i], 0xff) # set device to 0xff output = bus.read_byte(list_pcf[i]) list_pcf_value.append(output) # append value to list print ("found: %d, input value: 0x%x" % (list_pcf[i], output)) except IOError: It is best to put try/except around the smallest possible piece of code. If there is an I/O error in the above you have no idea what caused it. Even the print() could emit one, and in that case your except clause's action will be misguided. Example: try: bus.write_byte(list_pcf[i], 0xff) # set device to 0xff output = bus.read_byte(list_pcf[i]) except IOError as e: ... else: list_pcf_value.append(output) # append value to list print ("found: %d, input value: 0x%x" % (list_pcf[i], output)) print ("[ALERT] I/O problem device 0x%x (init)" % pcf) You should always include the exception itself in this kind of message, example: print ("[ALERT] I/O problem device 0x%x (init): %s" % (pcf, e)) 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) print ('---') while GPIO.input(23) == 0: for i in range(len(list_pcf)): You can write thos as: for i, (pcf, pcf_value) in enumerate(zip(list_pcf, list_pcf_value)): and then just talk about "pcf" and "pcf_value" where you have "list_pcf[i]" and "list_pcf_value[i]". Then you just want the "i" when you update "list_pcf_value[i]". (Assigning to pcf_value won't affect that, so you need the index.) try: output = bus.read_byte(list_pcf[i]) Again, this try/except covers too much code. It should only cover bus I/O actions. if output != list_pcf_value[i]: xor = list_pcf_value[i] ^ output for l in range(8): You might want a more meaningful name than "l", such as "bit_pos". if xor & 0x1: updown = (output >> l) & 0x1 print ("%d bit %d: to %d" % (list_pcf[i],l,updown)) print("%d %d %d" % (list_pcf[i],l,updown), file=open('/mnt/ramdisk/var/lib/ha/events.fifo', 'w')) This print is better written: with open('/mnt/ramdisk/var/lib/ha/events.fifo', 'w') as fifo: print("%d %d %d" % (list_pcf[i],l,updown), file=fifo) This ensures timely closing of the fifo when you exit the with suite. Your "print(, file=open(...))" _will_ close the fifo in a timely fashion in CPython because the reference counting will trigger the file's delete action, but in other Python implementations the deletion may happen an arbitrarily large amount of time later (because they may garbage collect unreferenced objects differently). Importantly, your print() won't get flushed to the fifo until the file closes, so timely closing is important. The with is reliable. And also the common idiom. xor = xor >> 1 You can write this: xor >>= 1 list_pcf_value[i] = output except IOError: print ("[ALERT] I/O problem device 0x%x" % list_pcf[i]) And again, you should include the exception value in the message. if GPIO.input(23) == 1: loopcntr = 0 break else: You don't need this else, because the break will exit the loop. loopcntr += 1 if loopcntr >=20: print ('[ALERT] possible INT loop, disable 10 seconds') sleep (10) sys.stdout.flush() You need a flush before the sleep, otherwise the flush won't occur for 10 seconds. Untimely. GPIO.cleanup() Cheers, Cameron Simpson -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Sun, 19 Aug 2018 19:53:04 +1000 Cameron Simpson wrote: [Oops, apparently you set the Reply-To to python-list@python.org, normally that's no problem, but I did something wrong somewhere] > There are always unPythonic bits. Even after you've cleaned them all > up, since people will disagree about the finer points of Pythonicism > there will be bits both over and under cleaned. Although I do not understand exactly what zip is doing here (I presume I switch to use pointers instead of the values), I like the "enumerate" function, very handy :-) The code is now as follows: #!/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 = [] GPIO.setmode(GPIO.BCM) bus = SMBus(1) # initialisation of the input devices: 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) 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) while GPIO.input(23) == 0: for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf, list_pcf_value)): try: output = bus.read_byte(pcf) except IOError as e: print ("[ALERT] I/O problem device 0x%x: %s" % (pcf, e)) if output != pcf_value: xor = pcf_value ^ output for bit_pos in range(8): if xor & 0x1: up_down = (output >> bit_pos) & 0x1 print ("pcf8574 0x%x bit %d: to %d" % (pcf,bit_pos,up_down)) # send decimal values to event script: with open('/mnt/ramdisk/var/lib/ha/events.fifo', 'w') as fifo: print("%d %d %d" % (pcf,bit_pos,up_down), file=fifo) xor >>= 1 list_pcf_value[device_nr] = output if GPIO.input(23) == 1: loopcntr = 0 break loopcntr += 1 if loopcntr >=20: print ('[ALERT] possible INT loop, disabling 10 seconds') sys.stdout.flush() sleep (10) sys.stdout.flush() GPIO.cleanup() And it still works :-) Thnx! R. -- richard lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Sun, 19 Aug 2018 12:02:51 +0300 Marko Rauhamaa wrote: > richard lucassen : > > As I'm new to Python, just this question: are there any unPythony > > things in this code? > > Your code looks neat. Well, apparently there were quite a lot of things that makes the code more readable I'd say. And even better. But it was indeed not very unPythony. OTOH, I'm not a programmer, otherwise I would have written this in C ;-) R. -- richard lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Sun, Aug 19, 2018 at 9:56 AM richard lucassen wrote: > > On Sun, 19 Aug 2018 12:02:51 +0300 > Marko Rauhamaa wrote: > > > richard lucassen : > > > As I'm new to Python, just this question: are there any unPythony > > > things in this code? > > > > Your code looks neat. > > Well, apparently there were quite a lot of things that makes the code > more readable I'd say. And even better. But it was indeed not very > unPythony. OTOH, I'm not a programmer, otherwise I would have written > this in C ;-) This strikes me as an odd conclusion. Raspberry Pi places a strong emphasis on python. It certainly doesn't execute as fast as C can, but it provides a conceptually higher level programming model. There is extremely good community support for python with Pi (a huge plus), and the code is much more understandable. It is faster to write code with python, you can come back to it and understand it more readily at some later time, as can others. And it runs 'fast enough' . So, no, I don't think if you were a 'programmer' you would have used C to do this project. But others may be of a different persuation. > > R. You seemed to have snipped your question about zip function. It takes iterables (things like lists, tuples, dictionaries) as arguments and pairs them together to form tuples. Look it up. Very useful. As and example, if you have list1 = (1,2,3), and list2 = (4,5,6,7) and zip them you will get ((1,4), (2,5),(3,6)). (It stops when the shortest iterable is exhausted) Your allusion to pointers is misguided. Python is not like C or assembler. You don't, and don't need to know where objects are stored. Names are assigned to reference data objects > > -- > richard lucassen > http://contact.xaq.nl/ > -- > https://mail.python.org/mailman/listinfo/python-list -- Joel Goldstick http://joelgoldstick.com/blog http://cc-baseballstats.info/stats/birthdays -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Sun, 19 Aug 2018 19:53:04 +1000 Cameron Simpson wrote: > There are always unPythonic bits. Even after you've cleaned them all > up, since people will disagree about the finer points of Pythonicism > there will be bits both over and under cleaned. Although I do not understand what zip is doing exactly here (I presume I switch to use pointers instead of the values), I like the "enumerate" function, very handy :-) The code is now as follows: #!/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 = [] GPIO.setmode(GPIO.BCM) bus = SMBus(1) # initialisation of the input devices: 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) 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) while GPIO.input(23) == 0: for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf, list_pcf_value)): try: output = bus.read_byte(pcf) except IOError as e: print ("[ALERT] I/O problem device 0x%x: %s" % (pcf, e)) if output != pcf_value: xor = pcf_value ^ output for bit_pos in range(8): if xor & 0x1: up_down = (output >> bit_pos) & 0x1 print ("pcf8574 0x%x bit %d: to %d" % (pcf,bit_pos,up_down)) # send decimal values to event script: with open('/mnt/ramdisk/var/lib/ha/events.fifo', 'w') as fifo: print("%d %d %d" % (pcf,bit_pos,up_down), file=fifo) xor >>= 1 list_pcf_value[device_nr] = output if GPIO.input(23) == 1: loopcntr = 0 break loopcntr += 1 if loopcntr >=20: print ('[ALERT] possible INT loop, disabling 10 seconds') sys.stdout.flush() sleep (10) sys.stdout.flush() GPIO.cleanup() And it still works :-) Thnx! R. -- richard lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Sun, 19 Aug 2018 10:11:08 -0400 Joel Goldstick wrote: > > Well, apparently there were quite a lot of things that makes the > > code more readable I'd say. And even better. But it was indeed not > > very unPythony. OTOH, I'm not a programmer, otherwise I would have > > written this in C ;-) > > This strikes me as an odd conclusion. Raspberry Pi places a strong > emphasis on python. It certainly doesn't execute as fast as C can, > but it provides a conceptually higher level programming model. There > is extremely good community support for python with Pi (a huge plus), > and the code is much more understandable. It is faster to write code > with python, you can come back to it and understand it more readily at > some later time, as can others. And it runs 'fast enough' . So, no, > I don't think if you were a 'programmer' you would have used C to do > this project. But others may be of a different persuation. You've got absolutely a point that Python seems to be largely supported for Rpi. But I'll tell you something else: I just started to use a Rpi ;-) I agree that python code is much more understandable than C. > You seemed to have snipped your question about zip function. It takes > iterables (things like lists, tuples, dictionaries) as arguments and > pairs them together to form tuples. Look it up. Very useful. As and > example, if you have list1 = (1,2,3), and list2 = (4,5,6,7) and zip > them you will get ((1,4), (2,5),(3,6)). (It stops when the shortest > iterable is exhausted) > > Your allusion to pointers is misguided. Python is not like C or > assembler. You don't, and don't need to know where objects are > stored. Names are assigned to reference data objects I'll have another look at it, I was just searching for a clear explanation, but the page I found was not clear enough for me. I'll have to take some time for it... -- Richard Lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Sun, Aug 19, 2018 at 12:16 PM Richard Lucassen wrote: > > On Sun, 19 Aug 2018 10:11:08 -0400 > Joel Goldstick wrote: > > > > Well, apparently there were quite a lot of things that makes the > > > code more readable I'd say. And even better. But it was indeed not > > > very unPythony. OTOH, I'm not a programmer, otherwise I would have > > > written this in C ;-) > > > > This strikes me as an odd conclusion. Raspberry Pi places a strong > > emphasis on python. It certainly doesn't execute as fast as C can, > > but it provides a conceptually higher level programming model. There > > is extremely good community support for python with Pi (a huge plus), > > and the code is much more understandable. It is faster to write code > > with python, you can come back to it and understand it more readily at > > some later time, as can others. And it runs 'fast enough' . So, no, > > I don't think if you were a 'programmer' you would have used C to do > > this project. But others may be of a different persuation. > > You've got absolutely a point that Python seems to be largely supported > for Rpi. But I'll tell you something else: I just started to use a > Rpi ;-) I agree that python code is much more understandable than C. > > > You seemed to have snipped your question about zip function. It takes > > iterables (things like lists, tuples, dictionaries) as arguments and > > pairs them together to form tuples. Look it up. Very useful. As and > > example, if you have list1 = (1,2,3), and list2 = (4,5,6,7) and zip > > them you will get ((1,4), (2,5),(3,6)). (It stops when the shortest > > iterable is exhausted) > > > > Your allusion to pointers is misguided. Python is not like C or > > assembler. You don't, and don't need to know where objects are > > stored. Names are assigned to reference data objects > > I'll have another look at it, I was just searching for a clear > explanation, but the page I found was not clear enough for me. I'll > have to take some time for it... try python.org tutorial, and search for terms like names, or name binding. And also 'namespace' > -- > Richard Lucassen > http://contact.xaq.nl/ > -- > https://mail.python.org/mailman/listinfo/python-list -- Joel Goldstick http://joelgoldstick.com/blog http://cc-baseballstats.info/stats/birthdays -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Sun, 19 Aug 2018 12:37:18 -0400 Joel Goldstick wrote: > > I'll have another look at it, I was just searching for a clear > > explanation, but the page I found was not clear enough for me. I'll > > have to take some time for it... > > try python.org tutorial, and search for terms like names, or name > binding. And also 'namespace' I'll have to get used to the language and I think it's a nice language. I just mucked about with the sqlite modules BTW. And it works :) -- Richard Lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On 19Aug2018 18:10, richard lucassen wrote: On Sun, 19 Aug 2018 10:11:08 -0400 Joel Goldstick wrote: Your allusion to pointers is misguided. Python is not like C or assembler. You don't, and don't need to know where objects are stored. Names are assigned to reference data objects I'll have another look at it, I was just searching for a clear explanation, but the page I found was not clear enough for me. I'll have to take some time for it... If you think of references like C pointers you are 80% of the way there. In CPython (the primary Python implementation, which you're using), a reference is effectively a pointer to the referenced Python object. _Internally_. And the result of the id() function (giving an object's identity) _happens_ to be a memory address. But the language specification doesn't talk about pointers or memory addresses, and other implementations may use other abstractions to associate variables with the objects they reference. So never talk about Python references as pointers. You'll cop noisy criticism! Just think of them as arrows from a variable (or attributes, etc) to an object. Every Python variable is a reference. So when you pass a variable to a function or use it in an expression, your putting a reference there. This: x = 3 y = x results in x and y referring to the same "3" int object. For ints this is pretty irrelevant, since they're immutable. Arithmetic works as you would expect. But this: values = [1, 2, 3] values2 = values Here, values and values 2 both refer to the same list - values2 does not have a copy. So: values2[1] = 4 means that values[1] and values2[1] are both 4 because it is the same list. Cheers, Cameron Simpson Draw little boxes with arrows. It helps. - Michael J. Eager -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Mon, Aug 20, 2018 at 7:55 AM, Cameron Simpson wrote: > Draw little boxes with arrows. It helps. - Michael J. Eager Draw good boxes. - DeviCat ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On 19Aug2018 15:09, richard lucassen wrote: On Sun, 19 Aug 2018 19:53:04 +1000 Cameron Simpson 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) ) >>> 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 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. -- https://mail.python.org/mailman/listinfo/python-list
Re: printing to stdout
On Mon, 20 Aug 2018 08:19:12 +1000 Cameron Simpson wrote: [sorry for late reply] > 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) ) > > >>> 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? Yep, an image or an example says more than 1000 pages of explanation > 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)): Well, that's a nice and clear explanation, at the prompt I played a bit with the enumerate and zip functions and after all it's quite simple :) > >The code is now as follows: > > Much nicer. A few tiny nit picks: [..] changes applied > >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. Probably, sounds logigal, the GPIO pin is read and if something is wrong it will generate an I/O error. R. -- richard lucassen http://contact.xaq.nl/ -- https://mail.python.org/mailman/listinfo/python-list
help with printing to stdout...
Hi, I've got a program here that prints out a percentage of it's completion. Currently with my implimentation it prints like this: 0% 1% 2% 3% 4% etc taking up lots and lots of lines of output... So, how can I make it write the percentage on the same line eg. while working: print percent every time the line print percent is ran it should delete the old percentage from the screen, replacing it with the new one, so as to only use up one line... Basically I'm just printing a string of text to the screen and every time my print command is ran I would like the old text to be removed and my new text added (talking about the one line of the screen here)... This is a command line program, under linux... Thanks, Daniel. -- http://mail.python.org/mailman/listinfo/python-list
Re: help with printing to stdout...
On Sun, Mar 8, 2009 at 1:37 AM, Daniel Dalton wrote: > Hi, > > I've got a program here that prints out a percentage of it's > completion. Currently with my implimentation it prints like this: > 0% > 1% > 2% > 3% > 4% > > etc taking up lots and lots of lines of output... So, how can I make it > write the percentage on the same line eg. > while working: > print percent Use the carriage return character to overwrite the line (you'll need to forego `print`): from sys import stdout while working: stdout.write('\r'+percent) Note that you'll need to ensure that `percent` has constant length throughout the loop. Cheers, Chris -- I have a blog: http://blog.rebertia.com -- http://mail.python.org/mailman/listinfo/python-list
Re: help with printing to stdout...
On Sun, 8 Mar 2009 01:59:03 -0800 Chris Rebert wrote: > > etc taking up lots and lots of lines of output... So, how can I make it > > write the percentage on the same line eg. > Use the carriage return character to overwrite the line (you'll need > to forego `print`): Why do you say that? > from sys import stdout > while working: > stdout.write('\r'+percent) while working: print '\r'+percent, > Note that you'll need to ensure that `percent` has constant length > throughout the loop. Nope. You just need to make sure that it never gets shorter which is the case here. If it wasn't then: while working: print '\r'+percent+' ', -- D'Arcy J.M. Cain | Democracy is three wolves http://www.druid.net/darcy/| and a sheep voting on +1 416 425 1212 (DoD#0082)(eNTP) | what's for dinner. -- http://mail.python.org/mailman/listinfo/python-list
Re: help with printing to stdout...
"Daniel Dalton" wrote: > I've got a program here that prints out a percentage of it's > completion. Currently with my implimentation it prints like this: > 0% > 1% > 2% > 3% > 4% > > etc taking up lots and lots of lines of output... So, how can I make it > write the percentage on the same line eg. > while working: > print percent > every time the line print percent is ran it should delete the old > percentage from the screen, replacing it with the new one, so as to only > use up one line... Basically I'm just printing a string of text to the > screen and every time my print command is ran I would like the old text > to be removed and my new text added (talking about the one line of the > screen here)... This is a command line program, under linux... Play with the following: put a comma after the print, like this: print percent,#This keeps it on the same line Then put a carriage return at the start, like this: print '\r',percent, or like this: print '\r'+str(percent), Then make sure it gets sent out, like this: sys.stdout.flush() Alternatively, you can play with backspaces instead of the carriage return: print '\b\b\b\b', print percent, sys.stdout.flush() And see what happens. - Hendrik -- http://mail.python.org/mailman/listinfo/python-list
Re: help with printing to stdout...
Chris Rebert wrote: On Sun, Mar 8, 2009 at 1:37 AM, Daniel Dalton wrote: Hi, I've got a program here that prints out a percentage of it's completion. Currently with my implimentation it prints like this: 0% 1% 2% 3% 4% etc taking up lots and lots of lines of output... So, how can I make it write the percentage on the same line eg. while working: print percent Use the carriage return character to overwrite the line (you'll need to forego `print`): from sys import stdout while working: stdout.write('\r'+percent) Note that you'll need to ensure that `percent` has constant length throughout the loop. or "erase" the previous character first with whitespace stdout.write('\r\r%s%%' % percent). curse might be more reliable for this kind of thing (though it is definitely an overkill) Note: \r doesn't work on IDLE -- http://mail.python.org/mailman/listinfo/python-list
Re: help with printing to stdout...
> or like this: > > print '\r'+str(percent), > > Then make sure it gets sent out, like this: > > sys.stdout.flush() Hey! Thanks very much, that did the trick! Thanks to everyone that replied, I discovered converting to str was crutial to actually print anything. :) Cheers, Daniel. -- http://mail.python.org/mailman/listinfo/python-list