I keep on getting NameError: name 'a' is not defined? - python

def main():
a == 3
b = a + 1
c = b + 1
print(a)
if (a<0):
print(a<0)
print(c)
else:
print('a is not less than 0')
print(a)
I watched the khan academy video #1 on Python programming and tried to duplicate it but it kept on giving the error above.
Thanks for your help
I am a first time python user

You are not assigning to a; you are instead testing for equality with a double ==:
a == 3
Since you didn't assign anything to a yet to compare with 3, that results in a NameError.
Remove one = sign to assign instead:
a = 3
This all assumes that the rest of your code is indented correctly to match the rest of your function:
def main():
a = 3
b = a + 1
c = b + 1
print(a)
if (a<0):
print(a<0)
print(c)
else:
print('a is not less than 0')
print(a)

== is used for comparison tests. You need to use = for variable assignment:
a = 3
Also, as your code currently stands, the stuff outside of main will not be able to access a because it is local to the function. Hence, you need to indent it one level:
def main():
a = 3
b = a + 1
c = b + 1
print(a)
if (a<0):
print(a<0)
print(c)
else:
print('a is not less than 0')
print(a)
main()

I think you want the following code:
def main():
a = 3
b = a + 1
c = b + 1
print(a)
if (a<0):
print(a<0)
print(c)
else:
print('a is not less than 0')
print(a)
main()
You want the if statements to be inside the function that you're making, in this case main(). Otherwise, 'a' will not be defined because it is inside the function main(). Welcome to python, and to stack overflow!

Related

How to add mathematical function as argument in python function

I know there are similar questions about passing functions into functions, but I'm not clear on the effective solution for my particular problem.
The following function works but the formula is static. It only works on a fixed function, namely (in mathy pseudocode) f(a) = 3^a mod 17 = b where f(11) = 7
def get_a(b):
'''
Get preimage a from A for f(a) = b where b in B
'''
a = 1
while(1):
x = pow(3, a) % 17
if x == b:
return a
if a > 10000:
return -1
a += 1
def main():
b = 7
a = get_a(7)
print(F'The preimage a of b={b} is: {a}')
if __name__ == '__main__':
main()
I want to make a user pass in any given function. To start with, I implemented something just a little more complex but still pretty simple.
def get_a_variable(b, base, mod):
'''
Get preimage a from A for f(a) = b where b in B
'''
a = 1
while(1):
# print(F'a:{a}, b{b}')
x = pow(base, a) % mod
# print(F'x:{x}')
if x == b:
return a
if a > 10000:
return -1
a += 1
def main():
b = 7
a = get_a(7)
print(F'The preimage a of b={b} is: {a}')
a = get_a_variable(7,3,17)
print(F'Again, the preimage a of b={b} is: {a}')
This works but I want to make it even more dynamic.
To try implement this, I created a new function that can be passed as an argument:
def power_mod_function(base, x, mod):
return power(base, x) % mod
I'm not exactly sure how the trial value arg x should be handled or if it should even be in this function.
Then I "forked" the "get_a(b)" function that takes a callback I believe
def get_a_dynamic(b, crypt_func):
'''
Get preimage a from A for f(a) = b where b in B
'''
a = 1
while(1):
x = crypt_func() # Not sure how to manage the arg passing here
if x == b:
return a
if a > 10000:
return -1
a += 1
Then I updated main():
def main():
b = 7
a = get_a(7)
print(F'The preimage a of b={b} is: {a}')
a = get_a_dynamic(b, power_mod_function(3, x, 17)) # Not sure how to pass my middle arg!!
print(F'Again the preimage a of b={b} is: {a}')
I'm getting the following error messages:
python pre_img_finder.py
The preimage a of b=7 is: 11
Traceback (most recent call last):
File "pre_img_finder.py", line 45, in <module>
main()
File "pre_img_finder.py", line 41, in main
a = get_a_dynamic(b, power_mod_function(3, x, 17))
NameError: name 'x' is not defined
I don't know how to set it up right and do the variable passing so that I can pass the static variables once in main and the middle test variable x will always increment and eventually find the results I want.
Perhaps I just need to receive a function that begins with a "type" argument that acts as a kind of switch, and then takes a variable number of arguments depending on the type. For example, we could call the above a base-power-mod function or (bpm), where "power" is the answer we're looking for, i.e. a is the pre-image of b in technical terms. Then just call
main():
a = get_a_dynamic(7, ("bpm", 3,17))
And then implement it that way?
Thanks for your help!
Use *args to pass additional arbitrary number of arguments to the function.
def get_a_dynamic(b, crypt_func, *args):
'''
Get preimage a from A for f(a) = b where b in B
'''
a = 1
while(1):
x = crypt_func(*args)
if x == b:
return a
if a > 10000:
return -1
a += 1
Then call it in your main like this
def main():
b = 7
a = get_a(7)
print(F'The preimage a of b={b} is: {a}')
a = get_a_dynamic(b, power_mod_function, 3, x, 17)
print(F'Again the preimage a of b={b} is: {a}')
The way to generate dynamic functions with partial defined arguments is... functools.partial
from functools import partial
def get_a_variable_with_func(b, func):
'''
Get preimage a from A for f(a) = b where b in B
'''
a = 1
while(1):
x = func(a)
if x == b:
return a
if a > 10000:
return -1
a += 1
b = 7
def power_mod_function(base, mod, x):
return (base ** x) % mod
partial_func = partial(power_mod_function, 3, 17)
a = get_a_variable_with_func(7, partial_func)
print(a)
>>>
11
By the way, this is more pythonic:
from functools import partial
def get_a_variable_with_func(b, func):
'''
Get preimage a from A for f(a) = b where b in B
'''
for a in range(10001):
if func(a) == b:
return a
return -1
def power_mod_function(base, mod, x):
return (base ** x) % mod
a = get_a_variable_with_func(7, partial(power_mod_function, 3, 17))
print(a)
When you do this :
a = get_a_dynamic(b, power_mod_function(3, x, 17))
you don't pass power_mod_function to get_a_dynamic, you pass its result
instead. To pass the function you just have to pass the function name.
Therefore, because the function needs a value internal to get_a_dynamic (the x arg) and also two external arguments (3 and 17), you must pass these two arguments to get_a_dynamic separately for it to be able to call the passed function with the three needed arguments.
For that purpose, the suggestion of AnkurSaxena could be used especially if if the number of args can vary. But you can also declare it like this :
def get_a_dynamic(b, crypt_func, pow, mod):
then use it like this :
a = get_a_dynamic(b, power_mod_function, 3, 17))
You do something like:
def get_a_dynamic(b, function, argtuple):
# …
x = function(*argtuple) # star-operator unpacks a sequence
# … et cetera
… in essence. You can then always check the range of argtuple when passing it around, or be scrupulous about your calling conventions – but that star-operator unpack bit is the crux of what you are looking for, I think.
If you want to pass the name of the function as a string (as per your example) you can do something like:
function = globals()["bpm"] # insert your passed string argument therein
… but that’s kind of sketchy and I don’t recommend it – better in that case to pre-populate a dictionary mapping function string names to the functions themselves.

