Python alternative to global variables - python

In this example test_function1 has 4 varibles that need to be used in test_funtion2.I would not like using global variables becouse the actual code i'm writing is more complex and it would break it.
def test_function1():
a = input("Type aaa:")
b = "bbb"
c = "ccc"
d = "ddd"
test_funtion1()
def test_function2():
if a == "aaa"
print(b)
print(c)
print(d)
test_function2()
I have a solution, but I am not sure if it is good or not.Could you tell me if this would work or if there is any other alternative.Thanks!
Sorry for my grammar , english is not my main language.
def test_function1():
a = input("Type aaa:")
b = "bbb"
c = "ccc"
d = "ddd"
return (a, b, c, d)
def test_function2():
if (test_funtion1()[0]) == "aaa"
print(test_funtion1()[1])
print(test_funtion1()[2])
print(test_funtion1()[3])

I think what you're looking for are classes.
a, b,c, d is your state, and an instantiation of such a class forms a state, which is basically the values referenced by these 4. Your first function is the "constructor" (called __init__) and the second function is then able to access these "instance variables".

I edited the solution that best fits me:
def test_function1():
a = input("Type aaa:")
b = "bbb"
c = "ccc"
d = "ddd"
return a, b, c, d
def test_function2():
x = test_function1()
if x[0] == "aaa":
print(x[1])
print(x[2])
print(x[3])
test_funtion2()

Passing arguments to functions and returning values from functions is indeed the first and most obvious way to avoid global state - but wrt/ to your snippet, you should avoid calling test_function1 four times, which is done by keeping the result in a local variable:
def test_function2():
result = test_funtion1()
if result[0] == "aaa"
print(result[1])
print(result[2])
print(result[3])
or in this specific case (when the function returns a tuple or ny sequence of known length) you could use tuple unpacking:
def test_function2():
a, b, c, d = test_funtion1()
if a == "aaa"
print(b)
print(c)
print(d)
Also, if you have a set of functions working on the same set of (related) variables, you may want to have a look at classes and objects.

You can also use this
def test_function1():
a = input("Type aaa:")
b = "bbb"
c = "ccc"
d = "ddd"
t = a, b, c, d
return t
def test_function2():
x = test_function1()
if x[0] == "aaa":
print(x[1])
print(x[2])
print(x[3])
test_function2()

Related

Assigning an OR statement to a variable in python

I have been looking for ways to assign a or statement to a variable, in a way that the variable can be used as a reference for other comparisons.
What i'm trying to accomplish by example:
a = 1
b = 0
c = a or b
print(a == c) #would return True
print(b == c) #would also return True
What you seem to want is somewhat close to the way sets work, with the operator | replacing or (which cannot be overridden):
a = {0}
b = {1}
c = a | b # or a.union(b)
a.issubset(c) # True
b.issubset(c) # True
{3}.issubset(c) # False
You could in principle make your own class that extends set:
class Singleton(set):
def __init__(self, n):
super().__init__([n])
def __eq__(self, other):
return self.issubset(other) or other.issubset(self)
a = Singleton(1)
b = Singleton(0)
c = a | b
print(a == c) # True
print(b == c) # True
But it is doubtful whether the confusing code this generates would ever be worth it.
You can change the definition of the == operator by creating a class and replacing your integer values with objects that contain each integer, so you will be able to override the equal operator with the __eq__ function. In this example, I will negate the result of the default operator to show you that you can apply whatever definition you need for that operation. The only disadvantage is that in Python, you can't override or redefine or:
class num:
def __init__(self, n):
self.n = n
def __eq__(self, n):
return not n==self.n
a = num(1)
b = num(0)
c = a or b
print(a == c)
print(b == c)
You can get something like that by using functools.partial and operator.or_:
a=True
b=False
c = partial(or_, a,b)
c()
True
But beware, a and b are evaluated at definition time:
a=False
c()
True

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.

Lambda inside dictionary comprehension

I could not decipher how this function is working, could somebody explain what the brackets after the curly braces mean?
def max(a,b):
f = {a >= b : lambda: a, b >= a: lambda: b}[True]
return f()
This is very convoluted (strange) definition for max, basically it creates a dictionary where the keys are the boolean True and False and the values are either a or b depending which one is the maximum. For example max(1,2) creates the following dictionary:
{ False: lambda: 1, True: lambda: 2}
Then f is assigned the function of the True value in the above example lambda: 2, which is a function that returns the constant value 2. Finally the function returns the call of f(), i.e. the value 2.
To answer your question more specifically, the brackets after the curly braces means get the value of the dictionary for the True key.
f = {a >= b : lambda: a, b >= a: lambda: b}[True]
Above statement will always get evaluated as either one of the following:
case 1: a > b
f = {True : lambda: a, False: lambda: b}[True]
which means f = lambda: a
which means f() is a
case 2: b > a
f = {False: lambda: a, True: lambda: b}[True]
which means f = lambda: b
which means f() is b
case 3: a = b
f = {True : lambda: a, True: lambda: b}[True]
which means f = lambda: a or it could be f = lambda: b
which means f() is a or b
If you don't know the clusters and the lambda function, it's hard to understand!
But this example teaches something:
{"name": "Jundullah", "age": 18}["name"] #ouput: "Jundullah"

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)

Python: variables not cumulative passing through functions

I am writing a function for a text adventure I'm making that acts as a progress bar when the player receives experience (which then levels the player up upon reaching 100). For some reason altering the values of my variables inside the function does not change their values outside the function even though I've returned all three. This becomes apparent when I try calling the function twice, each time adding 85 to the variable a.
Within the function, the objective is to pass the value of a to b, check if b is greater than or equal to 100, if so add 1 to c and remove 100 from b, then reset a to 0, print the result, and return the new values.
a = new experience b = current experience c = player level
a = 0
b = 0
c = 1
def func_1(a, b, c):
b = b + a
loop1 = 0
while loop1 < 1:
if b >= 100:
print(" ")
print("Add 1!")
print(" ")
c = c + 1
b = b - 100
else:
loop1 = loop1 + 1
a = a - a
print("c is " + str(c))
print("b is " + str(b))
print("a is " + str(a))
return a
return b
return c
a = a + 85
func_1(a, b, c)
a = a + 85
func_1(a, b, c)
print a, b, c
I'm really new to programming so I apologize for any inefficiencies. Thank you for any help and let me know if something doesn't make sense/is unclear.
Couple of things I see here:
First, out of the three return statements at the end of your code, only the first, return a, is executed. A return statement immediately stops execution of the function; return b and return c are never touched.
Second, you're having some confusion with the scope of the variables. a, b, and c defined outside of the function are global variables, while the a, b, and c passed into the function are local to the scope of the function. Thus, any modifications to the variables in your function won't affect the global variables.
You can do two things. First, have a global declaration at the beginning of the function:
def func_1():
global a
global b
global c
# Function body
This indicates to the function that a, b, and c are global variables that exist outside the function. Thus, passing in arguments is no longer needed; the function will search for variables outside the function. However, this is bad programming practice. The better option is to have func_1 return the modified values and reassign the global values to these new values, like so:
def func_1(a, b, c):
# Function body
return (a, b, c)
Then, to call the function and modify the variables outside the function:
a, b, c = func_1(a, b, c)
A couple suggestions:
You have a lot of incrementing going on, and python has specialized syntax for it: b = b + a can be shortened to b += a, c = c + 1 to c += 1, b = b - 100 to b -= 100. Also, simply reset a to 0 with a = 0 instead of subtracting a - a. Also, you don't need print(" "); print() will suffice.
Next, your while loop is unnecessary. Your function only needs to check once whether b >= 100, so there's no need to set up a loop. Increment b and then use a simple if statement to level up if necessary:
def func_1(a, b, c):
b += a
if b >= 100:
print("\nAdd 1!\n")
c += 1
b -= 100
a = 0
# Rest of the function
Inside func_1() the names a,b,c are local. When you change them nothing happens to the external a,b,c. You return the values correctly in the function, but then when calling the function you need to assign the values to the variables like this: a,b,c=func_1(a,b,c).
Returning a value doesn't set it unless you explicitly assign it in the calling function:
a, b, c = func_1(a, b, c)
Assigning inside the function doesn't affect the outer ones because they are considered "local scope". To counter that declare them global to affect the outer variables:
def func_1():
global a
global b
global c
Only one of these should be implemented
It is generally preferred not to declare globals. Ideally you should make a class for all of this, but these two options would require the least refactoring of your existing code
Note that a global variable (the variables outside of the function) are completely separate from the local variables (the variables inside the function).
This doesn't work because you can only return once. When you returned a, the function immediately stopped.
Also, since you didn't set any variable to the returned value, the global variables outside of the loop were unaffected. What you can do is return the a, b, and c values as a tuple, and then set the a, b and c global variables to that tuple.
return (a, b, c)
a, b, c = func_1(a, b, c)

Categories

Resources