Re: [Tutor] List comprehensions to search a list--amazing!

2015-03-20 Thread Peter Otten
Patrick Thunstrom wrote:

 The generalized problem:

 L = [V0, V1, ..., Vn], where V0 = V1 = V2 = ... = Vn .
 Find index i, such that V[i] = Vt = V[i + 1], where Vt is the test
 value being searched for. I need to know the indices i and i + 1,
 which I need to interpolate based on where Vt falls.

 The solution (As a sublist, S)  I worked out tonight after
 experimenting with comprehension syntax is:
 S = [i for i, V in enumerate(L) if L[i] = Vt = L[i + 1]]

 And, of course, the index i I need is:
 i = S[0]

 I tested this out with concrete examples in the interpreter, such as
 with a list, L:

 L = [item for item in range(1, 0, -1)]

 and trying different test values. It was blazingly fast, too!

 All I can say is: WOW!!!

 By the way, if you were to use a plain old loop the expected speedup over
 the listcomp would be 2. You can break out of the loop when you have
 found the gap, after iterating over one half of the list on average.

 So for-loops are twice as amazing ;)
 
 For the same basic speed up, a generator expression with a call to
 next() will produce similar results. Without the additional code to
 get the indexed item.
 
 index = (i for i, _ in enumerate(original_list) if original_list[i] =
 target = original_list[i + 1]).next()
 
 The only catch is it raises a StopIteration exception if no element
 fits the test.

In new code you shouldn't call the next() method (renamed __next__() in 
Python 3) explicitly. Use the next() builtin instead which also allows you 
to provide a default:


 exhausted = iter(())
 next(exhausted)
Traceback (most recent call last):
  File stdin, line 1, in module
StopIteration
 next(exhausted, default_value)
'default_value'


That said, rather than polishing the implementation of the inferior 
algorithm pick the better one.

Ceterum censeo bisect is the way to go here ;)

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Peter Otten
Alan Gauld wrote:

 On 20/03/15 02:57, Doug Basberg wrote:
 
 Still, I would like to know if a 'hook' exists on exit from Python.  I am
 running Linux on a Raspberry Pi with Python 2.7.4  I also run an Apache
 server on the Pi for monitor and control of power, HVAC, and security.
 
 Your previous mail got you three options. I'd use all of them!
 
https://docs.python.org/3/library/atexit.html
  
   ... But that's only for normal program termination; sys.excepthook is
   for unexpected exits
 
 
 def close_relay(e=None,v=None,t=None):
 try:
if not relay_closed()
   really_close_relay()
 except:
really_close_relay()
 
 import sys, atexit
 atexit.register(close_relay)
 sys.excepthook = close_relay
 
 
 try:
 main program here
 finally:
 close_relay()

That reeks of cargo cult. Are there actual scenarios for each of the three 
mechanisms where it is the only one that works?

I would expect that

try:
main program here
finally:
close_relay()

provides the same level of confidence, i. e. the relay will be closed when 
the program closes normally or the main code raises an exception, but not if 
the process is killed.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Reversi Game Logic

2015-03-20 Thread Alan Gauld

On 20/03/15 04:50, Danny Yoo wrote:


Some instructors out there do not realize that unit testing is
considered a standard technique for introductory programming.  Ask,
and maybe that will change.


Sadly, unit tests are not considered a standard technique for 
introductory programming. At least not in my part of the world.

They should be, but they ain't. Or not at high school level(*).
I've yet to meet a teacher who even discusses them in the sense
of using unitest type frameworks - they do of course tell
the kids to test their code but don't show them how!

Many schools teach programming because they have to, but have no 
qualified staff in the subject, so a teacher, often a math or

science teacher, gets sent off to do a course. He (usually he!)
returns and teaches what was learned, guided by what is in the
published syllabus. If the kids are really lucky they get somebody
who taught themselves to code (probably in BASIC/VB) when they
were a teenager...

That's not how it should be of course, and the whole RaspberyPi
movement is largely addressed at trying to remedy that situation.
But I have a lot of sympathy for anyone being taught programming
in the high schools around here just now (and for the poor,
ill-equipped  teachers too for that matter!)

Disclaimer:
Of course other places may have squadrons of properly trained and 
knowledgeable teachers. In which case, be very happy!


(*) I'm not sure about the current state of play in universities.
I know I was never taught anything about testing at university
but things may well have moved on there.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Steven D'Aprano
On Fri, Mar 20, 2015 at 08:35:34PM +, Alan Gauld wrote:

 Yeah, I know you can catch a signal and add your own handler, but I 
 meant what is the default Python suspend behaviour? Does it execute any 
 outstanding exception blocks? What about finally blocks? Or, if about to 
 exit a context manager, the __exit__ method?

Depends on the signal.

I'm not an expert on how signals work in Linux, or other Unixes, but I 
expect that, in the absense of a specific signal handler to catch it, 
the sleep (pause?) signal will cause the interpreter to just stop and 
wait. I think that's signal 19 on Linux, and 18 to wake.

Signal 9 doesn't give the interpreter to do anything. The OS just yanks 
the carpet out from under its feet and terminates the process with 
extreme prejudice. Signal 9 cannot be caught, no signal handlers will 
detect it, no try...finally blocks will run. The process just stops.

Don't use kill -9 unless you need to. I always try three steps to kill a 
rogue process:

First use kill processid with no other arguments. Give it 30 seconds 
or so to let the process tidy up after itself, and if it still hasn't 
quiet, try kill -HUP processid. Again, give it 30 seconds or so. 
Then, if and only if necessary, kill -9 processid.


 Or does it just stop and wait till its resumed? Kind of like
 an implicit yield statement?





 
 
 -- 
 Alan G
 Author of the Learn to Program web site
 http://www.alan-g.me.uk/
 http://www.amazon.com/author/alan_gauld
 Follow my photo-blog on Flickr at:
 http://www.flickr.com/photos/alangauldphotos
 
 
 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 https://mail.python.org/mailman/listinfo/tutor
 
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Reversi Game Logic

