Pass value to imported script in Python [duplicate] - python

This question already has answers here:
Using global variables in a function
(25 answers)
Closed 8 months ago.
I'm using functions so that my program won't be a mess but I don't know how to make a local variable into global.

Here are two methods to achieve the same thing:
Using parameters and return (recommended)
def other_function(parameter):
return parameter + 5
def main_function():
x = 10
print(x)
x = other_function(x)
print(x)
When you run main_function, you'll get the following output
>>> 10
>>> 15
Using globals (never do this)
x = 0 # The initial value of x, with global scope
def other_function():
global x
x = x + 5
def main_function():
print(x) # Just printing - no need to declare global yet
global x # So we can change the global x
x = 10
print(x)
other_function()
print(x)
Now you will get:
>>> 0 # Initial global value
>>> 10 # Now we've set it to 10 in `main_function()`
>>> 15 # Now we've added 5 in `other_function()`

Simply declare your variable outside any function:
globalValue = 1
def f(x):
print(globalValue + x)
If you need to assign to the global from within the function, use the global statement:
def f(x):
global globalValue
print(globalValue + x)
globalValue += 1

If you need access to the internal states of a function, you're possibly better off using a class. You can make a class instance behave like a function by making it a callable, which is done by defining __call__:
class StatefulFunction( object ):
def __init__( self ):
self.public_value = 'foo'
def __call__( self ):
return self.public_value
>> f = StatefulFunction()
>> f()
`foo`
>> f.public_value = 'bar'
>> f()
`bar`

Using globals will also make your program a mess - I suggest you try very hard to avoid them. That said, "global" is a keyword in python, so you can designate a particular variable as a global, like so:
def foo():
global bar
bar = 32
I should mention that it is extremely rare for the 'global' keyword to be used, so I seriously suggest rethinking your design.

You could use module scope. Say you have a module called utils:
f_value = 'foo'
def f():
return f_value
f_value is a module attribute that can be modified by any other module that imports it. As modules are singletons, any change to utils from one module will be accessible to all other modules that have it imported:
>> import utils
>> utils.f()
'foo'
>> utils.f_value = 'bar'
>> utils.f()
'bar'
Note that you can import the function by name:
>> import utils
>> from utils import f
>> utils.f_value = 'bar'
>> f()
'bar'
But not the attribute:
>> from utils import f, f_value
>> f_value = 'bar'
>> f()
'foo'
This is because you're labeling the object referenced by the module attribute as f_value in the local scope, but then rebinding it to the string bar, while the function f is still referring to the module attribute.

Related

What is the scope of a function defined outside of a class?

class player(object):
def __init__(self, a, b):
self.a = a
self.b = b
def foo():
x += 2
obj.a += 10
obj = player(0,0)
x = 4
foo()
I understand that my foo function is not able to assign a value to the local variable x since it was previously defined globally outside the foo scope. Yet the same problem won't occur for a variable a which is an attribute of the instance obj from the player class, which in turn has nothing to do with the function foo().
Apart from the error with x += 2, I would expect an error in obj.a, i.e., I think foo() should not be able to modify obj.a, but it does! It should have thrown the same error as for x += 2 perhaps, no?
All augmented assignments effectively desugar to one of three method calls, but only in one case is an actual assignment performed.
If the lefthand side is a name, then x += y desugars to x = x.__iadd__(y). Because this is an ordinary assignment statement, the parser makes x a local variable (unless preceded by a global x or nonlocal x). Regardless of scope, x must already have a value so that the righthand side can be evaluated. In other words, x is not a free variable.
If the lefthand side is an indexed name, then x[i] += y desugars to x.__setitem__(i, x[i] + y). If x is not already defined as a local variable, it is a free variable, and so will resolve to the value
of x in the first enclosing scope.
If the lefthand side is an attribute lookup, then x.a = y desugars to
x.__setattr__('a', x.a + y). Again, x is a free variable unless a local variable x already exists.
Your comparison is apples to oranges. An example which shows you the behavior you're expecting would be:
class player(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, value):
self.a += value
def foo():
obj += 10
obj = player(0,0)
x = 4
foo()
Python permits you to read global variables inside of foo, but not redefine them. The statement obj.a += 10 only reads the variable of obj from the global scope (even though it sets a value on the instance of obj) so it is allowed. x += 2 attempts to redefine the value of x which is a global, so it is not allowed. This foo will work because we are only reading x but not redefining it:
def foo():
obj.a += 10
y = x + 10
Actually, you can't call x += 2 because x is not yet defined in your code. You can read x as a global var, or you can change it's value using global.
If you run your code, you'll get the error:
UnboundLocalError: local variable 'x' referenced before assignment
What it is saying to you is: I know there is a global x variable in your code, but you can't change it here. But, if you wish, you can create a local variable here named x, and then change it's value. Or, if you really want to modify the value from the global variable, use the global keyword, so I'll know exactly what you want to do.
Declaring it locally:
def foo():
x = 0
x += 2
obj.a += 10
obj = player(0,0)
x = 4
foo()
With global:
def foo():
global x
x += 2
obj.a += 10
obj = player(0,0)
x = 4
foo()
Now, why x.a += 10 works?
Because you are not changing the x object at all.
As mentioned by John in his answer, the same error would occur if you were changing the object itself, not its properties.
if you try to run the code below:
def foo():
obj += 10
obj = player(0,0)
x = 4
foo()
You'll get the same error as before:
UnboundLocalError: local variable 'obj' referenced before assignment
a is an attribute of player instance while x is a variable or simply value. When you are modifying x in the function, it is in local scope and results in NameError. But obj is an object in global scope and when you modify a, you are simply updating its attribute, you won't get any error here.
Without using one of the keywords global or nonlocal, a function can read but not assign a new value to a variable outside of the function's own local scope. Let's consider these two cases:
For x += 2, this is an attempt to assign a new value to the global variable x, so it is not allowed.
For obj.a += 10, it is the variable obj which is global; obj.a is an object attribute, not a "variable" in this sense. The way obj.a += 10 is evaluated is something like this: first look up the object referenced by the variable obj, and then add 10 to the attribute named a belonging to that object. Since this only reads the global variable obj and does not attempt to assign a new value to obj, it is allowed.

