Name is local and global syntax error in python - python

I am getting error while executing below statement
a = 10
def test_method(a):
global a
print("Old value of local a = " + str(a)) #this is returning "a = 10"
a = 2
print("New value of local a = " + str(a))
test_method(a)
print("Value of global a = " + str(a))
Output
SyntaxError: name 'a' is local and global
How to change value of a globally in this proc where name is same for function argument and actual parameter

I really think the correct answer is to just pick a different name for the function argument as I commented, but if you cannot for some reason, you can access the global a via globals():
>>> a = 10
>>> def test_method(a):
... print('global:', globals()['a'])
... print('local: ', a)
...
>>> test_method(42)
global: 10
local: 42
Although this is somewhat hacky and I would strongly recommend simply changing the variable names to avoid the error instead.

Related

Python3 method not callable due to UnboundLocalError

Take into account the following code:
def main():
print('Calling methodA()')
methodA()
print('Calling methodB(True)')
methodB(True)
print('Calling methodB(False)')
try:
methodB(False)
except UnboundLocalError as error:
print(f'--> "UnboundLocalError" raised: {error}')
def methodA():
print('Running methodA()')
print('"method_original" in globals(): ' + str('method_original' in globals()))
method_original()
def methodB(patch_function):
print(f'Running methodB({patch_function})')
print('"method_original" in globals(): ' + str('method_original' in globals()))
if patch_function:
method_original=method_patched
method_original()
def method_original():
print('Running method_original()')
def method_patched():
print('Running method_patched()')
if __name__ == '__main__':
main()
It produces the following output:
Calling methodA()
Running methodA()
"method_original" in globals(): True
Running method_original()
Calling methodB(True)
Running methodB(True)
"method_original" in globals(): True
Running method_patched()
Calling methodA(False)
Running methodB(False)
"method_original" in globals(): True
--> "UnboundLocalError" raised: local variable 'method_original' referenced before assignment
Which makes no sense because "method_original" is in globals(). This error can be fixed simply adding global method_original at the beginning of the methodB() but in some cases we have a lot of functions and it could be a pain in the ass to put all of them at the beginning of every method.
Are there any rules to avoid this behavior?
//BR!
Let me explain it in a simpler example :
def fn(a):
if a % 2 == 0:
x = a
return x
print(fn(10)) # Fine
print(fn(9)) # UnboundLocalError: local variable 'x' referenced before assignment
In compile time, when interpreter reaches the function, it sees that there is an assignment to x, so it marks x as a "local" variable. Then in "runtime" interpreter tries to find it only in local namespace ! On the other hand, x is only defined, if a is even.
It doesn't matter if it presents in global namespace, now I want to add a global variable named x, to my example:
def fn(a):
if a % 2 == 0:
x = a
return x
x = 50
print(fn(10)) # Fine
print(fn(9)) # UnboundLocalError: local variable 'x' referenced before assignment
Nothing changed. Interpreter still tries to find x inside the function in local namespace.
Same thing happened in your example.
This is to show which variables are "local":
def fn(a):
if a % 2 == 0:
x = a
return x
print(fn.__code__.co_varnames)
co_varnames is a tuple containing the names of the local variables
(starting with the argument names)
Solution:
Either use global (which I see you don't like) , or do not do assignment inside the function, for example change your methodB to :
def methodB(patch_function):
print(f'Running methodB({patch_function})')
print('"method_original" in globals(): ' + str('method_original' in globals()))
if patch_function:
method_patched()
else:
method_original()

Get variable from a parent function

I have a function that produces another function.
def make_func(greeting):
def func(name):
return greeting + " " + name
return func
>>> say_hello = make_func("Hello")
>>> say_hello("there")
"Hello there"
Elsewhere in the script, I have access to say_hello, but I have no idea what the greeting in that function actually is. I'd like to find out.
name, of course, isn't possible to get because it's specified when the function is called. But greeting is static, because it's defined outside of the function.
Is there some attribute of say_hello I can examine to get the original "Hello"?
You can find a good explanation of how inner functions are compiled in python here
Then the easiest way to get the variable is say_hello.__closure__[0].cell_contents
You can just store the attribute greeting in func:
def make_func(greeting):
def func(name):
return func.greeting + " " + name
func.greeting = greeting
return func
say_hello = make_func("Hello")
print(say_hello.greeting) # Hello
say_hello.greeting = 'Bye'
print(say_hello('there')) # Bye there

Unable to run the following Python code

This program is basically a script to scan each host in a subnet by actually pinging each ip.
This is my code:
#!/usr/bin/python
import os
global lis
print("Scanning the Subnet : ")
subnet_input = '192.168.1.0'
subnet_input = subnet_input.split('.')
for x in range(0,255):
subnet_input[3] = x
str(subnet_input)
new_sub = str(subnet_input[0])+'.'+str(subnet_input[1])+'.'+str(subnet_input[2])+'.'+str(subnet_input[3])
res = os.system("ping -c 4 {}".format(new_sub))
if res==0:
print("{} is Alive".format(new_sub))
str(new_sub)
lis = lis + " " + new_sub
else:
continue
print("[*] ALL ALIVE HOSTS ARE : ")
for i in lis:
print(i)
Error is :
Traceback (most recent call last):
File "./Ping.py", line 16, in <module>
lis = lis + " " + new_sub
NameError: global name 'lis' is not defined
Even though i have declared a global variable it gives me an error saying that the variable is not defined
You misunderstand how the global statement works.
When you declare a variable global, you tell python that it should be accessible everywhere. However, you still need to give it a value.
In your code, you do:
global lis
But you never assign lis a value. Therefore, when you attempt to access it here:
lis = lis + " " + new_sub
You of course get a NameError. lis does not have a value for you to access.
To fix this, replace global lis with lis = "". Doing global lis and then assigning a value to it will also work. However, since everything seems to be in the global namespace in your example, this is unnecessary.

Converting a String containing text for a Python variable assignment into an actual variable

I'm trying to convert a String containing a Python variable assignment into an actual variable.
The following was working for me.
s = "VAR = [1,55]"
exec(s)
print(VAR)
But then when places this code in a function, VAR never gets defined.
def myFunction():
s = "VAR = [1,55]"
exec(s)
print(VAR)
myFunction()
I'm not sure what I am missing. Thanks in advance for the help!
Responses to a few of the questions...
Error message: "NameError: name 'VAR' is not defined"
Using: Python 3
You can also pass globals to exec:
def myFunction():
s = "VAR = [1,55]"
exec(s, globals())
print(VAR)
related
python 2.7
def myfunc():
v1 = 11
exec "v1 = 22"
print v1
myfunc() # 22
def myFunction():
VAR = None
s = "VAR = [1,55]"
exec(s)
print(VAR)
myFunction() # [1, 55]
OR
def myFunction():
#VAR = None
s = "VAR = [1,55]"
exec(s)
print(locals()["VAR"])
myFunction() # [1,55]
In Python 2.7 you can simply do:
>> s = "VAR=55"
>> exec(s)
>> VAR
55
If you need custom namespace do:
>> my_ns = {}
>> exec "VAR=55" in my_ns
>> my_ns["VAR"]
55
Similar applies for Python 3 but exec there is actually a function so exec(...) is to be used. For example:
>> s = "VAR=55"
>> exec(s)
>> VAR
55
When you use functions scope comes into play. You can use locals(), globals() or use your custom namespace:
>>def foo():
ns = {}
s = "VAR=55"
exec(s) in ns
print(ns["VAR"])
>>foo()
55

How to change function name dynamically in python

I want to change the function name according to result obtained from another function but the function definition remains same How can i do this i tried the following example but it didn't work
def f(text):
def x(text):
return text+"example"
name=x(text)
def name(y):
return y
return name
p=f("hi ")
print p("hello")
print p.__name__
OUTPUT
hello
name
But i want the function name p.__name__ as "hi example" not name
You can simply assign to __name__:
def f(text):
def r(y):
return y
r.__name__ = text + "example"
return r
p = f("hi ")
print (p("hello")) # Outputs "hello"
print (p.__name__) # Outputs "hi example"
Note that a function name does not have any influence on the function's behavior though, and does not have any meaning except as a part of the string representation or a debugging aid.

Categories