2015-03-20 Thread Dave Angel

On 03/20/2015 06:20 PM, niyanax...@gmail.com wrote:


Thank you Danny Yoo for replying.

I figured out what to do for the isLegalMove but I ran into another problem. I 
now get a traceback error every chip is black.

This is the traceback:

Traceback (most recent call last):
   File C:\Python34\lib\tkinter\__init__.py, line 1487, in __call__
 return self.func(*args)
   File u:\code\reversiguiapp.py, line 83, in _cbMouseClick
TypeError: makeMove() takes 2 positional arguments but 3 were given
Exception in Tkinter callback







   # Performs an actual move in the game. That is the current player places
   # one of his chips in the square at position (row, col).
   def makeMove( row, col ):


Don't you need a 'self' parameter to this method, like all the others?


 if isALineOfAttack(row, col, 1, 1) is True :
   if self._currentPlayer == 1 :
 self._gameBoard[row, col] = BLACK
   else :
 self._gameBoard[row, col] = WHITE






--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Reversi Game Logic

2015-03-20 Thread Dave Angel

On 03/20/2015 01:28 PM, niyanax...@gmail.com wrote:




You have more than one copy of some lines of previous messages, and more 
than one version of code in the message.  So I have to guess which one 
you intend to be current.





Thank you Mark for replying. I fixed the note you provided on the isLegalMove. 
However the lineOfAttack function is a function my Professor did so students 
are not allowed to touch it.




For the isOver function, are you able to guide me on that?

I am very new to Comp Science and am still learning.

I have attached the programs needed for testing to show that I am testing my 
code as well as the instructions provided for my project.

Please help me out!




   # Returns a boolean indicating whether the game is over.
   def isOver(self) :
 isOver = 0
 for i in range(8) :
   for j in range(8) :
 if self._gameBoard[i, j] != 0 :
   isOver + 1


The above line does NOT change isOver variable.  Try again.  By the way, 
it's not usually a good idea to use the function name as a local within 
the function, even though it'll work.




 if isOver == 64 :
 self._gameOver = True
 return True
 else:
 return False


   # Returns the
   def isLegalMove( self, row, col):
 if row  8  col:
   if self._gameBoard[row,col] != EMPTY:
 return True
 else:
   return False


This function is still buggy.  It does not return either True or False 
if the selected row is non-empty.





# Returns the player number whose chip occupies the given square.
   def occupiedBy(self, row, col):


How is the following function body any different from:
 return self._gameBoard[row, col]



 if self._gameBoard[row, col] == BLACK :
   return 1
 if self._gameBoard[row, col] == WHITE :
   return 2
 else:
   return 0




   # Performs an actual move in the game. That is the current player places
   # one of his chips in the square at position (row, col).
   def makeMove( row, col ):
 if isALineOfAttack(row, col, 1, 1) is True :


How are the four following lines any different from:
  self._gameBoard[row, col] = self._currentPlayer



   if self._currentPlayer == 1 :
 self._gameBoard[row, col] = BLACK
   else :
 self._gameBoard[row, col] = WHITE






--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Reversi Game Logic

2015-03-20 Thread niyanaxx95

Thank you Danny Yoo for replying. 

I figured out what to do for the isLegalMove but I ran into another problem. I 
now get a traceback error every chip is black.

This is the traceback:

Traceback (most recent call last):
  File C:\Python34\lib\tkinter\__init__.py, line 1487, in __call__
return self.func(*args)
  File u:\code\reversiguiapp.py, line 83, in _cbMouseClick
TypeError: makeMove() takes 2 positional arguments but 3 were given
Exception in Tkinter callback




Here is my code again just in case:

from ezarrays import Array2D




# Values representing the color of the chips on the board.
EMPTY = 0
BLACK = 1
WHITE = 2




class ReversiGameLogic :
  
  # Creates an instance of Reversi game logic with the board correctly
  # initialized and the current player set to black.
  def __init__(self) :
 # Use a 2-D array to represent the board.
self._gameBoard = Array2D(8, 8)
self._gameBoard.clear(EMPTY)

 # Set the initial configuration of the board.
self._gameBoard[4,3] = BLACK
self._gameBoard[3,4] = BLACK
self._gameBoard[3,3] = WHITE
self._gameBoard[4,4] = WHITE




 # Maintain the number of the current player.
self._currentPlayer = BLACK

 # Keep track of the number of each players chips.
self._numBlackChips = 2
self._numWhiteChips = 2

 # A flag that is set when the game is over. That is, when there are
 # no empty squares on the board or neither player can make a move.
self._gameOver = False

  # Returns a boolean indicating whether the game is over.
  def isOver(self) :
isOver = 0
for i in range(8) :
  for j in range(8) :
if self._gameBoard[i, j] != 0 :
  isOver = isOver + 1
if isOver == 64 :
self._gameOver = True
return True
else:
return False





  # Returns the player number of the current player.
  def whoseTurn(self) :
if self._currentPlayer == 1:
  return 1
else:
  self._curentPlayer == 2
return 2
  

  # Returns the number of chips on the board for the given player.
  def numChips(self, player) :
chipCounter = 0
if player == 1 :
  for i in range(8) :
for j in range(8) :
  if self._gameBoard[i, j] == BLACK :
chipCounter = chipCounter + 1
else : 
  for i in range(8) :
for j in range(8) :
  if self._gameBoard[i, j] == WHITE :
chipCounter = chipCounter + 1 
return chipCounter

  # Returns the number of open squares on the board.
  def numOpenSquares(self) :
numOpenSquares = 0
for i in range(8) :
  for j in range(8) :
if self._gameBoard[i, j] == EMPTY :
  numOpenSquares =  numOpenSquares + 1
return numOpenSquares

  # Returns the player number of the winner or 0 if it's a draw.
  def getWinner( self ):
player1 = 0
player2 = 0
if self._gameOver is True :
  for i in range(8) :
for j in range(8) :
  if self._gameBoard[i, j] == BLACK :
player1 = player1 + 1
  else :
player2 = player2 + 1
  if player1  player2 :
return 1
  if player2  player1 :
return 2
  else:
return 0
  
   # Returns the Return a Boolean indicating if the current player can place
   # their chip in the square at position (row, col). Both row and col must be
   # valid indices
  def isLegalMove( self, row, col ):
if row  0 or row = 8 or col  0 or col = 8:
return False
if self._gameBoard[row,col] == EMPTY:
return True
else:
return False
  
 
  
   # Returns the player number whose chip occupies the given square.
  def occupiedBy(self, row, col):
if self._gameBoard[row, col] == BLACK :
  return 1
if self._gameBoard[row, col] == WHITE :
  return 2
else:
  return 0




  # Performs an actual move in the game. That is the current player places
  # one of his chips in the square at position (row, col).
  def makeMove( row, col ):
if isALineOfAttack(row, col, 1, 1) is True :
  if self._currentPlayer == 1 :
self._gameBoard[row, col] = BLACK
  else :
self._gameBoard[row, col] = WHITE 
  

 


















   # Helper method that returns a Boolean indicating if there is a line of
   # attack from cell (row, col) in the direction offset given by rowInc
   # and colInc. The direction offsets should be, 0, 1, or -1.
  def _isALineOfAttack(self, row, col, rowInc, colInc) :
row += rowInc
col += colInc
 # The next cell in the line must contain the opponents chip.  
if self.occupiedBy(row, col) == self._currentPlayer :
  return False

 # Traverse along the line and determine if it's a line of attack.
while row = 0 and col = 0 and row  8 and col  8 :
  if self.occupiedBy(row, col) == self._currentPlayer :
return True
  elif self.occupiedBy(row, col) == EMPTY :
return False
  else :
 

Re: [Tutor] Fastest find in 2 2D lists with else statement

