Function won't store a value - python

I am trying to write a Python script with a function.
The code below works as expected, it prints 3.
def function(a,b):
k = a+b
print(k)
a = 1
b = 2
function(a,b)
But when I move the print statement outside the function like this, it won't work.
def function(a,b):
k = a+b
a = 1
b = 2
function(a,b)
print(k) # -> NameError: name 'k' is not defined
Any ideas on how to not have the print statement inside the function and still get this code to work?

k is a local variable defined inside the function.
Case 1: Just return it:
def function(a,b):
k = a+b
return k # just return, does not make it global
a = 1
b = 2
k = function(a,b)
# 3
print(k) # variable was returned by the function
Case 2: Make it global:
def function(a,b):
global k #makes it global
k = a+b
function(a,b)
print(k) # it is global so you can access it
Please read more here

Instead of setting a global variable (global variables are often bad), why not return the result and print it?
Something like
def function(a,b)
return a+b
print(function(1,2))

Related

Problem with local variable. NameError: name 'b' is not defined in python

There is something wrong with my code. I still don't understand how local variable works. The following is an example of a simple code. And I have a NameError issue. Why? How can I fix this? I need to fix this error without Global variables! And there must be variable(a) ! What should I do for the answer of this code to come out 21?
def first(a):
a = 0
b = 3
return b
def second(a):
a = 0
j = 7
return j
def result():
return first(b) * second(j) # <-NameError: name 'b' is not defined in python
print(result())
You should define what does your b and j mean in string 10:
For python you are giving noting to function, but this function is asking for some value (a), it should be like this:
def first(a):
a = 0
b = 3
return b
def second(a):
a = 0
j = 7
return j
def result():
b = 123 # Defining what are we giving to our functions
j = 5
return first(b) * second(j) # Now it will work
print(result())
So you can use b and j value, and access return values:
b = 3
return b
j = 7
return j
Think like this, when you're returning some value, it fully replaces function with that value.
Here, b is only defined within the scope of function first()
This means that any code outside of this function cannot access that variable.
Unless the variable is marked as global b it will only be accessible within that 'block' of code
Example:
# Variable not defined in a function, therefore in global scope.
a = 10
def foo():
# Variable defined in function, only accessible within function
b = 10
# NOT RECCOMENDED
# Variable marked as global and accessible anywhere after assignment
global c
c = 10
# Additional Note (Not important or useful)
# Non local overrides local variables with a variable in an outer but not global scope
d = 10
def bar():
nonlocal d
d = 20
print(a) # 10 - No error, in global scope
print(b) # Error - b not in global scope
print(c) # 10 - No error, in global scope
# nonlocal (ignore)
print(d) # Error - d not in global scope
Short answer: local variables can only be used inside the function where they are defined.
Let's look at your code to see what is going on:
def first(a):
a = 0
b = 3. # b is defined inside of `first()`
return b
def second(a):
a = 0
j = 7
return j
def result():
return first(b) * second(j) # trying to use `b` inside result() gives an error because there is no variable with that name defined here.
print(result())
See the comments on the relevant lines. I don't know what you are trying to do here, so I can't give any suggestions about how to fix it.

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.

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)

Pass a variable that increases as it is called?

How can I do this in python?
a = 0
func(a+=1) # a = 1
func(a+=1) # a = 2
Now I have had to solve it like this:
a = 0
a+=1
func(a)
a+=1
func(a)
...
and there must be a better way, right?
Edit:
Actually I also want to be able to pass it to different functions:
a = 0
a+=1
func1(a)
a+=1
func2(a)
a+=1
func1(a)
...
your solution is okay, but if you want to have a counting side effect, use itertools.count object:
import itertools
def f(x):
print(x)
c = itertools.count()
f(next(c))
f(next(c))
or the variant, performing the next call in the functions themselves (itertools.counter is mutable so you can modify it inside the function):
import itertools
def f(c):
x = next(c)
print(x)
c = itertools.count()
f(c)
f(c)
you can initialize it to a non-zero value: c = itertools.count(3)
Something simple like this:
a = 0
a+=1;func1(a)
a+=1;func2(a)
Each line is only 2 characters longer than your original request.
You can have a wrapping function that calls your function f and simultaneously increment the value of j!
>>> def f(a):print("Value of a is: %d"%a)
...
>>> c=lambda i:(i+1,f(i+1))
>>> j=0
>>> j,_=c(j)
Value of a is: 1
>>> j
1
>>> j,_=c(j)
Value of a is: 2
>>> j
2
There is no way in the sense that in Python, assignment is an instruction, not an operator whose operation returns a value.
You'll have to define a function and either use the global keyword with a or turn a into a mutable. You can also use a decorator for your functions.
a = [0]
#a = 0 # alternative version
def inc(x):
x[0] += 1
return x[0]
# global a # alternative version
# a += 1
# return a
def f1(x):
return x + 1
def f2(x):
return x + 2
# or (inspired by #jpp comment) decorate your functions
def inc1(x):
def inner(x):
x[0] += 1
return x[0]
return inner
#inc1
def f3(x):
return x
for i in range(10):
print(inc(a))
print()
print(f1(inc(a)))
print(f2(inc(a)))
print()
a = [0]
print(f3(a))
print(f3(a))

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)

Categories

Resources