I do understand what I did, now

I was trying to make variables inside a loop. i.e. I pass a pattern of variables, and the pattern of their values and the variables are accordingly created and stored in a text file.
But, I tried something off topic and did this:
a = lambda a: a
for i in ["a", "b"]:
b = eval(i)(a)
print(i)
the output was:
a
b
Can anyone please explain what has happened here?
Edit:
I have analysed its answer.
I will paste it below.
Please verify if it is correct.
Thank you!
Lets first break the problem in parts.
def a(n):
return n
b = eval("a")(a)
print("a")
b = eval("b")(a)
print("b")
We can clearly see that the output is due to the two print statements.
print("a")
print("b")
Thus the rest of the statements play no part in the output.
def a(n):
return n
b = eval("a")(a)
b = eval("b")(a)
These statements can simply be put across like this:
def a(n):
return n
b = a(a)
b = b(a)
The statement
b = a(a)
makes the same effect as
def b(n):
return n
Thus the entire code can be put across like this:
def a(n):
return n
def b(n):
return n
print("a")
print("b")
Thus there is no ambiguity in this question now.
Here's how you can deconstruct your loop to understand for yourself, and please don't do that as pointed out in the comment.
a = lambda a: a
# First iteration
i = "a"
b = eval(i)(a)
print(i) # a
# Second iteration
i = "b"
b = eval(i)(a) # eval("b") is now <function __main__.<lambda>(a)>
print(i) # b
You are printing the variable i (which takes the values "a" and "b" since you loop over ["a", "b"]). If you want to see which values the variable b takes, print b instead:
a = lambda a: a
for i in ["a", "b"]:
b = eval(i)(a)
print(b)
Lets first break the problem in parts.
def a(n):
return n
b = eval("a")(a)
print("a")
b = eval("b")(a)
print("b")
We can clearly see that the output is due to the two print statements.
print("a")
print("b")
Thus the rest of the statements play no part in the output.
def a(n):
return n
b = eval("a")(a)
b = eval("b")(a)
These statements can simply be put across like this:
def a(n):
return n
b = a(a)
b = b(a)
The statement
b = a(a)
makes the same effect as
def b(n):
return n
Thus the entire code can be put across like this:
def a(n):
return n
def b(n):
return n
print("a")
print("b")
Thus there is no ambiguity in this question now.

How to create a global variable in python

In my program I need a counter, but it just counts to one and not higher. Here is my code:
# set a counter variable
c = 0
def counter(c):
c += 1
print(c)
if c == 10:
methodXY()
def do_something():
# here is some other code...
counter(c)
this is the important part of my code. I guess the problem is that the method counter() starts with the value 0 all the time, but how can I fix that? Is it possible that my program "remembers" my value for c? Hope you understand my problem. Btw: I am a totally beginner in programming, but I want to get better
If you want to use outer variable "c" inside your function, write it as global c.
def counter():
global c
c += 1
print(c)
if c == 10:
methodXY()
You always call the function with the value 0 (like you expected). You can return "c"
and call it again.
Look:
# set a counter variable
c = 0
def counter(c):
c += 1
print(c)
return c
def do_something(c):
c=counter(c)
return c
for i in range(10):
c=do_something(c)

Remember Array value after Function call

If I write this:
c = []
def cf(n):
c = range (5)
print c
if any((i>3) for i in c) is True:
print 'hello'
cf(1)
print c
Then I get:
[1, 2, 3, 4]
hello
[]
I'm really new to programming, so please explain it really simply, but how do I stop Python from forgetting what c is after the function has ended? I thought I could fix it by defining c before the function, but obviously that c is different to the one created just for the function loop.
In my example, I could obviously just write:
c = range (5)
def cf(n)
But the program I'm trying to write is more like this:
b = [blah]
c = []
def cf(n):
c = [transformation of b]
if (blah) is True:
'loop' cf
else:
cf(1)
g = [transformation of c that produces errors if c is empty or if c = b]
So I can't define c outside the function.
In python you can read global variables in functions, but you cant assigned to them by default. the reason is that whenever python finds c = it will create a local variable. Thus to assign to global one, you need explicitly specify that you are assigning to global variable.
So this will work, e.g.:
c = [1,2,3]
def cf():
print(c) # it prints [1,2,3], it reads global c
However, this does not as you would expect:
c = [1,2,3]
def cf():
c = 1 # c is local here.
print(c) # it prints 1
cf()
print(c) # it prints [1,2,3], as its value not changed inside cf()
So to make c be same, you need:
c = [1,2,3]
def cf():
global c
c = 1 # c is global here. it overwrites [1,2,3]
print(c) # prints 1
cf()
print(c) # prints 1. c value was changed inside cf()
To summarise a few of these answers, you have 3 basic options:
Declare the variable as global at the top of your function
Return the local instance of the variable at the end of your function
Pass the variable as an argument to your function
You can also pass the array c into the function after declaring it. As the array is a function argument the c passed in will be modified as long as we don't use an = statement. This can be achieved like this:
def cf(n, c):
c.extend(range(5))
print c
if any((i>3) for i in c) is True:
print 'hello'
if __name__ == '__main__':
c = []
cf(1, c)
print c
For an explanation of this see this
This is preferable to introducing global variables into your code (which is generally considered bad practice). ref
Try this
c = []
def cf(n):
global c
c = range (5)
print c
if any((i>3) for i in c) is True:
print 'hello'
cf(1)
print c
If you want your function to modify c then make it explicit, i.e. your function should return the new value of c. This way you avoid unwanted side effects:
def cf(n, b):
"""Given b loops n times ...
Returns
------
c: The modified value
"""
c = [transformation of b]
...
return c # <<<<------- This
c = cf(1)

Why doesn't program print value?

I am wondering why the following program does not print 'b'. It is is very simple code; I think it must work; and do not know the reason why it doesn't.
def a():
if b > 10:
print 'b'
sys.exit(1)
# main
while 1:
a()
b += 1
b is global variable. Actual code is more complicated but the structure is the same as mine. I guess when I call a() function and if b is greater than 10, it shows 'b'. However, it does not go inside if-statement.
Would you help me out how to solve?
Thanks.
Globals are horrid learn not to use them, try something like this
import sys
def a(value):
if value > 10:
print value
print "Greater than 10!"
sys.exit(0)
b = 0
while True:
a(b)
b += 1
Another answers suggests not using globals, and I agree. If you still want to use globals, you should define b outside of the loop first.(if you do, then please post the complete code, because apart from that, it should work (and it does)).
Now, global b in the function definition is not necessary, because python guesses it is a global variable when you try to access it before assigning. But since it is not defined it raises an NameError:
NameError: global name 'b' is not defined
If you don't see that, so there's something else, you're not showing the actual code that has a problem.
This gives you in the end, something similar:
import sys
def a():
global b
if b > 10:
print 'b'
sys.exit(1)
b = 0
# main
while 1:
a()
b += 1
Global vars are not the usual way to go. You may prefer the usage of nested functions instead:
import sys
def outer(value=0):
count = [value]
print "started at:", count[0]
def inner(x=1):
print "current val:", count[0]
count[0] += x
if count[0] > 10:
print "stopped at:", count[0]
sys.exit(0)
return inner
f = outer(5)
while True:
f(1)
You need to define b before "+="ing it.
def a():
if b > 10:
print 'b'
sys.exit(1)
# main
b = 0 # HERE
while 1:
a()
b += 1
By the way, as many had told you: avoid globals.
just my 2 cents: forget global variables.
anyway, this should work
def a():
global b
if b > 10:
print 'b'
sys.exit(1)
EDIT FUUUUUUUUUUUUUUU
Although I fully agree with Jackob on how you should use functions arguments and avoid globals, just for the record, here's the solution with global:
def a():
global b
if b > 10:
print 'b'
sys.exit(1)
# main
b = 0
while 1:
a()
b += 1

Categories

Resources