2015-03-20 Thread Steven D'Aprano
On Fri, Mar 20, 2015 at 08:22:03AM -0400, Kale Good wrote:
 Hello all,
 I'm new to python and a bit of a weekend-warrior programmer (guitar 
 teacher by trade), so there are plenty of computer sciencey concepts 
 that I haven't grasped yet, and I think I'm bumping up against those now.
 
 Read from separate csv files, I have something like
 
 a=[['bass',9],['eagle',36],['human',68]]
 b=[['bass','fish'],['eagle','bird'],['dog',land']]
 c=[[1,'fish','water'],[2, 'mammal','land'],[3,'bird','air']]

What do the numbers 9, 36, 68 in a list mean?

If I'm reading b correctly, you say a bass is a fish, an eagle is a 
bird, and a dog is a land.

What do the numbers 1, 2, 3 in c list mean?


 What I want is to return where each animal lives. What I've been able to 
 glisten from the manuals and stack overflow is:

Let's start by writing in English how you would do this. My guess is:

For each animal:
find out what kind of animal it is;
then look up where that kind of animal lives.


This tells you that the most natural sort of information you want is a 
list of animals:

# [...] is used for lists
animals = [bass, eagle, human, spider, salmon]

plus a dict that associates each animal with its kind:


# {...} is used for dicts
kinds = {bass: fish,
 eagle: bird,
 human: mammal,
 spider: arachnid,
 salmon: fish,
 }

plus a second dict that maps each kind to a location:

locations = {fish: water,
 bird: air,
 mammal: land,
 insect: land,
 arachnid: land,
 mollusk: water,
 }

Then your code becomes trivially easy!

for animal in animals:
kind = kinds[animal]
print(animal, lives in or on, locations[kind])


The dict lookup kinds[animal] takes care of all the searching for you, 
no need to write a for loop at all.


To handle the case where the animal or kind is unknown:


for animal in animals:
kind = kinds.get(animal, None)
if kind is None:
# Ask the user what sort of kind of animal it is.
# In Python 2, you MUST use raw_input instead of input!
kind = input(What kind of animal is '%s'? % animal)
kind = kind.strip().lower()
kinds[animal] = kind
location = locations.get(kind, None)
if location is None:
# Ask the user where this kind of animal lives.
# In Python 2, you MUST use raw_input instead of input!
location = input(Where do '%s' animals live? % kind)
location = location.strip().lower()
locations[kind] = location
print(animal, lives in or on, location)


Note that direct lookups into a dict are written with square brackets:

kinds[animal]

but optional lookups with a default value use round brackets 
(parentheses):

kinds.get(animal, None)  # None is the default.


Also, there's nothing you can write in Python which will be faster than 
looking it up in a dict. If you have concerns about looping over lists 
repeatedly, you are right to worry about speed. But if you can get the 
same data into a dict or two, dict lookups are *blazingly* fast.


Are you able to move your data into the list and dictionary formats 
shown above? The secret to programming successfully is that getting the 
data into the right format is half the battle. Once you have the data in 
the right format, everything else becomes so much simpler.

For example, I might take your a list and convert it like this:

a=[['bass',9],['eagle',36],['human',68]]
animals = [sublist[0] for sublist in a]

That extracts out the strings bass, eagle etc. and puts them into a 
list called animals.


Converting your b list to a dict should be even easier:

b=[['bass', 'fish'],['eagle', 'bird'],['dog', 'mammal']]
kinds = dict(b)

Can you work out how to get the locations you need, or do you need more 
help? Feel free to ask any questions you have!


-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Martin A. Brown


Hi,

This is mostly a distant footnote to Doug Basberg's original 
question, which I believe is largely answered at this point.


Albert-Jan Roskum, Alan Gauld and Steven D'Aprano were asking about 
signals and how they are handled (in Un*xen).  I am trying to 
address that.



Yeah, I know you can catch a signal and add your own handler, but I
meant what is the default Python suspend behaviour? Does it execute any
outstanding exception blocks? What about finally blocks? Or, if about to
exit a context manager, the __exit__ method?


Suspension of the process has nothing to do with Python.  This 
happens in the Un*x scheduler--long before Python is involved.



Depends on the signal.


Correct.  It all depends on the signal.

Short version:

(Apologies, Jack Nicholson, in demonic form or otherwise):

  * You can't 'handle':  STOP, CONT, KILL, SEGV, BUS.

  * You can handle: HUP, INT, QUIT, USR1, USR2, PIPE, ALRM, TERM and others.

Short advice (though I do not have experience dealing with signals 
in a realtime environment).  I suggest the following guidelines:


  1. Do not catch a signal you cannot handle (or do not intend to
 handle).

  2. Do everything you can at startup to make sure that the
 environment in which you are operating is as you expect.

  3. Catch all the signals you want to catch and, in response to
 receiving such a signal, do what you need in order to shut down
 cleanly.  This coexists peacefully with the handy
 atexit handlers suggested earlier.

(I am normally not at all a fan of an unspecific try--finally, but I 
get what Peter Otten is suggesting and might make the same choice, 
were I faced with Doug Basberg's situation.)


I'm not an expert on how signals work in Linux, or other Unixes, 
but I expect that, in the absense of a specific signal handler to 
catch it, the sleep (pause?) signal will cause the interpreter 
to just stop and wait. I think that's signal 19 on Linux, and 18 
to wake.


Longer version:

I have experience with handling Linux signals and Python.  There may 
be subtle differences on other Un*xen.  If you wish to know more, I 
would suggest reading the chapter on Signals in _Advanced 
Programming in the Unix Environment_ (Chapter 10, in my second 
edition by Stevens  Rago).


You cannot catch nor handle:

  * SIGSTOP (19), because that tells Un*x, Please remove this
process from the scheduler, i.e. freeze it!

  * SIGCONT (18), because that tells Unix, Please restore this
process to normal scheduling, i.e. unfreeze it.

  * SIGKILL (9), because that tells Unix, Terminate this thing,
with prejudice!  Do not tell it what happened.

This means, your Un*X will never actually deliver SIGSTOP, SIGCONT 
or SIGKILL to Python and your program.


I believe that you cannot do anything with the following signals:

  * SIGSEGV (11), because this means that there has been a memory
fault.  Python is a sufficiently high-level language, that, if
this happens, this should not be your code doing it.  (Unless
you are writing C extensions for Python, and then, of course,
you know what you are doing)

  * SIGBUS (7), because this is extraordinarily rare (today), but
would be a case of trying to access memory that does not exist.

In practice, I have seen SIGSEGV often over the last 20 years 
(perhaps I have worked with flaky software, or perhaps that is just 
something that happens in this line of work).  I have seen SIGBUS 
very rarely (usually a precursor to a machine eating itself for 
lunch).


The signals STOP and CONT are so rarely exhibited that they are 
perceived as exotic specimens when demonstrated.


The KILL signal is the big hammer that everybody learns in their 
first month using any Un*x (which is unfortunate because of the 
power it commands).


Signal 9 doesn't give the interpreter to do anything. The OS just 
yanks the carpet out from under its feet and terminates the 
process with extreme prejudice. Signal 9 cannot be caught, no 
signal handlers will detect it, no try...finally blocks will run. 
The process just stops.


Correct.  When the (Linux | Un*x) kernel has a signal 9 for a 
process, that process does not get any chance to clean up.  It 
simply disappears.  It is never given an opportunity to run 
again--i.e. it will never be scheduled again.


Don't use kill -9 unless you need to. I always try three steps to 
kill a rogue process:


First use kill processid with no other arguments. Give it 30 
seconds or so to let the process tidy up after itself, and if it 
still hasn't quiet, try kill -HUP processid. Again, give it 30 
seconds or so. Then, if and only if necessary, kill -9 
processid.


Agreed.  In my experience, most mature sysadmins do this, too.


Or does it just stop and wait till its resumed? Kind of like
an implicit yield statement?


Sending a SIGSTOP to a process is equivalent to freezing it in 
memory/process space.  I sometimes think of this as suspend (because 
of ctrl-Z in bash, 

Re: [Tutor] Reversi Game Logic

2015-03-20 Thread Dave Angel

On 03/19/2015 08:50 PM, niyanax...@gmail.com wrote:

I am having trouble with a function in my reversi logic code. The function is the 
isLegalMove I am asked to Return a Boolean indicating if the current player can 
place their chip in the square at position (row, col). Both row and col must be valid 
indices​. So I came up with my code below, however a move I make in the game says 
Error: not a legal move. Please help!




I see lots of things wrong with the code, just by visual inspection. 
That should tell us that unit tests are necessary.  If nothing else, 
unit tests help you refine just what each method is supposed to do, and 
under what conditions.


I don't recall the rules for Othello, as it's been about 25 years since 
I've played it, and even then I didn't play much.


But there are lots of things about the code that the comments don't 
describe.  For example, it would seem from some of your code that the 
first player is always BLACK, and the second player is always WHITE. But 
in other places, you keep them distinct.


I see Mark gave you a number of markers into your code for problems that 
already exist.  So I'm going to concentrate only on the method you mention.





   # Returns the


Finish the comment


   def isLegalMove( self, row, col):
 if row  8 and col  8:
   if self._gameBoard[row,col] != EMPTY:
 return True
 else:
   return False


There are 3 exit points from the above function, and only two of them 
have return statements.  Your unit test could detect that by assuring 
that the return value is always either True or False.  The above 
function sometimes returns None.


Have you been taught yet what happens when a function falls off the end 
without a return statement?



--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Albert-Jan Roskam


On Fri, Mar 20, 2015 10:37 AM CET Peter Otten wrote:

Alan Gauld wrote:

 On 20/03/15 02:57, Doug Basberg wrote:
 
 Still, I would like to know if a 'hook' exists on exit from Python.  I am
 running Linux on a Raspberry Pi with Python 2.7.4  I also run an Apache
 server on the Pi for monitor and control of power, HVAC, and security.
 
 Your previous mail got you three options. I'd use all of them!
 
https://docs.python.org/3/library/atexit.html
  
   ... But that's only for normal program termination; sys.excepthook is
   for unexpected exits
 
 
 def close_relay(e=None,v=None,t=None):
 try:
if not relay_closed()
   really_close_relay()
 except:
really_close_relay()
 
 import sys, atexit
 atexit.register(close_relay)
 sys.excepthook = close_relay
 
 
 try:
 main program here
 finally:
 close_relay()

That reeks of cargo cult. Are there actual scenarios for each of the three 
mechanisms where it is the only one that works?

I would expect that

try:
main program here
finally:
close_relay()

Is this (also) called a diaper pattern? Or is that name reserved for the 
antipattern with try-bare except, where the 'except' catches all the sh*t 
(pardon my language)?


provides the same level of confidence, i. e. the relay will be closed when 
the program closes normally or the main code raises an exception, but not if 
the process is killed.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Peter Otten
Albert-Jan Roskam wrote:

I would expect that

try:
main program here
finally:
close_relay()
 
 Is this (also) called a diaper pattern? 

Cool name, but most parents want the baby's faeces to go into the diapers 
whereas try ... bare except is notorious for swallowing useful information 
that should be propagated to the user or developer.

 Or is that name reserved for the
 antipattern with try-bare except, where the 'except' catches all the sh*t
 (pardon my language)?

For try ... finally it's its raison d'être to execute some code no matter 
what. E. g. before the advent of with ...

with open(...) as f:
... # use file
# file is closed now even if something went wrong while using it and no
# matter how garbage collection works for the Python implementation running
# the code.
# The exception (if any) is not swallowed

it was good style to write

f = open(...)
try:
... # use file
finally:
f.close()
# file is closed...



___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Cameron Simpson

On 20Mar2015 19:20, Martin A. Brown mar...@linux-ip.net wrote:
[...]

Short version:
(Apologies, Jack Nicholson, in demonic form or otherwise):
 * You can't 'handle':  STOP, CONT, KILL, SEGV, BUS.


You can handle SEGV and BUS. Though probably not meaningfully in Python, 
haven't tried; if they fire in Python something internal is already badly 
wrong.


IIRC, in the distant past the Bourne shell used SIGSEGV as a trigger to 
allocate more memory:-)


Really, the only 3 a UNIX process can't intercept are the first three: STOP, 
CONT, KILL.


Since everything else Martin says seems to be in the context of in Python, no 
other quibbles.


Cheers,
Cameron Simpson c...@zip.com.au
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Fastest find in 2 2D lists with else statement

2015-03-20 Thread Mark Lawrence

On 20/03/2015 12:22, Kale Good wrote:

Hello all,
I'm new to python and a bit of a weekend-warrior programmer (guitar
teacher by trade), so there are plenty of computer sciencey concepts
that I haven't grasped yet, and I think I'm bumping up against those now.


Welcome to the club :)



Read from separate csv files, I have something like

 a=[['bass',9],['eagle',36],['human',68]]
 b=[['bass','fish'],['eagle','bird'],['dog',land']]
 c=[[1,'fish','water'],[2, 'mammal','land'],[3,'bird','air']]

What I want is to return where each animal lives. What I've been able to
glisten from the manuals and stack overflow is:

for i in range(len(a)):

 for x in range(len(b)):
   if a in b[x][1]:
  clss = (b[x][0])
occurrence  w/ else statement
 for y in range(len(c)):
if clss in c[y][1]:
   place = (c[y][2])

 a[i].append(place)



Classic newbie stuff that immediately flags up a code smell.  You do not 
need to loop around Python containers using indexes.  This is typically 
written something like.


for animal in animals:
doSomething(animal)

However see my comment below, you probably don't need so many loops if 
you hold your data in dicts.



a)I'd like to have an else statement; if a match isn't found in b,
prompt the user for one of the values in c[:][0]. (no need to print the
list c; the user will have that available elsewhere)

b)Is there a faster way to do this? List a has ~300 elements, while list
b has ~45000, so I'm curious if I can make it faster.


Take a look at the DictReader here 
https://docs.python.org/3/library/csv.html as when it comes to looking 
things up dicts are far faster than lists.  Try coding it up and come 
back to us if you get any problems.  We don't bite although I have been 
known to bark :)



 -I only need to find the first match, so it seems a next statement
