I have started to learn about python and is currently reading through a script written by someone else. I noticed that globals are scattered throughout the script (and I don't like it).. Besides that, I also noticed that when I have code like this
def some_function():
foo.some_method()
# some other code
if __name__ == '__main__' :
foo = Some_Object()
some_function()
even though I don't pass in foo into some_function(), but some_function is still able to manipulate foo (??!). I don't quite like this although it is somewhat similar to Javascript closure (?). I would like to know whether it is possible to stop some_function() from accessing foo if foo is not passed in as a function argument? Or this is the preferred way in python??! (I'm using python 2.5 under ubuntu hardy at the moment)
3 Answers 3
That script has really serious issues with style and organization -- for example, if somebody imports it they have to somehow divine the fact that they have to set thescript.foo
to an instance of Some_Object
before calling some_function
... yeurgh!-)
It's unfortunate that you're having to learn Python from a badly written script, but I'm not sure I understand your question. Variable scope in Python is locals (including arguments), nonlocals (i.e., locals of surrounding functions, for nested functions), globals, builtins.
Is what you want to stop access to globals? some_function.func_globals
is read-only, but you could make a new function with empty globals:
import new
f=new.function(some_function.func_code, {})
now calling f()
will given an exception NameError: global name 'foo' is not defined
. You could set this back in the module with the name some_function
, or even do it systematically via a decorator, e.g.:
def noglobal(f):
return new.function(f.func_code, {})
...
@noglobal
def some_function(): ...
this will guarantee the exception happens whenever some_function
is called. I'm not clear on what benefit you expect to derive from that, though. Maybe you can clarify...?
2 Comments
nonlocal
keyword), are not really a problem -- and I speak on the basis of decades of hard-won experience;-).As far as I know, the only way to stop some_function
from accessing foo
is to eliminate the foo
variable from some_function
's scope, possibly like:
tmp = foo
del foo
some_function()
foo = tmp
Of course, this will crash your (current) code since foo
doesn't exist in the scope of some_function
anymore.
In Python, variables are searched locally, then up in scope until globally, and finally built-ins are searched.
Another option could be:
with some_object as foo:
some_function()
But then, you'll have to at least declare some_object.__exit__
, maybe some_object.__enter__
as well. The end result is that you control which foo
is in the scope of some_function
.
More explanation on the "with" statement here.
1 Comment
In python, something like foo
is not a value, it's a name. When you try to access it, python tries to find the value associated with it (like dereferencing a pointer). It does this by first looking in the local scope (the function), then working its way outwards until it reaches the module scope (i.e. global), and finally builtins, until it finds something matching the name.
That makes something like this work:
def foo():
bar()
def bar():
pass
Despite the fact that bar
doesn't exist when you defined foo
, the function will work because you later defined bar
in a scope that encloses foo
.
Exactly the same thing is going on in the code you post, it's just that foo
is the output of Some_Object()
, not a function definition.
As Alex said, the fact that you can write code like that does not mean that you should.