Using an argument from one Function in a separate function - python

I have a function:
def create_discs(noDiscs):
which when called creates a specified number of discs, so for example:
create_discs(5)
will create 5 discs.
I then want to use the integer inputted into the create_discs function in a separate function:
def hanoi(disc_int):
In other words I would like disc_int to equal 5 (or whatever number is inputted)
Can anyone help me?

If you want two functions to share state like this, they should be defined as methods of a class.
class Hanoi(object):
def __init__(self, num_discs):
self.num_discs = num_discs
def create_discs(self):
# use value of self.num_discs
def hanoi(self):
# use value of self.num_discs
h = Hanoi(5)
h.create_discs()
h.hanoi()

If you're passing 5 to create_discs, can you do:
num = 5
create_discs(num)
hanoi(num)

You could make a closure:
def create_discs(num):
# create some discs
def hanoi_closure():
# now num is available within this function
# do hanoi stuff
return
return hanoi_closure
hanoi = create_discs(5)
hanoi()
In this case, create_discs defined your hanoi function within itself so that num was within its scope (automatically, no need to store anything in a global or a class!) and it returned the inner function so you could call it later.
If create_discs was already supposed to return something, then you could just return a tuple with what it was returning plus the inner function:
def create_discs(num):
# ...
return what_it_normally_returns, hanoi_closure
create_discs_result, hanoi = create_discs(5)
hanoi()

Related

Closure : a function that returns the value of its previous call

I'm trying to build a function that returns the value of its previous call using closure. The first time function is called, it will return None. I'm not sure how to update last_in from one call to another.
def last_in(x):
last_in = [None]
def get():
temp = last_in[0]
last_in[0] = x
# print(last_in)
return temp
return get()
For example, print(last_in(1),last_in(2),last_in(3)) should print: None 1 2
The problem with your approach is that whenever you call last_in, i.e. the "outer" function, the previous value stored in last_in (the array, not the function) is reset to None. Instead, the outer function should be called only once so that the value is not reset each time you call it.
Not sure what you need this for, but I think it would make sense to create a decorator function for this, i.e. a function modifying an existing function. This way, all the storing-and-retrieving-the-last-result can be done in the decorator without cluttering the actual function. The outer function (the decorator) is called only once, and the original function is replaced with the decorated version that will correctly retrieve the stored value.
def return_previous(f):
f.last_result = None
def _f(*args, **kwargs):
res = f.last_result
f.last_result = f(*args, **kwargs)
return res
return _f
#return_previous
def some_function(x):
return x**2
print(some_function(1), some_function(2), some_function(3))
# None 1 4
I like the solution that #tobias_k provides, but here is another alternative which conforms to the current organization/structure of your code.
def last_in(x):
def get():
temp = last_in.__dict__.get('prev', None)
last_in.__dict__['prev'] = x
return temp
return get()
print(last_in(1),last_in(2),last_in(3))
None 1 2
This is a slight deviation from the request since it requires a second keyword argument but you could take advantage of the fact that default arguments are only set once (see here) to do something like this:
def last_in(x, __last=[None]):
last = __last[0]
__last[0] = x
return last
__last is set once when the function is declared and since it is mutable, you can update it at each function call and the updated value will persist between calls.

How can I share a function variable within a nested function?

UPDATED:
How can I use a function variable within nested function? I've simplified my problem in the following example:
def build():
n = 1 # code to parse rpm package minor version from file
f = min_ver(n) # update minor version
return
def min_ver(n):
n = 2 # this is defined by another process, not set intentionally
s = 1 + n # still need the original value from build()
return s
The actual use case is that I'm grabbing a parsed rpm package minor version value in ex1() from disk called 'n'. When ex2() is executed from ex1(), it deletes the old package, builds a new rpm package with a new minor version. So when it calls for ex1()'s value within the nested function, it's not changed to the new version.
How can I maintain the original 'n' value within the nested function, before passing onto a new value of 'n' post nested function?
A simple way to do this would be to pass the variable as an argument to ex2.
def build():
n = int(1)
f = ex2(n) # pass the value to the next function
n = int(5)
return
def min_ver(n_old):
n = 2
s = 1 + n_old # use the n that was passed in
return s
If you make ex2() actually nested then you can access the outer variables.
def ex1():
n = int(1)
def ex2():
s = 1 + n
return(s)
f = ex2()
n = int(5) # done with nested value, rewrite new value
return()
Also, you probably want to return f or n instead of an empty tuple, I would imagine.
And you don't need to say int(1) you can just say 1. Everything, including integers and strings, is implicitly an object in python.

How to write a function keeping return the maximum value while calling it repeatedly