would do the trick. However, I can't figure out how to use next for
finding in two 2d arrays.
-From my understanding, for this use, b needs to be a list. However,
each line is unique, so it could be a set if necessary.

Thanks in advance.

Best,
Kale


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

Mark Lawrence

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Alan Gauld

On 20/03/15 09:37, Peter Otten wrote:


def close_relay(e=None,v=None,t=None):
 try:
if not relay_closed()
   really_close_relay()
 except:
really_close_relay()


The purpose of the if clause is to ensure that
if the function is called many times you only
close the relay once (I surmised that more than
once could be harmful?)


import sys, atexit
atexit.register(close_relay)
sys.excepthook = close_relay


atexit should be overkill, but it might be needed
if for some reason the interpreter dies while
performing the usual cleanup.

excepthook replaces the usual exception mechanism
with a clean up. This is needed for cases where an
exception occurs before getting to the finally. We
want to close the relay ASAP, not waiting till
the interpreter decides to call the finally.


try:
 main program here
finally:
 close_relay()


This is the happy path where everything shuts down as expected.


That reeks of cargo cult. Are there actual scenarios for each of the three
mechanisms where it is the only one that works?


In real-time you never trust anything.
Always cover your back.


I would expect that

try:
 main program here
finally:
 close_relay()

provides the same level of confidence,


