I am new to python. This might be a simple question, but if I have many functions that are dependent on each other how would I access lists from one function to use in another.
So...
def function_1():
list_1=[]
def function_2():
list_2= [2*x for x in list_1]
def function_3():
list_3= [x * y for x, y in zip(list_1, list_2)]
That is not the exact code but that is the idea of my problem. I would just put them all together in one function but I need them to be separate.
The correct way to do this would be to use a class. A class is an object that has internal variables (in your case, the three lists), and methods (functions that can access the internal methods). So, this would be:
class Foo(object):
def __init__(self, data=None):
self.list_1 = data if not data is None else []
def function_2():
self.list_2 = [2 * x for x in self.list_1]
And so on. For calling it:
foo = Foo() # list_1 is empty
foo2 = Foo([1,2,3]) # list_1 is not empty
foo2.function_2()
print foo2.list_2
# prints [2, 4, 6]
Make them arguments and return values:
def function_1():
return []
def function_2(list_1):
return [2*x for x in list_1]
def function_3(list_1, list_2):
return [x * y for x, y in zip(list_1, list_2)]
(this suggests that function_1 isn't much worth having...)
The exact way will depend on exactly how you want things to work, but here is a simple example:
def function_1():
return []
def function_2():
return [2*x for x in function_1()]
def function_3():
return [x * y for x, y in zip(function_1(), function_2())]
The key point is that functions do not generally just "do" things, they return things. If you have a value in one function that you want to use in another function, the first function should return that value. The second function should call the first function, and use its return value.
Functions are basically black boxes -- the outside world doesn't really know what goes on inside or what variables exist there. From the outside, other code only sees what goes in (the function's arguments) and what goes out (its return value).
So if your function computes some value that is to be used elsewhere, it should be returned as the result of the function.
E.g.,
def square(x):
return x * x
Takes a number, computes its square, and returns it.
Then you could do:
print(square(5))
and it will print 25.
So in your case you can return the lists and use them in the other functions, as the other answers showed:
def function_1():
return []
def function_2():
return [2*x for x in function_1()]
def function_3():
return [x * y for x, y in zip(function_1(), function_2())]
Related
Over here, the main function is g(x) and the helper function is h(). I noticed I can get the output for g(3), simply by binding x=3 and then doing any of the three
print(g(x))
g(x)
z=g(x)
But on the other hand, I noticed h() is outputted only when I type "print(h())". Are my observations correct or did I make a mistake? And also what is the logic behind this weird discrimination?
I like to think of it this way. Usually, if you had a line like "5" or "x=5", python doesn't give an output of 5. But functions have been given a special feature where they are invoked in any of the 3 ways. It's only that this special feature is being 'withdrawn' in the case of helper functions
The code you have written is equivalent to this:
def g(x):
def h():
any_name_you_want = 'abc'
return any_name_you_want
x += 1
print("in g(x)", x)
print(h())
return x
You cannot assign to a non-local variable inside a function. When Python creates the namespace for h, x is local to h because the assignment requires python to add the namespace for x at runtime.
Hence your code is also equivalent to :
def g(x):
def h():
return 'abc'
x += 1
print("in g(x)", x)
print(h())
return x
To get a sense of what is happening, run the following and then read up on UnboundLocalError:
def g(x):
def h():
x = x
return x
x += 1
print("in g(x)", x)
print(h())
return x
The goal is to try and access any function's sub functions. I've looked around and I'm not too sure there is a way to do it. When I've tried using
functions = [name for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isfunction)]
which returns the functions in some module (in the above __name__==__main__). When I have used that method, it doesn't return any sub functions. However I'd like to access sub functions that look something like
def f(x):
def y(x):
return x += 3
def z(x):
return x**2 - 1
x += y(x)
x += z(x)
return x
So it seems to me like there should be some way to access them with a magic method of f or some attribute of f. I have a hard time believing that those sub functions aren't stored as some attribute of f, but I have no idea.
In the end, what I need to do is to iterate through the sub functions of some function, so I thought the solution would look something like
for subfunc in f.__method_that_returns_subfuncs__():
if 'my_string' == subfunc.__name__:
out = subfunc(args)
I just need to be able to compare a string to a subfunction name then call that subfunction.
Thanks
There's no implicit list of functions to iterate over. You need to define it yourself. Simply functions can be assigned directly to a list by defining them with lambda expressions; more complex functions will need to be defined first, then added. Examples of each:
def f(x):
funcs = []
def y(x):
return x += 3
f.append(y)
f.append(lambda x: x**2 - 1)
for func in funcs:
x = func(x)
return x
If you care about the name, you can access it via the function object's __name__ attribute.
for func in funcs:
if func.__name__ == "some_func":
x = func(x)
I saw a question they wanted me to make a function to calculate the area of some shapes
the example code is below, I just don't understand what do that parenthesis work after brackets and how can I create a function to solve the question this way
code:
ls = area_func(['square', 'circle', 'rectangle', 'triangle'])
print(ls[0](1))
print(ls[1](2))
print(ls[2](2, 4))
print(ls[3](4, 5))
output:
1
12.566370614359172
8
10.0
From your code, I assume that area_function return 4 functions as list like
def area_func():
def square(x):
return x*x
# other functions
return [square,circle, rectangle, triangle]
and from this code, below it seems like you are calling these function at index 0,1,2,3
print(ls[0](1)) # ls[0] has reference to square function
print(ls[1](2)) # ls[1] has reference to circle function
print(ls[2](2, 4)) #ls[2] has reference to rectangle function
print(ls[3](4, 5)) #ls[3] has reference to triangle function
So, essecially doing
ls[0](1)
is equivalent to
square(1)
Could be many different things, for example - scope for passing parameters to a function:
def area_func(arr):
return [func1, func2, func3, func4]
def func1(x):
return '1'
def func2(x):
return '12.566370614359172'
def func3(x, y):
return '8'
def func4(x, y):
return '10.0'
ls = area_func(['square', 'circle', 'rectangle', 'triangle'])
print(ls[0](1))
print(ls[1](2))
print(ls[2](2, 4))
print(ls[3](4, 5))
area_func returns a list of functions.
Then the functions are call with different parameters.
ls[0] probably computes the area of a square, ls[1] for circle, and so on.
The area func is probably supposed to generate a list of functions based on the input given to it, so calling it with ['circle','square'] for example should return a list with just those two functions, in the specified order? For that, you probably want to have a dictionary of functions, something like this:
def area_func(func_list):
def square(x):
def circle(r):
def rectangle(h, w):
def triangle(h, b):
funcs = {'square':square, 'circle':circle, 'rectangle':rectangle,
'triangle':triangle}
return [funcs.get(x) for x in func_list if funcs.get(x) is not None] #avoids KeyError
Dictionaries of functions are a common way to do this kind of thing.
I have a simple class that adds 2 nos. Before adding 2 nos I pass a helper function that appends 2 zeros and passes the result.
When I try to print the add_nos.provide(append_zeros) it always shows None.
def append_zeros(x,y):
x = int(str(x) + '00' )
y = int(str(y) + '00')
print x+y
return x + y
class Add_Nos():
def __init__(self,input_array):
self.input_array = input_array
def provide(self,callback):
for each in self.input_array:
x,y = each
callback(x,y)
add_nos = Add_Nos([(1,2),(3,4)])
print add_nos.provide(append_zeros)
The method add_nos.provide(self, callback) has no return statement, thus it returns nothing, which in python means that it returns None.
To avoid this, either add a return statement to provide() or simply call the method without print.
It's not entirely clear what you are trying to do, but provide does not return anything. In python, the default return type of any function is None, so implicitly printing add_nos.provide(append_zeros) will do the function call, and then return None behind the scenes.
One option you have is to return self.input_array:
class Add_Nos():
def __init__(self,input_array):
self.input_array = input_array
def provide(self,callback):
for each in self.input_array:
x,y = each
callback(x,y)
return self.input_array
Note that you can also do for x, y in self.input_array: :)
Presumably, you actually want to be getting a new list out with the result of the computation. In this case, this is an excellent candidate for a list comprehension:
def provide(self,callback):
return [callback(x, y) for x, y in self.input_array]
This is a one-line equivalent of doing
def provide(self, callback):
ret = []
for x, y in self.input_array:
ret.append(callback(x, y))
return ret
You said:
I want the result to be 300 in the first instance and 700 in the
next instance, kind of generate a iterator object.
So you simply need to turn the .provide method into a generator, and then call it appropriately. Like this:
def append_zeros(x,y):
x = int(str(x) + '00')
y = int(str(y) + '00')
#print x+y
return x + y
class Add_Nos():
def __init__(self,input_array):
self.input_array = input_array
def provide(self,callback):
for each in self.input_array:
x,y = each
yield callback(x,y)
add_nos = Add_Nos([(1,2),(3,4)])
for t in add_nos.provide(append_zeros):
print t
output
300
700
That append_zeros function is a bit strange. Rather than converting the args to strings so you can append the zeros and then converting the results back to ints to do the arithmetic yu should simply multiply each arg by one hundred.
Also, you can make the .provide method a little more streamlined by using "splat" unpacking. And as tyteen4a03 mentioned, in Python 2 your Add_Nos class ought to inherit from object so that you get a new-style class instead of the deprecated old-style class. So here's another version with those changes; it produces the same output as the above code.
def append_zeros(x, y):
return x * 100 + y * 100
class Add_Nos(object):
def __init__(self, input_array):
self.input_array = input_array
def provide(self, callback):
for each in self.input_array:
yield callback(*each)
add_nos = Add_Nos([(1,2),(3,4)])
for t in add_nos.provide(append_zeros):
print t
Imagine I've got a Python module with some function in it:
def sumvars(x, y, z):
s = x
s += y
s += z
return s
But sometimes I want to get results of some intermediate calculations (for example, I could have a function which reverses a matrix and would like to know the determinant which has been calculated as an intermediate step as well). Obviously, I wouldn't want to redo those calculations again if they were already done within that function.
My first idea is to return a dict:
def sumvars(x, y, z):
d = {}
s = x
d['first_step'] = s
s += y
d['second_step'] = s
s += z
d['final'] = s
return d
But I don't recall any functions in numpy or scipy which return dicts and so it seems like this might be not a good idea. (Why?) Also routinely I'll always have to type sumvars(x,y,z)['final'] for a default return value...
Another option I see is creating global variables but seems wrong having a bunch of them in my module, I would need to remember their names and in addition not being attached to the function itself looks like a bad design choice.
What would be the proper function design for such situation?
Generally when you have two different ways you want to return data, go ahead and make two different functions. "Flat is better than nested", after all. Just have one call the other so that you Don't Repeat Yourself.
For example, in the standard library, urllib.parse has parse_qs (which returns a dict) and parse_qsl (which returns a list). parse_qs just then calls the other:
def parse_qs(...):
parsed_result = {}
pairs = parse_qsl(qs, keep_blank_values, strict_parsing,
encoding=encoding, errors=errors)
for name, value in pairs:
if name in parsed_result:
parsed_result[name].append(value)
else:
parsed_result[name] = [value]
return parsed_result
Pretty straightforward. So in your example it seems fine to have
def sumvars(x, y, z):
return sumvars_with_intermediates(x, y, z).final
def sumvars_with_intermediates(x, y, z):
...
return my_namedtuple(final, first_step, second_step)
(I favor returning namedtuples instead of dicts from my APIs, it's just prettier)
Another obvious example is in re: re.findall is its own function, not some configuration flag to search.
Now, the standard library is a sprawling thing made by many authors, so you'll find counterexamples to every example. You'll far more often see the above pattern rather than one omnibus function that accepts some configuration flags, though, and I find it far more readable.
Put the common calculation into its own function as Jayanth Koushik recommended if that calculation can be named appropriately. If you want to return many values (an intermediate result and a final result) from a single function then a dict may be an overkill depending on what is your goal but in python it is much more natural to simply return a tuple if your function has many values to return:
def myfunc():
intermediate = 5
result = 6
return intermediate, result
# using the function:
intermediate, result = myfunc()
Not sure if function attributes is a good idea:
In [569]: def sumvars(x, y, z):
...: s = x
...: sumvars.first_step = s
...: s += y
...: sumvars.second_step = s
...: s += z
...: return s
In [570]: res=sumvars(1,2,3)
...: print res, sumvars.first_step, sumvars.second_step
...:
6 1 3
Note: as #BrenBarn mentioned, this idea is just like global variables, your previously calculated "intermediate results" could not be stored when you want to reuse them.
Just came up with this idea which could be a better solution:
def sumvars(x, y, z, mode = 'default'):
d = {}
s = x
d['first_step'] = s
s += y
d['second_step'] = s
s += z
d['final'] = s
if mode == 'default':
return s
else:
return d
I belive the proper solution is to use a class, to have a better grasp of what you are modeling. For example in the case of the Matrix, you could simply store the determinant in the "determinant" attribute.
Here is an example using your matrix example.
class Matrix:
determinant = 0
def calculate_determinant(self):
#calculations
return determinant
def some_method(self, args):
# some calculations here
self.determinant = self.calculate_determinant()
# other calculations
matrix = Matrix()
matrix.some_method(x, y, z)
print matrix.determinant
This also allows you to separate your method into simpler methods, like one for calculating the determinant of your matrix.
Another variation:
def sumvars(x, y, z, d=None):
s = x
if not d is None:
d['first_step'] = s
s += y
if not d is None:
d['second_step'] = s
s += z
return s
The function always returns the desired value without packing it into a tuple or dictionary. The intermediate results are still available, but only if requested. The call
sumvars(1, 2, 3)
just returns 6 without storing intermediate values. But the call
d = {}
sumvars(1, 2, 3, d)
returns the same answer 6 and inserts the intermediate calculations into the supplied dictionary.
Option 1. Make two separate functions.
Option 2. Use a generator:
>>> def my_func():
... yield 1
... yield 2
...
>>> result_gen = my_func()
>>> result_gen
<generator object my_func at 0x7f62a8449370>
>>> next(result_gen)
1
>>> next(result_gen)
2
>>> next(result_gen)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
Inspired by #zhangxaochen solution, here's my take on your problem using class attributes:
class MyClass():
def __init__(self):
self.i = 4
def f(self):
s = self.i
MyClass.first_step = s
print(MyClass.first_step)
s += self.i
MyClass.second_step = s
print(MyClass.second_step)
s += self.i
return s
def main():
x = MyClass()
print(x.f()) # print final s
print(x.first_step)
print(x.second_step)
print(MyClass.second_step)
Note: I included several prints to make it more explicit how attribute values can be retrieved.
Result:
4
8
12
4
8
8