Pythonic way to detect which optional parameters are present - python

Still fairly new to python.
I was wondering what would be a good way of detecting what output response a python program were to choose.
As an example, if you were to make a speed/distance/time calculator, if only 2 input were ever given, how would you detect which was the missing input and therefore the output? I can think of some fairly crude ways but I was wondering if there was anything else if more complex tasks were to come into play.
I guess something like:
def sdf(speed=0, distance=0, time=0):
# detect which parameter has no input / equals 0
# calculate result
# return result
sdf(speed=10, distance=2)
Any ideas?

Python allows you to change types of variables on the fly. Since you are working with integers and 0 could be a useful value in your calculations, your default 'not present' value should be None:
def sdf(speed=None, time=None, distance=None):
if speed is None:
return calculate_speed(time, distance), time, distance
if time is None:
return speed, calculate_time(speed, distance), distance
if distance is None:
return speed, time, calculate_distance(speed, time)
# All paramters have been set! Maybe check if all three are correct
return speed, time, distance
speed, time, distance = sdf(speed=1, distance=2)
This way you don't have to find out what happened afterwards. This function will give you all three values, given you gave it at least 2 out of the 3.
If your program flow allows for multiple values be None, your functions calculate_XY should throw an exception if they detect it. So in this case:
def calculate_distance(speed, time)
return speed * time
It will throw an unsupported operand exception(TypeError), so no need to clutter your code with useless asserts.
If you really don't know how many parameters will be set, do something like this:
try:
retval = sdf(None, None, x)
except TypeError as e:
print(e)
handle_exception(e)
Also just a heads up: the is operator in Python checks if the objects are the same object, not their value. Since objects that are assigned to None are just a 'pointer to the global None object'(simplification), checking whether a value 'contains' None with is is preferred. However be aware of this:
a = b = list()
a is b
True
# a and b are 'pointers' to the same list object
a = list()
b = list()
a is b
False
a == b
True
# a and b contain 2 different list objects, but their contents are identical
Just be aware that to compare values use == and to check if they are the same object, use is.
HTH

This is what I would do :
def sdf(distance=None, speed=None, time=None):
"""Calculate the missing speed, distance time value
returns a 3-tuple (speed, distance, time)
raises ValueError if more than one or no unknowns are given"""
if (distance, speed,time).count(None) > 1:
raise ValueError('Error - more than one unknown provided')
if (distance, speed,time).count(None) == 0:
raise ValueError('Not sure what to calculate - all paramaters provided')
if speed is None:
return distance/time, distance, time
if time is None:
return speed, distance, distance/speed
if distance is None:
return speed, speed*time, time

You should use multiple functions and call the one needed.
def CalculateTravelTime(distance, speed)
def CalculateTravelSpeed(distance, time)
def CalculateTravelDistance(speed, time)

Related

Updating local variable within function not working correctly [duplicate]

This question already has answers here:
Static variable in Python?
(6 answers)
Closed 1 year ago.
I'm trying to write a function that updates its local variable each time it is run but it is not working for some reason.
def max_equity(max_equity=0):
if current_equity() > max_equity:
max_equity = current_equity()
print(max_equity)
return max_equity
else:
print(max_equity)
return max_equity
and the function which it is calling
def current_equity():
for n in range(len(trade_ID_tracker)-1):
equity_container = 0
if (trade_ID_tracker[n,2]) == 0:
break
else:
if (trade_ID_tracker[n, 1].astype(int) == long):
equity_container += (df.loc[tbar_count,'Ask_Price'] - trade_ID_tracker[n, 2]) * trade_lots * pip_value * 1000
elif (trade_ID_tracker[n, 1].astype(int) == short):
equity_container += 0 - (df.loc[tbar_count,'Ask_Price'] - trade_ID_tracker[n, 2]) * trade_lots * pip_value * 10000
return (current_balance + equity_container)
but for some reason the max_equity() function prints current_equity() which I can only imagine means that either:
if current_equity() > max_equity:
is not doing it's job and is triggering falsely
or
max_equity = current_equity()
is not doing its job and max_equity starts at zero every time it is run.
In other words if I put max_equity() in a loop where current_equity() is
[1,2,3,4,5,4,3,2,1]
then max_equity() should return
[1,2,3,4,5,5,5,5,5]
But instead it returns
[1,2,3,4,5,4,3,2,1]
Here's a quick example test
ar = [1,2,3,4,5,4,3,2,1]
def stuff(max_equity=0):
if ar[n] > max_equity:
max_equity = ar[n]
print(max_equity)
else:
print(max_equity)
for n in range(len(ar)):
stuff()
Either way I'm kind of stumped.
Any advice?
local function variables are reset at each function call. This is essential for the behavior of functions as idempotent, and is a major factor in the success of the procedural programming approach: a function can be called form multiple contexts, and even in parallel, in concurrent threads, and it will yield the same result.
A big exception, and most often regarded as one of the bigger beginner traps of Python is that, as parameters are reset to the default values specified in the function definition for each call, if these values are mutable objects, each new call will see the same object, as it has been modified by previous calls.
This means it could be done on purpose by, instead of setting your default value as 0 you would set it as a list which first element was a 0. At each run, you could update that value, and this change would be visible in subsequent calls.
This approach would work, but it is not "nice" to depend on a side-effect of the language in this way. The official (and nice) way to keep state across multiple calls in Python is to use objects rather than functions.
Objects can have attributes tied to them, which are both visible and writable by its methods - which otherwise have their own local variables which are re-started at each call:
class MaxEquity:
def __init__(self):
self.value = 0
def update(max_equity=0):
current = current_equity()
if current > self.value:
self.value = current
return self.value
# the remainder of the code should simply create a single instance
# of that like ]
max_equity = MaxEquity()
# and eeach time yoiu want the max value, you should call its "update"
# method