Only if the interpreter is behaving as normal.
The hooks are to try (we hope) to catch cases where
the interpreter has broken its normal flow.

So the scenarios are:

1) an unexpected exception occurs - close the relay ASAP.
   - Use excepthook

2) The interpreter gets sent a kill or similar unexpected
termination - use atexit because finally may not get
called. (I'm not sure, so belt n' braces here)
(BTW Does anyone know what the interpreter does when
suspending - Ctrl-Z in Unix land?)

3) Normal program exit. Use the finally clause.

But its only ever going to be a best endeavour, that's
why Python is not suitable for true real-time/critical apps...
But I'd never trust any environment to its usual behaviour
if there is a possibility of something being broken.
In this case the relay and its battery pack.


the program closes normally or the main code raises an exception, but not if
the process is killed.


What's not clear in the Python  documentation is how Python responds
to a kill(or suspend). I'd hope the atexit got called even in a kill.
I would not expect the finally to be executed.

Of course, if its a seg fault you are probably stuffed either way...


--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Reversi Game Logic

2015-03-20 Thread Danny Yoo

 So let's say that in the unit tests.  Add assertions that we want
 those four starred points to be legal moves.

 #
 import unittest

 class ReversiTests(unittest.TestCase):
 def testIslegalMoveOnExistingSpots(self):
 logic = ReversiGameLogic()
 # Placing on existing spots should not be legal.
 self.assertFalse(logic.isLegalMove(4, 3))
 self.assertFalse(logic.isLegalMove(3, 4))
 self.assertFalse(logic.isLegalMove(3, 3))
 self.assertFalse(logic.isLegalMove(4, 4))


 def testIsLegalMoveGood(self):
 logic = ReversiGameLogic()
 # But here are spots that should be legal.
 self.assertTrue(logic.isLegalMove(2, 3))
 ...  ## fill me in with the other three legal moves!


 if __name__ == '__main__':
 unittest.main()
 ##


Sorry: I sent this draft a bit too early!  There really should be at
least one more test that we need to have;  we need to check for moves
that are not legal, but for fundamental Reversi-based reasons.

For example, we *know* that playing on (1, 1) can't be legal when the
game is starting: it's an empty spot on the board, but it's not
adjacent to a line of white pieces.

This is the sort of thing that would be an appropriate to write as a test:

###
import unittest

class ReversiTests(unittest.TestCase):
def testIslegalMoveOnExistingSpots(self):
logic = ReversiGameLogic()
# Placing on existing spots should not be legal.
self.assertFalse(logic.isLegalMove(4, 3))
self.assertFalse(logic.isLegalMove(3, 4))
self.assertFalse(logic.isLegalMove(3, 3))
self.assertFalse(logic.isLegalMove(4, 4))


def testIsLegalMoveGood(self):
logic = ReversiGameLogic()
# But here are spots that should be legal.
self.assertTrue(logic.isLegalMove(2, 3))
## ... fill me in with the other three legal moves!


def testIsLegalMoveNotAdjacentAttackLine(self):
logic = ReversiGameLogic()
# But here is a spot that should be illegal.
self.assertTrue(logic.isLegalMove(1, 1))


if __name__ == '__main__':
unittest.main()



You'll should see that one of the tests is succeeding, which is great!
 That's what you want to see: partial success.   It means that you're
going in the right direction, and that you just need to amend what
you've got so far.


It should also point out two concrete ways in which your program isn't
quite working yet.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Reversi Game Logic

2015-03-20 Thread Danny Yoo
Hi Ni'Yana,

Here's a little transcript of what I'd do if I were to take a testing
approach to the problem.

---

Let's say that we start with a fresh board.  Imagine that we've just
created a fresh ReversiGameLogic.


What does the board look like?  Let's look at the state in the initializer.

#
  def __init__(self) :
 # Use a 2-D array to represent the board.
self._gameBoard = Array2D(8, 8)
self._gameBoard.clear(EMPTY)
self._gameBoard[4,3] = BLACK
self._gameBoard[3,4] = BLACK
self._gameBoard[3,3] = WHITE
self._gameBoard[4,4] = WHITE
self._currentPlayer = BLACK
...
#

Let's visualize this.  The board looks like this:

. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . W B . . .
. . . B W . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .

and we'll keep in mind that the current player is black.



You mention the following:


 I am having trouble with a function in my reversi logic code. The function is 
 the isLegalMove I am asked to Return a Boolean indicating if the current 
 player can place their chip in the square at position (row, col). Both row 
 and col must be valid indices.



What moves are illegal when the board is just starting off?  Well, if
I try placing on the same points as what's already on the board,
that's definitely wrong.  Let me try writing this as a unit test.


##
import unittest

class ReversiTests(unittest.TestCase):
def testIslegalMoveOnExistingSpots(self):
logic = ReversiGameLogic()

self.assertFalse(logic.isLegalMove(4, 3))
self.assertFalse(logic.isLegalMove(3, 4))
self.assertFalse(logic.isLegalMove(3, 3))
self.assertFalse(logic.isLegalMove(4, 4))


if __name__ == '__main__':
unittest.main()
##


I'd then run these tests, and they'd all pass, so I'd like that your
code is doing *something* good.


But then, I'd notice that the tests don't really say too much yet:
they've only said that it's illegal to play where there's already a
piece.


What at the places where black can play when the board looks like this?

. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . W B . . .
. . . B W . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .


According to:

http://en.wikipedia.org/wiki/Reversi

the legal places where black can play next are here, marked with *'s.

. . . . . . . .
. . . . . . . .
. . . * . . . .
. . * W B . . .
. . . B W * . .
. . . . * . . .
. . . . . . . .
. . . . . . . .


So let's say that in the unit tests.  Add assertions that we want
those four starred points to be legal moves.

#
import unittest

class ReversiTests(unittest.TestCase):
def testIslegalMoveOnExistingSpots(self):
logic = ReversiGameLogic()
# Placing on existing spots should not be legal.
self.assertFalse(logic.isLegalMove(4, 3))
self.assertFalse(logic.isLegalMove(3, 4))
self.assertFalse(logic.isLegalMove(3, 3))
self.assertFalse(logic.isLegalMove(4, 4))


def testIsLegalMoveGood(self):
logic = ReversiGameLogic()
# But here are spots that should be legal.
self.assertTrue(logic.isLegalMove(2, 3))
...  ## fill me in with the other three legal moves!


if __name__ == '__main__':
unittest.main()
##


If this is the first time you've seen a testing approach, notice that
writing tests is a matter of asking yourself: if this is what the
world looks like, what *should* happen if my code were working?
That's an easier thing to do than to actually write the working code.

But it's not just something that we ponder: it's something we can run!
  Once we have the other three legal moves in play, now we have
something we can execute.  This is something that will say yes or
no to our implementation of isLegalMove().  This is the sort of
thing we *need* in order to tell if the logic is working or not.

It will also point out very clearly that your isLegalMove() is not
working, since it's going to fail.  But these are going to tell more
than than things are broken: they're going to tell you that things are
partially working, which is good!

That is, if you have these tests in place, one of the tests will
succeed, and the other will fail.  And that failure is going to point
out where you're missing something in your definition of
isLegalMove().
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Fastest find in 2 2D lists with else statement

2015-03-20 Thread Kale Good

Hello all,
I'm new to python and a bit of a weekend-warrior programmer (guitar 
teacher by trade), so there are plenty of computer sciencey concepts 
that I haven't grasped yet, and I think I'm bumping up against those now.


Read from separate csv files, I have something like

a=[['bass',9],['eagle',36],['human',68]]
b=[['bass','fish'],['eagle','bird'],['dog',land']]
c=[[1,'fish','water'],[2, 'mammal','land'],[3,'bird','air']]

What I want is to return where each animal lives. What I've been able to 
glisten from the manuals and stack overflow is:


for i in range(len(a)):

for x in range(len(b)):
  if a in b[x][1]:
 clss = (b[x][0])
occurrence  w/ else statement
for y in range(len(c)):
   if clss in c[y][1]:
  place = (c[y][2])

a[i].append(place)

a)I'd like to have an else statement; if a match isn't found in b, 
prompt the user for one of the values in c[:][0]. (no need to print the 
list c; the user will have that available elsewhere)


b)Is there a faster way to do this? List a has ~300 elements, while list 
b has ~45000, so I'm curious if I can make it faster.
-I only need to find the first match, so it seems a next statement 
would do the trick. However, I can't figure out how to use next for 
finding in two 2d arrays.
   -From my understanding, for this use, b needs to be a list. However, 
each line is unique, so it could be a set if necessary.


Thanks in advance.

Best,
Kale
--

Kale Good: Guitar Instructor ♫
phillyguitarlessons.com http://phillyguitarlessons.com
phone: (215)260-5383

 * 4705 Baltimore Ave, Phila, PA 19143 :Mailing  Lessons
 * 1867 Frankford Ave. Phila, PA 19125 :Lessons

Google+ https://plus.google.com/b/105422331794047992190/
Facebook http://facebook.com/KaleGoodGuitarStudio
Read my article The Seven Secrets to Six String Success 
http://www.guitarnoise.com/lesson/seven-secrets-to-six-string-success/ at 
GuitarNoise.com http://guitarnoise.com

Leading the Journey from No-Skills-Guitarist to Talented Musician!

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Reversi Game Logic

2015-03-20 Thread niyanaxx95

I am very new to Comp Science and am still learning.

I have attached the programs needed for testing to show that I am testing my 
code as well as the instructions provided for my project.

Please help me out!






Sent from Windows Mail





From: Ni'Yana Morgan
Sent: ‎Friday‎, ‎March‎ ‎20‎, ‎2015 ‎11‎:‎16‎ ‎AM
To: Mark Lawrence






I am very new to Comp Science and am still learning.

I have attached the programs needed for testing to show that I am testing my 
code as well as the instructions provided for my project.

Please help me out!






Sent from Windows Mail





From: Mark Lawrence
Sent: ‎Friday‎, ‎March‎ ‎20‎, ‎2015 ‎11‎:‎11‎ ‎AM
To: Ni'Yana Morgan






please use reply all so everybody can benefit


 


Kindest regards. 

Mark Lawrence.









On Friday, 20 March 2015, 15:04, niyanax...@gmail.com niyanax...@gmail.com 
wrote:
 








Thank you Mark for replying. I fixed the note you provided on the isLegalMove. 
However the lineOfAttack function is a function my Professor did so students 
are not allowed to touch it.




For the isOver function, are you able to guide me on that?

I am very new to Comp Science and am still learning.

I have attached the programs needed for testing to show that I am testing my 
code as well as the instructions provided for my project.

Please help me out!
















from ezarrays import Array2D




# Values representing the color of the chips on the board.
EMPTY = 0
BLACK = 1
WHITE = 2




class ReversiGameLogic :
  
  # Creates an instance of Reversi game logic with the board correctly
  # initialized and the current player set to black.
  def __init__(self) :
 # Use a 2-D array to represent the board.
self._gameBoard = Array2D(8, 8)
self._gameBoard.clear(EMPTY)

 # Set the initial configuration of the board.
self._gameBoard[4,3] = BLACK
self._gameBoard[3,4] = BLACK
self._gameBoard[3,3] = WHITE
self._gameBoard[4,4] = WHITE




 # Maintain the number of the current player.