python: name resolution clarification?

I'm reading the python reference name resolution, which reads
A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution with an exception that unbound local variables are looked up in the global namespace.
Based on that, I would expect the following code
x = 10
def f():
x = 5
class Test:
y = x
return Test
print(f().y)
to print 10, however it prints 5. is this a mistake in the reference, or am I misunderstanding something?
In this case, 'normal' rules apply:
x = 'global'
def f():
x = 'defined in f'
class Test:
print(x) # not local, normal rules apply
f()
# defined in f
In this second case, we would expect an UnboundLocalError: local variable 'x' referenced before assignment if we were inside a function:
x = 'global'
def f():
x = 'defined in f'
class Test:
print(x) # unbound local at this time
x = 'assigned in Test'
print(x)
But for the first print(x), x will be taken from the global namespace:
f()
# global
# assigned in Test
I think #khelwood gave the answer. The value in the variable:
Test.y
is an integer that you define, but you never give the x = 10 to the function.
Maybe what you want is actually:
x = 10
def f(x=5):
class Test:
y = x
return Test
print(f().y) #print default 5
print(f(x).y)
The last line print 10 since x is given to the function, and therefore the class set y as x
You can see the exception by wrapping f in another function that defines a local variable x:
x = 10
def g():
x = 7
def f():
class Test:
y = x
return Test
return f()
print(g().y)
Now the output is 7, as the lookup of x in the class statement bypasses the local scope of g to find the global value of x.
In your code, because class establishes a new namespace, but not a new scope, the value of x is taken from the current local scope, that of f.

Using global variables in python in a function

def foo():
global a
a = 10
vs
a = 0
def foo():
a = 10
What is the use of declaring global in a function instead of declaring variables right at the top. It should be cleaner this way ?
Q. What is the use of declaring global in a function instead of declaring variables right at the top?
Generally we define few regularly used constants as global variables.
>>> import math
>>> math.pi
3.141592653589793
Mathematical contants/Web Page/Servernames/URLs - which wont change over a period of time.
In general, it is not recommended to RE-DEFINE global variable or define global variables with in a function. But few exception cases are there where we are left with no option but to re-define it. Could be due to a new upgrade in old system where this variable is heavily used across.
So please go with your second approach. Define 'a' outside your
function. This also looks good & easy to read.
>>> a = 10
>>> def foo():
... a = 14 # defining a local variable called a
...
>>> a
10
>>>
>>> foo()
>>> a
10
>>> # a = 14 has no scope outside foo function
>>>
>>> def foo():
... global a # notify function to use global variable here.
... a = 15 # re-defining global ==> nt preferred it
...
>>> a
10
>>> foo()
>>> a # see now it changed here.
15
Hope this helps.
In the first case the value remains same in all the functions.
def set_globvar_to_one():
global globvar
globvar = 1
print globvar
def print_globvar():
print globvar # No need for global declaration to read value of globvar
set_globvar_to_one()
print_globvar()
The output will be 1 and 1.
But 2nd case
def set_globvar_to_one():
globvar = 1
print globvar
def print_globvar():
print globvar # No need for global declaration to read value of globvar
set_globvar_to_one()
print_globvar()
Here you get error saying globvar is not defiend, coz there is no local or global variable named globavar
That would make it ambiguous. Look at this,
a = 0
def foo():
a = 10 # *
Look at the line marked *. Are you assigning to the global a or is this a local variable a with a value 10. The interpreter has no way to knowing what you meant. Thus, the need for global.
a = 0
def foo():
a = 10 # local variable a
def bar():
global a # will be modifying global variable a in this function
a = 10 # assign 10 to global variable
In your first example "a" is not available before foo() is called. Once it is defined in the function it available outside of the function.
In the second example it is available before foo() is called butchanges to it inside the function do not affect the global version .
This example should demonstrate the difference between the two examples
#!/usr/bin/python
def foo():
global a
a = 10
print a
try:
print a
except Exception,e:
print e
foo()
print a
print "-"*70
b = 0
def bar():
b = 10
print b
print b
bar()
print b
Output:
global name 'a' is not defined
10
10
----------------------------------------------------------------------
0
10
0
If you declare it as a global, you don't have to return it.
If you don't use global, you have the function to return a.
Without global it be like this:
In [7]: def foo():
...: a = 10
...: return a
...:
In [9]: a = foo()
In [10]: a
Out[10]: 10
With global:
In [11]: a = 0
In [12]: def foo2():
....: global a
....: a = 10
....:
In [13]: a
Out[13]: 0
In [14]: foo2()
In [15]: a
Out[15]: 10
It is you who decide if you want your function to return or to use global.
It can simplify you code, it can be useful for function that calculates some constants that you don't want to call it each time.
But if use it for single procedure, prefer "return" method.
if you are using the same variable inside the loop then there will be a competition between the global and local variable . so if you want to use the value of the global variable in the loop you have to mention the 'global' keyword

How to make a local variable (inside a function) global [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
Closed 8 months ago.
I'm using functions so that my program won't be a mess but I don't know how to make a local variable into global.
Here are two methods to achieve the same thing:
Using parameters and return (recommended)
def other_function(parameter):
return parameter + 5
def main_function():
x = 10
print(x)
x = other_function(x)
print(x)
When you run main_function, you'll get the following output
>>> 10
>>> 15
Using globals (never do this)
x = 0 # The initial value of x, with global scope
def other_function():
global x
x = x + 5
def main_function():
print(x) # Just printing - no need to declare global yet
global x # So we can change the global x
x = 10
print(x)
other_function()
print(x)
Now you will get:
>>> 0 # Initial global value
>>> 10 # Now we've set it to 10 in `main_function()`
>>> 15 # Now we've added 5 in `other_function()`
Simply declare your variable outside any function:
globalValue = 1
def f(x):
print(globalValue + x)
If you need to assign to the global from within the function, use the global statement:
def f(x):
global globalValue
print(globalValue + x)
globalValue += 1
If you need access to the internal states of a function, you're possibly better off using a class. You can make a class instance behave like a function by making it a callable, which is done by defining __call__:
class StatefulFunction( object ):
def __init__( self ):
self.public_value = 'foo'
def __call__( self ):
return self.public_value
>> f = StatefulFunction()
>> f()
`foo`
>> f.public_value = 'bar'
>> f()
`bar`
Using globals will also make your program a mess - I suggest you try very hard to avoid them. That said, "global" is a keyword in python, so you can designate a particular variable as a global, like so:
def foo():
global bar
bar = 32
I should mention that it is extremely rare for the 'global' keyword to be used, so I seriously suggest rethinking your design.
You could use module scope. Say you have a module called utils:
f_value = 'foo'
def f():
return f_value
f_value is a module attribute that can be modified by any other module that imports it. As modules are singletons, any change to utils from one module will be accessible to all other modules that have it imported:
>> import utils
>> utils.f()
'foo'
>> utils.f_value = 'bar'
>> utils.f()
'bar'
Note that you can import the function by name:
>> import utils
>> from utils import f
>> utils.f_value = 'bar'
>> f()
'bar'
But not the attribute:
>> from utils import f, f_value
>> f_value = 'bar'
>> f()
'foo'
This is because you're labeling the object referenced by the module attribute as f_value in the local scope, but then rebinding it to the string bar, while the function f is still referring to the module attribute.

Can you assign to a variable defined in a parent function? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Python nested functions variable scoping
After much trial and error I have eventually discovered that this doesn't work:
def a():
def b():
print x
x=2
x = 1
b()
print x
You get an exception (x not defined before being referenced). So it looks like b can read from x, but if it tries to assign to it, Python changes its interpretation of 'x' to be a local variable, which is now not defined.
Question for my own sick curiosity: is there any way of achieving this? Is there a way of explicitly accessing the scope of the parent function? (x is not global)
The nonlocal statement in Python 3 will do this.
Edit: In Python 2, there's not a simple way to do it. I suggest you use some mutable container object if you need this capability. For example:
def a():
def b():
print d["x"]
d["x"]=2
d = dict(x=1)
b()
print d["x"]
If you absolutely must emulate nonlocal for CPython 2, you can hack it with the Python C API this way:
import ctypes
import inspect
locals_to_fast = ctypes.pythonapi.PyFrame_LocalsToFast
locals_to_fast.restype = None
locals_to_fast.argtypes = [ctypes.py_object, ctypes.c_int]
def set_in_frame(frame, name, value):
frame.f_locals[name] = value
locals_to_fast(frame, 1)
def a():
def b(frame=inspect.currentframe()):
print x
set_in_frame(frame, "x", 2)
x = 1
b()
print x
You could also set the frame local, and instead of calling PyFrame_LocalsToFast(), you could manipulate the bytecode of a so that it uses LOAD_NAME instead of LOAD_FAST. Please don't do either of these things. There is surely a better solution for your use case.

Categories