Python function refactoring

I need help with refactoring my program. I have a function that I am calling in two programs. In one program i just need the overtimeAmount, and in the other program I need all three variables returned. How can I refactor this two only return the variables i need for the program.
def OT2(hours, rate):
if hours > 160.0:
overtimeHours = hours - 160.0
overtimeRate = rate * 1.05
overtimeAmount = overtimeHours * overtimeRate
else:
overtimeAmount = 0.0
overtimeRate = 0.0
overtimeHours = 0.0
return overtimeHours, overtimeRate, overtimeAmount
Instead of having one function that does two things, use two functions. That'll go a long way in terms of maintainability and follows the Unix philosophy of doing one thing well:
def get_overtime_hours(hours):
return max(0, hours - 160)
def get_overtime_info(hours, rate):
overtime_hours = get_overtime_hours(hours)
if overtime_hours > 0:
overtime_rate = rate * 1.05
overtime_amount = overtime_hours * overtime_rate
else:
overtime_amount = 0.0
overtime_rate = 0.0
return overtime_hours, overtime_rate, overtime_amount
It's good advice to never return a variable amount of results because it makes your function unpredictable; instead, either
always return the same number, (potentially making unused values None) and let the caller pick what to keep
return a dictionary (one result)
PEP 8 has some words about this in Be consistent in return statements, but doesn't explicitly cover your case
Be consistent in return statements. Either all return statements in a function should return an expression, or none of them should. If any return statement returns an expression, any return statements where no value is returned should explicitly state this as return None, and an explicit return statement should be present at the end of the function (if reachable) [..]
One possibility is to add a third parameter to indicate what you want returned and then an if statement to decide what to return. That doesn't seem any cleaner than just returning all 3 values and ignoring the ones you don't want.

Detecting value has returned to below threshold before allowing value change

I'm trying to design is a system that takes user input (from a continuously variable analogue potentiometer 0-100) and uses that input to set a value and I'm looking for a good method to handle a failure case.
I need to handle an error in the system that once detected sets the value to zero and requires the input to be brought back to a low value below a threshold before the user can again increase the value as required. I would also be fine for the value to return to zero if it allowed for simpler logic.
This seems like quite a common piece software safety logic however I have struggled to find any information about this problem on the internet. (I was thinking it might share some logic with a Schmitt trigger?)
If you have ideas about this problem or know of its name/ a good set of resources that would be much appreciated.
I have developed a simple python program as an example to perform this however I'm sure that is not the most robust or efficient method to solve this problem.
# check value has returned to below 5% before allowing
# increase after failure case
value = 0
user_command = 0
failure_case = True
while True:
## get input
raw_input = input()
if (raw_input == 'e'):
# if input is 'e'
# enter failure case
failure_case = True
else:
try:
# if input is a number
user_command = int(raw_input)
except:
pass
if (failure_case):
# a failure has been detected
print("Waiting for value to return to below 5")
# set value to zero
value = 0
# only remove the error flag once the
# input value is below 5
if (user_command < 5):
failure_case = False
else:
# no error thus set value to the user input
value = user_command
# print the accepted value
print(value);
Any help would be much appreciated.
Thanks.

Python Recursion Issue; I Can’t Change My Hard Code Into a Recursive Function

beside(picture,picture) #beside takes two pictures as arguments and prints them side by side in a 1:1 ratio.
stackn(n,picture) #stackn takes a number and a picture as arguments and prints n number of shapes in a vertical row.
show(picture) #show takes a picture as an argument and shows it on the canvas
In this case picture is the parameter heart_bb:
(n=2)# show(beside((stackn(1,heart_bb)),(stackn(2,heart_bb))))
(n=3)# show(beside((stackn(1,heart_bb)),(beside((stackn(2,heart_bb)),(stackn(4,heart_bb))))))
(n=4)# show(beside((stackn(1,heart_bb)),(beside((stackn(2,heart_bb)),(beside((stackn(4,heart_bb)),(stackn(8,heart_bb))))))))
My task is to come up with a recursive function(I’m going to call it test):
def test(n, picture):
I need this function to return the corresponding line of code shown above. For example, test(3,heart_bb) should return the line of code for n=3. Likewise, test(4,heart_bb) will return the line of code for n=4.
It has to work for any n>1, but after n=5 coding it gets really tedious.
def fractal(picture,n):
if n==1:
return(picture)
else:
return(beside((fractal(picture,(n-1))),(stackn((2**(n-1)), (picture)))))
I suppose you mainly need an idea of how you can do it and not a way to find someone that writes the code for you.
I would suggest to use a n-ary beside operation in place of your one, in such a way to simplify the code for n=2,3,4,... Since I cannot modify it I will define a new one in terms of your binary operation in this way:
def beside_pictures(pictures):
assert len(pictures) > 0
result = pictures[-1]
for tmp in pictures[:-1:-1]: # reverse order, starting from -1
result = beside(tmp, result)
return result
Now we are ready to transform your test function in a one line function:
def test(n, picture):
assert n > 0
show(beside_pictures([stackn(2**i,picture) for i in range(n)]))
UPDATE: If the requirement to have a recursive function is strict, one possible solution is the following one:
def test(n, picture):
if n == 1:
return stackn(1,picture)
return beside(test(n-1, picture), stackn(2**(n-1),picture))

python, how to write an iterative function

I am quering a database for some paramaters which depend on a attribute called count! count can be incremented incase the 1st query does not return anything. Here is a sample code
sls = {(213.243, 55.556): {}, (217.193, 55.793): {}, (213.403, 55.369): {}}
for key in sls.keys:
if not sls[key]:
ra, dec = key[0], key[1]
search_from_sourcelist(sl, ra,dec)
count = 1
def search_from_sourcelist(sl, ra,dec):
dist = count/3600.0
sls[(ra,dec)] = sl.sources.area_search(Area=(ra,dec,dist))
return
Incase i run the method search_from_sourcelist, and it doesnt return anything, i would like to increment count, and do the query again. This is to be done for all keys in sls dictionary, untill all the keys have a value!!
Here is the most fundamental recursive function
def countdown(n):
if n == 0:
return "Blastoff"
else:
print "T minus %s" % n
return countdown(n-1)
You will notice that countdown returns itself with a modified argument, in this case n but -1, so if you actually followed this all the way through you would get
(-> indicates a call)
countdown(5) -> countdown(4) -> countdown(3) -> countdown(2) -> countdown(1) -> countdown(0) #stop
So now you understand what a recursive function looks like you realize you never actually return a call of your own function, thus your code is not recursive
We use recursion because we want to boil a task down to its simplest form then work from there, so a good example of this would be the mcnuggets problem. So you need to tell us what you are trying to achieve and how it can be made a smaller problem (or more importantly why.) Are you sure you cannot do this iteratively? remember you don't want to blow your stack depth because python is NOT tail recursive by standard
Recursion is useful when you find a way to reduce the initial problem to a "smaller version of itself".
The standard example is the factorial function
def fac(n):
return n * fac(n-1) if n > 1 else 1
Here you reduce the problem of calculating the factorial of n to calculating the factorial of n-1.
In your code there is no such "reduction". You just increment a value and start the same problem over again. Thus, I recommend you solve it iteratively.
I'm not sure that you need a recursive algorithm for this.
Incase i run the method search_from_sourcelist, and it doesnt return anything, i would like to increment count, and do the query again. This can be done with a while loop as follows:
for key, value in sls.iteritems():
if not value:
ra, dec = key[0], key[1]
count = 1
while not search_from_sourcelist(sls, ra, dec):
count += 1
But if you really do want to do this recursively, you can do it as follows, leave a comment and I'll write it up.
Further, you should look into your search_from_sourcelist function, as it always returns None

Categories