On Sun, 26 Dec 2004, Jacob S. wrote:
> > The only thing that's missing is that this script can't handle paths > > like ~/dir/junkthis > > I believe you're looking for os.path.expanduser("~/dir/junkthis") > > BTW, trashcan IS a module level variable because it's defined at the module > level. Why it says it's local is beyond me. Hi Jacob, Ah, you must be running into the global/local gotcha. This one is notorious. Let's work with a few simplified examples to clear up the situation. For the sake of simplification, my variable names will suck. *grin* Anyway, here's the first example: ### y = 0 def inc(x): y = x + 1 return y ### We know that when we assign to variables in functions, those variables are locally scoped. This is a fairly unique feature in Python: to assign to a variable is the same thing as declaration in the Python language. So in the example above, 'y' in the line: y = x + 1 is a local variable, since it's assigned within the function. And if we play with this in the interactive interpreter, we'll see that calling inc() doesn't touch the value of the module-level 'y' variable. ### >>> y = 0 >>> def inc(x): ... y = x + 1 ... return y ... >>> inc(3) 4 >>> y 0 >>> y = 2 >>> inc(7) 8 >>> y 2 ### Hope that made sense so far: assignment in a function causes the assigned variable to be treated as local to that function. Now let's look at a slightly different example which highlights the problem: ### y = 42 def inc_y(): ## buggy y = y + 1 ### The issue is the one brought up by the first example: assignment causes a variable to be local. But if 'y' is local, then what does: y = y + 1 mean, if 'y' hasn't been assigned to yet? ### >>> y = 42 >>> def inc_y(): ... y = y + 1 ... >>> inc_y() Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in inc_y UnboundLocalError: local variable 'y' referenced before assignment ### And this is actually something that could --- and probably should! --- be handled at "definition" time rather than at "run" time. We really shouldn't have to call inc_y() to know that something's already wrong with it. [Advanced: In general, it'd be impossible to do it in full generality, since Python's behavior is so dynamic. As a hideous example: ### y = 42 def degenerate_case(): if some_strange_runtime_condition_was_true(): y = 42 y = y + 1 ### Depending on the definition of some_strange_runtime_condition_was_true(), we'd either die and get a UnboundLocalError, or the function would run to completion. But in this case, I would promptly yell at anyone who would write code like this. *grin*] Anyway, to fix the problem, that is, to be able to write a function that does an assignment to a global, we then have to declare the variable as 'global': ### y = 42 def inc_y_fixed(): global y ## fix for scoping issue y = y + 1 ### so that Python knows up front that 'y' in inc_y_fixed is meant to refer to the module-level 'y'. All of this is a consequence of Python's approach to variable declaration. For the common case, we get to save a lot of lines, since we don't have to write things like var x, y, z int x; at the head of every one of our functions. But, consequently, we do hit this slightly odd and ugly situation when we want to assign to module-level variables. For more information, you may want to look at Tim Peters's nice FAQTS entry on this subject, linked here: http://www.faqts.com/knowledge_base/view.phtml/aid/4722/fid/241 This is also in AMK's "Python Warts" page: http://www.amk.ca/python/writing/warts.html under the header "Local Variable Optimization". If you have more questions, please feel free to ask. Hope this helps! _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor