Simple Python variable scope - python

It seems to me that functions can reference variables outside of their scope but cannot set them. Is this correct? Am I understanding this right?
I also included the globals usage. I know they are bad ju-ju and will avoid them; I know how to get around this, but just wanted to be clear.
My example program:
import foo
# beginning of functions
# this one works because I look at the variable but dont modify it
def do_something_working:
if flag_to_do_something:
print "I did it"
# this one does not work because I modify the var
def do_something_not_working:
if flag_to_do_something:
print "I did it"
flag_to_do_something = 0
# this one works, but if I do this God kills a kitten
def do_something_using_globals_working_bad_ju_ju:
global flag_to_do_something
if flag_to_do_something:
print "I did it"
flag_to_do_something = 0
# end of functions
flag_to_do_something = 1
do_something_working()
do_something_not_working()
do_something_using_globals_working_bad_ju_ju()

Correct. Well mostly. When you flag_to_do_something = 0 you are not modifying the variable, you are creating a new variable. The flag_to_do_something that is created in the function will be a separate link to (in this case) the same object. However, if you had used a function or operator that modified the variable in place, then the code would have worked.
Example:
g = [1,2,3]
def a():
g = [1,2]
a()
print g #outputs [1,2,3]
g = [1,2,3]
def b():
g.remove(3)
b()
print g #outputs [1,2]

Yep, pretty much. Note that "global" variables in Python are actually module-level variables - their scope is that Python module (a.k.a. source file), not the entire program, as would be the case with a true global variable. So Python globals aren't quite as bad as globals in, say, C. But it's still preferable to avoid them.

Related

Why can't I change a global variable in a function in python

I have a global variable let's just call it:
foo = ""
And I have a bunch of functions, and I called foo in one of those function. I changed it to having a string value. But if I go into another function after that and call it it doesn't still have that string value.
Here's an example:
foo = ""
funct():
global foo
foo = "some words"
funct2():
global foo
if foo == "some words":
print ("foo is" + foo)
funct()
funct2()
But in my case, in:
funct2()
it thinks that foo is empty even though in
funct()
I changed it to having a value, is it possible that nested functions have an effect on this because my code is very large and I couldn't really accurately depict the function mess in it. So instead I gave you this example, where here it is quite simple. Do nested functions not work well with changing globals or is there another problem. Is there an easier way to get one variable that can be read and edited in any function? Thank you for anyone who could point me in the right direction.

How do I make a variable created inside a function become global?

I have a function in a program that I`m working at and I named a variable inside this function and I wanted to make it global. For example:
def test():
a = 1
return a
test()
print (a)
And I just can`t access "a" because it keeps saying that a is not defined.
Any help would be great, thanks.
I have made some changes in your function.
def test():
# Here I'm making a variable as Global
global a
a = 1
return a
Now if you do
print (a)
it outputs
1
As Vaibhav Mule answered, you can create a global variable inside a function but the question is why would you?
First of all, you should be careful with using any kind of global variable, as it might be considered as a bad practice for this. Creating a global from a function is even worse. It will make the code extremely unreadable and hard to understand. Imagine, you are reading the code where some random a is used. You first have to find where that thing was created, and then try to find out what happens to it during the program execution. If the code is not small, you will be doomed.
So the answer is to your question is simply use global a before assignment but you shouldn't.
BTW, If you want c++'s static variable like feature, check this question out.
First, it is important to ask 'why' would one want that? Essentially what a function returns is a 'local computation' (normally). Having said so - if I have to use return 'value' of a function in a 'global scope', it's simply easier to 'assign it to a global variable. For example in your case
def test():
a = 1 # valid this 'a' is local
return a
a = test() # valid this 'a' is global
print(a)
Still, it's important to ask 'why' would I want to do that, normally?

Why would people use globals() to define variables

I've come across recently a number of places in our code which do things like this
...
globals()['machine'] = otherlib.Machine()
globals()['logger'] = otherlib.getLogger()
globals()['logfile'] = datetime.datetime.now().strftim('logfiles_%Y_%m_%d.log')
and I am more than a little confused as to why people would do that, rather than doing
global machine
machine = otherlib.Machine()
and so on.
Here is a slightly anonymised function which does this, in full:
def openlog(num)
log_file = '/log_dir/thisprogram.' + num
if os.path.exists(log_file):
os.rename(log_file, log_file + '.old')
try:
globals()["log"] = open(log_file, 'w')
return log
except:
print 'Unable to open ' + log_file
sys.exit(1)
It confuses the hell out of pylint (0.25) as well me.
Is there any reason for coding it that way? There's minimal usage of eval in our code, and this isn't in a library
PS I checked Reason for globals() in python but it doesn't really answer as to why you'd use this for setting globals in a program
Maybe the function uses a local variable with the same name as the global one, and the programmer didn't want to bother changing the variable name?
def foo(bar):
global bar # SyntaxError
bar = bar + 1
def foo(bar):
globals()['bar'] = bar + 1
foo(1)
print(bar) # prints 2
Another use case, albeit still a bit specious (and clearly not the case in the example function you gave), is for defining variable names dynamically. This is rarely, if ever, a good idea, but it does come up a lot in questions on this site, at least. For example:
>>> def new_variable():
... name = input("Give your new variable a name! ")
... value = input("Give your new variable a value! ")
... globals()[name] = value
...
>>> new_variable()
Give your new variable a name! foo
Give your new variable a value! bar
>>> print(foo)
bar
Otherwise, I can think of only one reason to do this: perhaps some supervising entity requires that all global variables be set this way, e.g. "in order to make it really, really clear that these variables are global". Or maybe that same supervising entity has placed a blanket ban on the global keyword, or docks programmer pay for each line.
I'm not saying that any of these would be a good reason, but then again, I truly can't conceive of a good reason to define variables this way if not for scoping purposes (and even then, it seems questionable...).
Just in case, I did a timing check, to see if maybe the globals() call is faster than using the keyword. I'd expect the function call + dictionary access to be significantly slower, and it is.
>>> import timeit
>>> timeit.timeit('foo()', 'def foo():\n\tglobals()["bar"] = 1',number=10000000)
2.733132876863408
>>> timeit.timeit('foo()', 'def foo():\n\tglobal bar\n\tbar = 1',number=10000000)
1.6613818077011615
Given the code you posted and my timing results, I can think of no legitimate reason for the code you're looking at to be written like this. Looks like either misguided management requirement, or simple incompetence.
Are the authors PHP converts? This is a valid code in PHP:
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
See this for more examples. If someone was used to this way of writing the code, maybe they just used the closest matching way of doing it in Python and didn't bother to check for alternatives.
You'd sometimes use a superglobal $GLOBAL variable to define something, because although global keyword exists in PHP, it will only import existing variables - it cannot create a new variable as far as I know.

Reason for globals() in Python?

What is the reason of having globals() function in Python? It only returns dictionary of global variables, which are already global, so they can be used anywhere... I'm asking only out of curiosity, trying to learn python.
def F():
global x
x = 1
def G():
print(globals()["x"]) #will return value of global 'x', which is 1
def H():
print(x) #will also return value of global 'x', which, also, is 1
F()
G()
H()
I can't really see the point here? Only time I would need it, was if I had local and global variables, with same name for both of them
def F():
global x
x = 1
def G():
x = 5
print(x) #5
print(globals()["x"]) #1
F()
G()
But you should never run into a problem of having two variables with same name, and needing to use them both within same scope.
Python gives the programmer a large number of tools for introspecting the running environment. globals() is just one of those, and it can be very useful in a debugging session to see what objects the global scope actually contains.
The rationale behind it, I'm sure, is the same as that of using locals() to see the variables defined in a function, or using dir to see the contents of a module, or the attributes of an object.
Coming from a C++ background, I can understand that these things seem unnecessary. In a statically linked, statically typed environment, they absolutely would be. In that case, it is known at compile time exactly what variables are global, and what members an object will have, and even what names are exported by another compilation unit.
In a dynamic language, however, these things are not fixed; they can change depending on how code is imported, or even during run time. For that reason at least, having access to this sort of information in a debugger can be invaluable.
It's also useful when you need to call a function using function's string name. For example:
def foo():
pass
function_name_as_string = 'foo'
globals()[function_name_as_string]() # foo().
You can pass the result of globals() and locals() to the eval, execfile and __import__ commands. Doing so creates a restricted environment for those commands to work in.
Thus, these functions exist to support other functions that benefit from being given an environment potentially different from the current context. You could, for example, call globals() then remove or add some variables before calling one of those functions.
globals() is useful for eval() -- if you want to evaluate some code that refers to variables in scope, those variables will either be in globals or locals.
To expand a bit, the eval() builtin function will interpret a string of Python code given to it. The signature is: eval(codeString, globals, locals), and you would use it like so:
def foo():
x = 2
y = eval("x + 1", globals(), locals())
print("y=" + y) # should be 3
This works, because the interpreter gets the value of x from the locals() dict of variables. You can of course supply your own dict of variables to eval.
It can be useful in 'declarative python'. For instance, in the below FooDef and BarDef are classes used to define a series of data structures which are then used by some package as its input, or its configuration. This allows you a lot of flexibility in what your input is, and you don't need to write a parser.
# FooDef, BarDef are classes
Foo_one = FooDef("This one", opt1 = False, valence = 3 )
Foo_two = FooDef("The other one", valence = 6, parent = Foo_one )
namelist = []
for i in range(6):
namelist.append("nm%03d"%i)
Foo_other = FooDef("a third one", string_list = namelist )
Bar_thing = BarDef( (Foo_one, Foo_two), method = 'depth-first')
Note that this configuration file uses a loop to build up a list of names which are part of the configuration of Foo_other. So, this configuration language comes with a very powerful 'preprocessor', with an available run-time library. In case you want to, say, find a complex log, or extract things from a zip file and base64 decode them, as part of generating your configuration (this approach is not recommended, of course, for cases where the input may be from an untrusted source...)
The package reads the configuration using something like the following:
conf_globals = {} # make a namespace
# Give the config file the classes it needs
conf_globals['FooDef']= mypkgconfig.FooDef # both of these are based ...
conf_globals['BarDef']= mypkgconfig.BarDef # ... on .DefBase
fname = "user.conf"
try:
exec open(fname) in conf_globals
except Exception:
...as needed...
# now find all the definitions in there
# (I'm assuming the names they are defined with are
# significant to interpreting the data; so they
# are stored under those keys here).
defs = {}
for nm,val in conf_globals.items():
if isinstance(val,mypkgconfig.DefBase):
defs[nm] = val
So, finally getting to the point, globals() is useful, when using such a package, if you want to mint a series of definitions procedurally:
for idx in range(20):
varname = "Foo_%02d" % i
globals()[varname]= FooDef("one of several", id_code = i+1, scale_ratio = 2**i)
This is equivalent to writing out
Foo_00 = FooDef("one of several", id_code = 1, scale_ratio=1)
Foo_01 = FooDef("one of several", id_code = 2, scale_ratio=2)
Foo_02 = FooDef("one of several", id_code = 3, scale_ratio=4)
... 17 more ...
An example of a package which obtains its input by gathering a bunch of definitions from a python module is PLY (Python-lex-yacc) http://www.dabeaz.com/ply/ -- in that case the objects are mostly function objects, but metadata from the function objects (their names, docstrings, and order of definition) also form part of the input. It's not such a good example for use of globals() . Also, it is imported by the 'configuration' - the latter being a normal python script -- rather than the other way around.
I've used 'declarative python' on a few projects I've worked on, and have had occasion to use globals() when writing configurations for those. You could certainly argue that this was due to a weakness in the way the configuration 'language' was designed. Use of globals() in this way doesn't produce very clear results; just results which might be easier to maintain than writing out a dozen nearly-identical statements.
You can also use it to give variables significance within the configuration file, according to their names:
# All variables above here starting with Foo_k_ are collected
# in Bar_klist
#
foo_k = [ v for k,v in globals().items() if k.startswith('Foo_k_')]
Bar_klist = BarDef( foo_k , method = "kset")
This method could be useful for any python module that defines a lot of tables and structures, to make it easier to add items to the data, without having to maintain the references as well.
It can also be used to get an instance of the class 'classname' from a
string:
class C:
def __init__(self, x):
self.x = x
print('Added new instance, x:', self.x)
def call(str):
obj = globals()[str](4)
return obj
c = call('C')
print(c.x)
It might be useful if you like to import module you just have built:
a.py
[...]
def buildModule():
[...code to build module...]
return __import__("somemodule")
[...]
b.py
from a import buildModule
def setup():
globals()["somemodule"] = buildModule()
Not really. Global variables Python really has are module-scoped variables.
# a.py
print(globals())
import b
b.tt()
# b.py
def tt():
print(globals())
run python a.py, at least two output of globals()['__name__'] is different.
Code here in cpython on Github shows it.
I did not notice in answers anything about using globals() to check if you have value set. Maybe you only set value if debugging or have forgotten to set one and want to avoid getting exception. Though locals() might be better solution in some of the cases to avoid accessing global scope and to access local scope only.
# DEBUG = True
if 'DEBUG' in globals():
print(f'We found debug flag and it has value {DEBUG}.')
else:
print(f'Debug flag was not found.')
Also you can use it with combination with get() to set the default value in case variable was not found
# VARIABLE = "Value of var"
my_var = globals().get("VARIABLE", "Value was not found")
print(my_var) # Prints: "Value was not found"
print(VARIABLE) # Raises NameError
VARIABLE = "Value of var"
my_var = globals().get("VARIABLE", "Value was not found")
print(my_var) # prints: "Value of var"
print(VARIABLE) # prints: "Value of var"

static effect on python

how we can construct static effect on python instead of using class and global ?
not like that one :
global a
a = []
#simple ex ;
fonk ( a , b , d)
x = 1
a.append ( x)
EDIT:
I want to create temporary memory , if I exit the function namely fonk , I want to save change as list on temporary memory .
We can do that demand only put static keyword in front of data type but in python , we dont have static, so I want that effect in python . Therefore , how can I do ?
As above code say "a" represents temporary memory
Default values for function arguments are evaluated once, at function definition time, so if you put a mutable object there, it will live across calls. Can be a gotcha, but very useful for caches and similar things static is often used for in other languages. Of course callers can override your cache in this case - but that's not a bad thing, they won't unless they have good reasons and in that case you should allow them to.
Example (this one is usually found in "gotchas" question instead ^^):
def append_and_return_static_list(item, items=[]):
items.append(item)
return items
append_and_return_static_list(0)
append_and_return_static_list(1)
print append_and_return_static_list(2) #=> [0,1,2]
Now, if you absolutely don't want to go that way, you still have other possibilities: You can create a variable outside the function and put the object you want to share there. You should propably prefix the name with a single underscore if you want it to be considered private to that place (not compiler-enforced-private but convention-and-survival-instinct-enforced).
Example (not the best code, the above is better in almost all cases):
_items = []
def append_and_return_static_list(item):
_items.append(item)
return _items
append_and_return_static_list(0)
append_and_return_static_list(1)
print append_and_return_static_list(2) #=> [0,1,2]
Attributes defined in global scope or in class scope are effectively static since modules are treated as singletons and by extension class definitions are singletons within a particular module global scope. (This explanation glosses over the dynamic features of Python that can change this behavior)
The global keyword is used within a local scope to disambiguate assignment. It's a declaration that the attribute name belongs to the enclosing global scope.
In your (broken) example you don't even need to use the global keyword since you are not using assignment, you are calling the append() method of a - no disambiguation is required.
An illustrative example of what global is used for:
>>> a = []
>>> def fonk():
... a = [1]
...
>>> print a
[]
>>> fonk()
>>> print a
[]
>>>
>>> def fonk2():
... global a
... a = [2]
...
>>> print a
[]
>>> fonk2()
>>> print a
[2]
EDIT: I guess I missed the point of the question (do not do it via global and classes), but I don't understand the objection especially when it seems that the example code was broken.

Categories