Prev: Is there a standard name for this tree structure?
Next: def method with variable no of parameters file.writeStuff(n, a1, a2,...an)
From: johngilbrough on 4 Apr 2010 18:12 I cannot make sense of what's happening here ... I'm getting the following error: initializing last modified time /home/john/Dropbox/Projects/python/scripts/src 29 referencing last modified time /home/john/Dropbox/Projects/python/scripts/src 29 referencing last modified time Traceback (most recent call last): File "/home/john/Dropbox/Projects/python/scripts/src/file-watch.py", line 42, in <module> time.sleep(10000) File "/home/john/Dropbox/Projects/python/scripts/src/file-watch.py", line 18, in handler if modifiedTime <> lastModifiedTime: UnboundLocalError: local variable 'lastModifiedTime' referenced before assignment From this logic: #!/usr/bin/python def watchFile(filePath, callback): ### # calls callback whenever file is changed ### import fcntl import os import signal print "initializing last modified time" lastModifiedTime = os.path.getmtime(filePath) def handler(signum, frame): ## this gets called twice whenever a file changes print filePath + " " + str(signum) modifiedTime = os.path.getmtime(filePath) print "referencing last modified time" if modifiedTime <> lastModifiedTime: lastModifiedTime = modifiedTime callback() signal.signal(signal.SIGIO, handler) fd = os.open(filePath, os.O_RDONLY) fcntl.fcntl(fd, fcntl.F_SETSIG, 0) fcntl.fcntl(fd, fcntl.F_NOTIFY, 0 | fcntl.DN_MODIFY | fcntl.DN_CREATE | fcntl.DN_MULTISHOT # what's this? ) def doSomething (): print "in doSomething" import time filePath = "/home/john/Dropbox/Projects/python/scripts/src" watchFile (filePath, doSomething) while True: # needed to keep this alive - gets interrupted when a file changes time.sleep(10000) print "*",
From: Alf P. Steinbach on 4 Apr 2010 18:22 * johngilbrough: > I cannot make sense of what's happening here ... I'm getting the > following error: > > initializing last modified time > /home/john/Dropbox/Projects/python/scripts/src 29 > referencing last modified time > /home/john/Dropbox/Projects/python/scripts/src 29 > referencing last modified time > Traceback (most recent call last): > File "/home/john/Dropbox/Projects/python/scripts/src/file-watch.py", > line 42, in <module> > time.sleep(10000) > File "/home/john/Dropbox/Projects/python/scripts/src/file-watch.py", > line 18, in handler > if modifiedTime <> lastModifiedTime: > UnboundLocalError: local variable 'lastModifiedTime' referenced before > assignment > > From this logic: > > #!/usr/bin/python > def watchFile(filePath, callback): > ### > # calls callback whenever file is changed > ### > import fcntl > import os > import signal > print "initializing last modified time" > lastModifiedTime = os.path.getmtime(filePath) > > def handler(signum, frame): > ## this gets called twice whenever a file changes > print filePath + " " + str(signum) > modifiedTime = os.path.getmtime(filePath) > print "referencing last modified time" > if modifiedTime <> lastModifiedTime: > lastModifiedTime = modifiedTime > callback() Since 'handler' has an assignment to 'lastModifiedTime' that name becomes the name of a local variable. It's not the execution of the assignment that creates the variable. It's the /presence/ of the assignment (this helps the compiler generate code that allocates all local variables on entry to the function). There are a couple of ways around. (1) At least in Py3 you can declare the variable as 'global', like this: global lastModifiedTime within the function. (2) Or, you can apply some indirection, which is nearly always a solution to any computer science and programming problem, and declare your variable like so: class Object: pass g = Object() g.lastModifiedTime = os.path.getmtime( filePath ) Then when you assign to 'g.lastModifiedTime' in 'handler' you're not creating a variable, because you're assigning to an attribute of an object. (3) Best is however to recognize that you have some state (your variable) and some operations on that state (your callback), and that that is what objects are all about. I.e. wrap your logic in a class. Then 'lastModifiedTime' becomes an instance attribute, and 'handler' becomes a method. It doesn't matter that there will only ever be one object (instance) of that class. Classes were meant for just this sort of thing, state + operations. Cheers & hth., - Alf
From: Stephen Hansen on 4 Apr 2010 18:32 On 2010-04-04 15:22:48 -0700, Alf P. Steinbach said: > * johngilbrough: >> I cannot make sense of what's happening here ... I'm getting the >> following error: > (1) > At least in Py3 you can declare the variable as 'global', like this: > > global lastModifiedTime > > within the function. Actually, what you're looking for in py3 is the "nonlocal" keyword, which addresses this precise situation. Using "global" would mark the variable as *global* -- top-level module namespace. nonlocal (within "handler") would make the assignment apply to the enclosing scope lastModifiedTime, instead. -- --S .... p.s: change the ".invalid" to ".com" in email address to reply privately.
From: Alf P. Steinbach on 4 Apr 2010 18:35 * Stephen Hansen: > On 2010-04-04 15:22:48 -0700, Alf P. Steinbach said: > >> * johngilbrough: >>> I cannot make sense of what's happening here ... I'm getting the >>> following error: >> (1) >> At least in Py3 you can declare the variable as 'global', like this: >> >> global lastModifiedTime >> >> within the function. > > Actually, what you're looking for in py3 is the "nonlocal" keyword, > which addresses this precise situation. Using "global" would mark the > variable as *global* -- top-level module namespace. Thanks, I didn't see that. I thought it was a global. > nonlocal (within "handler") would make the assignment apply to the > enclosing scope lastModifiedTime, instead. Cheers, - Alf
From: John Nagle on 5 Apr 2010 13:08
Alf P. Steinbach wrote: > Best is however to recognize that you have some state (your variable) > and some operations on that state (your callback), and that that is what > objects are all about. I.e. wrap your logic in a class. Then > 'lastModifiedTime' becomes an instance attribute, and 'handler' becomes > a method. > > It doesn't matter that there will only ever be one object (instance) of > that class. > > Classes were meant for just this sort of thing, state + operations. Yes. Functions with persistent state are generally a bad idea. Unfortunately, the "signal" module requires a callback parameter which is a plain function. So you have to send it a function, closure, or lambda. Here, it's being sent a closure - "handler" bound to the state that existed when "signal.signal" was called. John Nagle |