I am learning Python and practice some problem on the book.
The problem asks me to write a function keeping the max value.
The function (foo) works like below:
if call foo(1) then print 1
call foo(5) print 5
call foo(3) print 5
call foo(10) print 10
call foo(8) print 10
I don't know what is the key point of this problem.
Another way (and much more correct in terms of encapsulation for the production code) to complete the task is to use classes instead of functions and global variables:
class MaxPositiveValue:
def __init__(self):
self.max_value = 0
def __call__(self, new_value):
'''
This magic method will emulate function call
:param new_value: new value to compare
:return: max value
'''
if new_value > self.max_value:
self.max_value = new_value
return self.max_value
foo = MaxPositiveValue()
print(foo(1)) # Will print "1"
print(foo(5)) # Will print "5"
print(foo(2)) # Will print "5"
print(foo(10)) # Will print "10"
print(foo(4.6)) # Will print "10"
print(foo(12.8)) # Will print "12.8"
And if you want to properly compare both positive and negative numbers, you may use next code:
class MaxValue:
def __init__(self):
self.max_value = None
def __call__(self, new_value):
'''
This magic method will emulate function call
:param new_value: new value to compare
:return: max value
'''
if (self.max_value is None) or (new_value > self.max_value):
self.max_value = new_value
return self.max_value
foo = MaxValue()
print(foo(-10.4)) # Will print "-10.4"
print(foo(-30.1)) # Will print "-10.4"
print(foo(1)) # Will print "1"
print(foo(5.6)) # Will print "5.6"
print(foo(2)) # Will print "5.6"
print(foo(10)) # Will print "10"
In mathematics, if a function is given certain input, it always returns the same value. That is what pure(sorry about being vague in wording) functions do. It means, your function will forget every information it used once it's done its job. In this case, your functions is not likely to remember previous max value and you will not be able to solve your problem, right? That's why other people suggested somewhat complex solutions like global variables or class. They do different jobs but they are all about keeping previous state(or what happened in the past). I would suggest one more method to achieve your goal. This may seem harder for now, but you will appreciate this later.
# written in Python3, not Python2
def function_factory():
prev_max = None
def print_max(num):
nonlocal prev_max
# prev_max is None or smaller than num
if not (prev_max and prev_max > num):
prev_max = num
print(prev_max)
return print_max
# make an instacne of print_max and bind that
# new function to the name, my_func
my_func = function_factory()
my_func(3) # >> 3
my_func(5) # >> 5
my_func(3) # >> 5
I used what's called a closure, and if you are interested you can study functional programming. It's a bit involved but makes your code succinct.
Your question is about global variables. It is saying to create a variable that is not dependent upon that instance of the function. Instance is used (in this case) to describe when that function is being used. Setting the variable as a global keeps it as that value irrespective of being in a different time the function has been called.
This code would be the solution:
glob_max = 0 #This variable needs to be set before the function
#(assuming you're just using natural numbers otherwise set a smaller number)
def foo(numbr):
if numbr > glob_max: #This find if it is the max or not
glob_max = numbr #Sets the variable
global glob_max #Makes the variable global to remember it for other functions
print(glob_max) #Print the number as required

Define a function using string variable

I am trying to create a function "a21" that takes a parameter x and adds 4 to it.
eq = 'x+4'
b=21
new='a'+str(b)+'(x)'
def eval(new):
return eval(eq)
c=5
print(a21(c))
The desired output is 9 but it's not recognizing a21 as a function. How do I write this to create a the function a21 that also takes a parameter x?
Write a fully-featured function definition:
new = '''
def a21(x):
return x + 4
'''
And then execute it: exec(new) and run: a21(678).
If you want to construct a function during runtime, use string formatting.
new = '''
def {}({}):
return {}
'''
exec(new.format('test', 'x', 'x+4'))
test(123)
The following is possible and does almost the same thing:
You can bind the function in a function like below.
eq = 'x+4'
def bindfunc(name):
def dynamicfunc(x):
return eval(eq)
dynamicfunc.__name__ = name
return dynamicfunc
The way you would use this would be a little different:
b=21
new='a'+str(b) #your function name
c=5
print(bindfunc(new)(c))
What the last line does is that it first runs bindfunc which returns a function with the given name. It then runs that function with the input c as needed and prints output.
Hope this helps!

Re-evaluating a function to get a new random value in python

here is the code that I am having a problem with(simplified to make it clearer). It is for a text based game just to help learn things.
class Character(object):
def __init__(self):
self.level = 5
self.moveset = [None,None,None,None]
def movesetleveling(self):
if self.level > 4:
self.moveset[0] = Punch(self.level)
def punch(level):
damagedealt = random.randint(0,5)**level
return damagedealt
I would like to know how I can make self.moveset[0] = Punch() rather than being equal to the output of Punch() in this block of code. So that everytime i run it in a while loop it will re-evaluate the output of Punch() rather than evaluating Punch() once and assigning that to the 0th index of self.moveset[0].
You could assign a function to self.moveset[0] instead of its result (using functools.partial()):
from functools import partial
self.moveset[0] = partial(punch, self.level)
Then later, in your while loop, just call it:
while True:
new_punch_every_time = self.moveset[0]() #note: parentheses
self.moveset[0]() calls punch function with level parameter set to self.level (its value at the time of partial call).
It works because functions, methods are first class citizens in Python. You can pass them as parameters to other functions, return from functions, bind to a different name, append to a list, etc.

Categories

Resources