self._currentPlayer = BLACK

 # Keep track of the number of each players chips.
self._numBlackChips = 2
self._numWhiteChips = 2

 # A flag that is set when the game is over. That is, when there are
 # no empty squares on the board or neither player can make a move.
self._gameOver = False

  # Returns a boolean indicating whether the game is over.
  def isOver(self) :
isOver = 0
for i in range(8) :
  for j in range(8) :
if self._gameBoard[i, j] != 0 :
  isOver + 1
if isOver == 64 :
self._gameOver = True
return True
else:
return False

  # Returns the player number of the current player.
  def whoseTurn(self) :
if self._currentPlayer == 1:
  return 1
else:
  self._curentPlayer == 2
return 2
  

  # Returns the number of chips on the board for the given player.
  def numChips(self, player) :
chipCounter = 0
if player == 1 :
  for i in range(8) :
for j in range(8) :
  if self._gameBoard[i, j] == BLACK :
chipCounter = chipCounter + 1
else : 
  for i in range(8) :
for j in range(8) :
  if self._gameBoard[i, j] == WHITE :
chipCounter = chipCounter + 1 
return chipCounter

  # Returns the number of open squares on the board.
  def numOpenSquares(self) :
numOpenSquares = 0
for i in range(8) :
  for j in range(8) :
if self._gameBoard[i, j] == EMPTY :
  numOpenSquares =  numOpenSquares + 1
return numOpenSquares

  # Returns the player number of the winner or 0 if it's a draw.
  def getWinner( self ):
player1 = 0
player2 = 0
if self._gameOver is True :
  for i in range(8) :
for j in range(8) :
  if self._gameBoard[i, j] == BLACK :
player1 = player1 + 1
  else :
player2 = player2 + 1
  if player1  player2 :
return 1
  if player2  player1 :
return 2
  else:
return 0
  
  # Returns the 
  def isLegalMove( self, row, col):
if row  8  col:
  if self._gameBoard[row,col] != EMPTY:
return True
else:
  return False
  
 
  
   # Returns the player number whose chip occupies the given square.
  def occupiedBy(self, row, col):
if self._gameBoard[row, col] == BLACK :
  return 1
if self._gameBoard[row, col] == WHITE :
  return 2
else:
  return 0




  # Performs an actual move in the game. That is the current player places
  # one of his chips in the square at position (row, col).
  def makeMove( row, col ):
if isALineOfAttack(row, col, 1, 1) is True :
  if self._currentPlayer == 1 :
self._gameBoard[row, col] = BLACK
  else :
self._gameBoard[row, col] = WHITE 
  

 


















   # Helper method that returns a Boolean indicating if there is a line of
   # attack from cell (row, col) in the direction offset 

Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Alan Gauld

On 20/03/15 20:04, Albert-Jan Roskam wrote:


(BTW Does anyone know what the interpreter does when
suspending - Ctrl-Z in Unix land?)


No experience with it, but I would first check the 'signal' module


Yeah, I know you can catch a signal and add your own handler, but I 
meant what is the default Python suspend behaviour? Does it execute any 
outstanding exception blocks? What about finally blocks? Or, if about to 
exit a context manager, the __exit__ method?


Or does it just stop and wait till its resumed? Kind of like
an implicit yield statement?


--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] UPDATE: Is there a 'hook' to capture all exits from a python program?

2015-03-20 Thread Albert-Jan Roskam

-
On Fri, Mar 20, 2015 8:05 PM CET Alan Gauld wrote:

On 20/03/15 09:37, Peter Otten wrote:

 def close_relay(e=None,v=None,t=None):
  try:
 if not relay_closed()
really_close_relay()
  except:
 really_close_relay()

The purpose of the if clause is to ensure that
if the function is called many times you only
close the relay once (I surmised that more than
once could be harmful?)

 import sys, atexit
 atexit.register(close_relay)
 sys.excepthook = close_relay

atexit should be overkill, but it might be needed
if for some reason the interpreter dies while
performing the usual cleanup.

excepthook replaces the usual exception mechanism
with a clean up. This is needed for cases where an
exception occurs before getting to the finally. We
want to close the relay ASAP, not waiting till
the interpreter decides to call the finally.

 try:
  main program here
 finally:
  close_relay()

This is the happy path where everything shuts down as expected.

 That reeks of cargo cult. Are there actual scenarios for each of the three
 mechanisms where it is the only one that works?

In real-time you never trust anything.
Always cover your back.

 I would expect that

 try:
  main program here
 finally:
  close_relay()

 provides the same level of confidence,

Only if the interpreter is behaving as normal.
The hooks are to try (we hope) to catch cases where
the interpreter has broken its normal flow.

So the scenarios are:

1) an unexpected exception occurs - close the relay ASAP.
- Use excepthook

2) The interpreter gets sent a kill or similar unexpected
termination - use atexit because finally may not get
called. (I'm not sure, so belt n' braces here)
(BTW Does anyone know what the interpreter does when
suspending - Ctrl-Z in Unix land?)

No experience with it, but I would first check the 'signal' module

import signal
import sys
 
def signal_term_handler(signal, frame):
print 'got SIGTERM'
sys.exit(0)
 
signal.signal(signal.SIGTERM, signal_term_handler)

https://nattster.wordpress.com/2013/06/05/catch-kill-signal-in-python/


3) Normal program exit. Use the finally clause.

But its only ever going to be a best endeavour, that's
why Python is not suitable for true real-time/critical apps...
But I'd never trust any environment to its usual behaviour
if there is a possibility of something being broken.
In this case the relay and its battery pack.

 the program closes normally or the main code raises an exception, but not if
 the process is killed.

What's not clear in the Python  documentation is how Python responds
to a kill(or suspend). I'd hope the atexit got called even in a kill.
I would not expect the finally to be executed.

Of course, if its a seg fault you are probably stuffed either way...


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor