passing dictionaries to other functions - python

I've got a main function in my python code and several other functions. In my main, I've accessed another function that creates a dictionary. At the end of my python code is an if statement that writes text into a text file. I'm having trouble figuring out how to access the dictionary created from the previous functions.
Here is a model of how my code currently works
def main:
# "does something"
call function X
# does other stuff
def X:
#create dictionary
dict = {'item1': 1,'item2': 2}
return dictionary
....
.... # other functions
....
if __name__ == "__main__":
# here is where I want to write into my text file
f = open('test.txt','w+')
main()
f.write('line 1: ' + dict[item1])
f.write('line 2: ' + dict[item2])
f.close()
I'm just starting to learn python so any help is much appreciated! Thank you!

You have to add parentheses () when defining functions, even if it does not take any arguments:
def main():
...
def X():
...
Also, because X() returns something, you have to assign the output to a variable. So you can do something like this in main:
def main():
mydict = X()
# You now have access to the dictionary you created in X
You can then return mydict if you want in main(), so you can use it at the end of your script:
if __name__ == "__main__":
f = open('test.txt','w+')
output = main() # Notice how we assign the returned item to a variable
f.write('line 1: ' + output[item1]) # We refer to the dictionary we just created.
f.write('line 2: ' + output[item2]) # Same here
f.close()
You can not define a variable in a function and then use it elsewhere outside of the function. The variable will only be defined in the local scope of the relative function. Thus, returning it is a good idea.
By the way, it's never a good idea to name a dictionary dict. It will override the built-in.

Related

Get a Variable directly from function Python

i want to work with the variable "sets" after the function has been called.
How can i do this?
sets = 0
def search_str(monatsabrechnung, d1):
with open(monatsabrechnung, 'r') as file:
content = file.read()
if lastDay == heute and ja == 1:
sets = 1
else:
pass
search_str(monatsabrechnung, d1)
print(sets)
IIUC, you are trying to modify a variable in a function, which is originally defined outside a function. This is a variable scoping problem. Do check this awesome article to get an understanding of how variable scopes work in python.
Back to your code, the issue here is that even though you run the function to modify the variable sets to 1, python goes back to the outer scope where sets were set to 0.
sets = 0 #<-- outer scope
def search_str():
... #do something
sets = 1 #<-- inner scope
search_str()
print(sets) #back to outer scope
# 0
Solution 1: Pass as a parameter and return
You will have to pass the variable as a parameter to the function and then return it as follows -
sets = 0
def search_str(sets): #<-- pass as paramter
... #do something
sets = 1 #<-- modify
return sets
output = search_str(sets) #<-- save the output
print(output)
# 1
TIP: If your function is already returning another output, you can actually return, store and unpack multiple return values at once -
In your return statement, return everything you need return x, y, sets
Then, while calling use - X, Y, sets = search_str(...)
Solution 2: Set scope to global
If passing a parameter and returning is not an option for you, the scope of the variable has to be made global -
sets = 0
def search_str():
global sets #<-- set the scope to global
... #do something
sets = 1
search_str()
print(sets)
# 1
EDIT: As an additional pointer, as Matthias points out in his comments correctly, global scoping is usually avoided as it can cause a lot of problems if not careful.
Here is a great StackOverflow thread detailing Why are global variables evil?
Return the new value of sets from the function. If the if statement is true, then return 1, otherwise return the same value as before. To be able to return the old value you should add it as a parameter to the function.
sets = 0
def search_str(monatsabrechnung, d1, sets):
with open(monatsabrechnung, 'r') as file:
content = file.read()
if lastDay == heute and ja == 1:
current_sets = 1
else:
current_sets = sets
return current_sets
sets = search_str(monatsabrechnung, d1, sets)
Don't use global if you don't have to. You get side-effects and the code is less reusable.

Returning functions

I have functions that use returned variables.
How do I call them in a main function like this:
text = 'a'
def a(text):
text = x
return x
def b(x):
x = z
return z
def main():
# What do I put here to call function a and b?
main()
How do I call them
You already know how to call them ;)
def main():
...
main()
So I assume you are bewildered by:
def a(text):
text = x
return x
That x is not defined in a nor is it passed by argument to it. But that's OK. In python, all variables defined outside function are still visible inside it. Only exception is if argument of function have the same name as one of those variables. Then argument will take precedence.
This mechanism is called closure. Function close over some variable that already exists in scope when function is defined.
You can learn about it some more here:
https://www.learnpython.org/en/Closures
text = 'a'
def a(text):
text = x
return x
def b(x):
x = z
return z
def main():
x = a(text)
z = b(x)
main()
This might be what you want
It is not clear what are you trying to achieve. You are using variable x in the function a and variable z in function b without defining these two variables.
Moreover, you are setting variable text in function a without capturing it using statement global, look here for more information.
And global variables are considered to be bad practice.

How to access a Python function using it's __name__?

I have a function func :
def func(a):
print a
func.__name_ = "My_Function"
To get the name of the function I will just do func.__name__.
But is there a way to call func() by using its name i.e. "My_Function"?
Edit: There are going to be large number of functions for which this has to be done. Is there any better solution apart from keeping a mapping of function.name to the function. ?
It will be much easier to use a dictionary:
def func():
print('func')
func_dict = {"My_Function": func}
func_dict["My_Function"]()
# 'func'
Assuming that you want to access functions that are defined in global scope (not part of any class/object):
def foo():
print "foo"
def bar():
print "bar"
foo.__name__ = "1"
bar.__name__ = "2"
# locals().items() will return the current local symbol table, which is an iterable and
# it contains the globally defined functions.
symbol_table = locals().items()
# we will generate a list of functions that their __name__ == "1"
one_functions = [value for key, value in symbol_table if callable(value) and value.__name__ == "1"]
# now we can call the first item on the list - foo()
one_functions[0]()

Python - List of Assignments

Is there a way to have
statements = [statement1, statement2, statement3, ...]
in Python?
I want to be able to do:
run statements[i]
or:
f = statements[j] (where f is a function)
P.S. I want to have a list of assignment statements (lambda would not work) and I rather not create functions. For example:
switch = [output = input, output = 2 * input, output = input ** 2]
Is there any other way than defining a function for each entry?
Thank you everyone who answered my question.
Yes. Functions are first-class-citizens in python: i.e. you could pass them as parameters or even store them in an array.
It is not uncommon to have a list of functions:
You could build a simple registry in python like this:
#!/usr/bin/env python
processing_pipeline = []
def step(function):
processing_pipeline.append(function);
return function
#step
def step_1(data):
print("processing step1")
#step
def step_2(data):
print("processing step2")
#step
def step_3(data):
print("processing step3")
def main():
data = {}
for process in processing_pipeline:
process(data)
if __name__ == '__main__':
main()
Here the processing_pipeline is just a list with functions.
step is a so called decorator-function, which works like a closure.
The python interpreter adds while parsing the file every decorated #step to the pipeline.
And you are able to access the function with an iterator, or via processing_pipeline[i]: try adding processing_pipeline[2](data).
I want to be able to do: run statements[i]
well, you can do that by exec:
statements = ["result=max(1,2)","print(result)"]
for idx in range(len(statements)):
exec(statements[idx])
print(result)
Hope it helps!
This is perfectly fine:
def addbla(item):
return item + ' bla'
items = ['Trump', 'Donald', 'tax declaration']
new_items = [addbla(item) for item in items]
print(new_items)
It adds a political statement to every item in items :)
If you want to run a block of statements, use a function.
def run_statements():
func()
for i in range(3):
if i > 1:
break
extra_func()
run_statements()
If you want to choose specific statements from a list, wrap each one in a function:
def looper():
for i in range(3):
if i>1:
break
def func():
print('hello')
statements = [looper, func]
statements[-1]()
If your statements are simply function calls, you can put them directly into a list without creating wrapper functions.
You can do:
funcs = [min, max, sum]
f = funcs[0]
funcs[1](1,2,3) # out 3
funcs[2]([1,2,3]) # out 6
Since we've had every other way, I thought I'd toss this out:
def a(input):
return pow(input, 3)
def b(input):
return abs(input)
def c(input):
return "I have {0} chickens".format(str(input))
#make an array of functions
foo = [a,b,c]
#make a list comprehension of the list of functions
dop = [x(3) for x in foo]
print dop

Why I cannot pass my parameter python

I wrote a simple function to calculate mode, but it seems one parameter does not pass successfully.
I initial countdict= dict() in the main function, then I pass it mod = mode(magList, countdict).
In mode(alist, countdict), countdict= dict(zip(alist,[0]*len(alist))). and countdict can print in mode.
but when I try to print(countdict) in main function, the output says it is empty. I check my code, it says in function mode, I unused countdict. How could that be possible.
The whole code is as following:
def mode(alist, countdict):
countdict= dict(zip(alist,[0]*len(alist)))
for x in alist:
countdict[x]+=1
maxcount =max(countdict.values())
modelist = [ ]
for item in countdict:
if countdict[item] == maxcount:
modelist.append(item)
return modelist
def makeMagnitudeList():
quakefile = open("earthquakes.txt","r")
headers = quakefile.readline()
maglist = [ ]
for aline in quakefile:
vlist = aline.split()
maglist.append(float(vlist[1]))
return maglist
def mymain():
magList = makeMagnitudeList()
print(magList)
countdict= dict()
mod = mode(magList, countdict)
print("mode: ", mod)
print(countdict)
if __name__=='__main__':
mymain()
As I said earlier, the line:
countdict= dict(zip(alist,[0]*len(alist)))
will wipe out the reference to countdict that you passed in. Because of this, the countdict variable you are printing is the original, empty dictionary. The question Liarez linked to: How do I pass a variable by reference? will help explain why this is happening.
To get around this, you could change the return statement in the mode function to:
return (modelist, countdict)
which will return a tuple containing both modelist and countdict. When calling this function, you would write:
(mod, countdict) = mode(magList, countdict)
ensuring that the modified countdict is returned, meaning that your print function call should not output an empty dictionary.
The other thing to note is that the countdict you are passing into mode is empty anyway, so you may find it better to simply not pass this argument in and have mode take only one parameter.
This line of code is your problem.
countdict= dict(zip(alist,[0]*len(alist)))
Python dictionaries are mutable objects and can be changed in a function, however, dictionary itself is not passed to the function. Only reference is passed and is passed by value. It means that when you assign a new dictionary to your countdict parameter, you lose the original reference pointing at countdict created in your mymain function.

Categories

Resources