How to define optional arguments in functions in Stanza - stanza

Can I do something like this in Stanza?
defn set-color (x: Int, y: Int, color : Maybe<Tuple<Int>> ) : ; if not provided, color is defaulted to [0, 0, 0]
I am not sure this is the correct use of Maybe<>.
And the following calls are legal.
set-color(0, 0, [0, 100, 0])
set-color(100, 100)
Currently I use a paradigm of
defn set-color(x : Int, y : Int, color : Tuple<Int>|False ) :
But I want to know if there is a method to provide optional arguments.

Related

Using map python with key argument

I have a function that looks like this:
def myFunct(arg1=None,arg2=None,arg3=None):
pass
I would like to use that function with a map function but with argument 1 and 3 only.
idea would be:
map(myFunct,list_arg1,list_arg3)
so each of the call would be myFunct(value1,arg3=value3)
How could I achieve that ?
You could use lambda to map the arguments to your keyword arguments.
def foo(arg1=None, arg2=None, arg3=None):
return arg1 + arg3
list1 = [3, 4, 5]
list2 = [5, 6, 7]
print(list(map(lambda x, y: foo(arg1=x, arg3=y), list1, list2)))
Another approach is to keep your function as is and modify what you are mapping over:
from itertools import repeat
def f(x = 0, y = 0, z = 0):
return sum((x,y,z))
map(f,range(1,10),repeat(0),range(21,30))
Although from a readability point of view, a simple generator expression might be preferable to any solution based on map, something along the lines of:
f(x = i,z = j) for i,j in zip(range(1,10),range(21,30)))

Python splat-in-the-middle

You can put splat arguments in the middle rather than at the end (only in python 3 it seems):
import functools
def wierd_sum(use_str_cat=False, *args, use_product=False):
if use_str_cat:
return ''.join([str(a) for a in args])
elif use_product:
return functools.reduce(lambda a,b : a*b, args)
else:
return functools.reduce(lambda a,b : a+b, args)
Now how do you use said function?
print(wierd_sum(1, 2, 3)) # 23 -> Concatenation, 1 counts as True.
print(wierd_sum(False, 2, 3, 4, 5, True)) # 15 -> Addition, True counts as 1.
print(wierd_sum(False, 2, 3, 4, 5, use_product=True)) # 120 -> Multiplication 2*3*4*5
print(wierd_sum(use_str_cat=True, 1, 2, 3)) # SyntaxError: positional argument follows keyword argument.
print(wierd_sum(1, 2, 3, use_str_cat=False)) # TypeError: wierd_sum() got multiple values for argument 'use_str_cat'
My question is, is there ever, ever, EVER a reason to do such a thing?
This is to allow for keyword only arguments; similar to positional-only arguments (comparison here).
Ideally though, unless you actually need the varargs, you should omit the name to disallow varargs from being supplied:
def my_func(a, *, keyword_only=True):
pass
my_func(1, 2) # TypeError: my_func() takes 1 positional argument but 2 were given
my_func(1, keyword_only=2) # Fine

manipulating a Python list with treshold value

I need to make a function which would compare each value in a list and then set each value accordingly. Code follows:
actions = [0, 0, 0, 0.5, 0, 0.3, 0.8, 0, 0.00000000156]
def treshold(element, value):
if element >= value:
element == 1
else:
element == 0
treshold(actions, 0.5)
This code however results in the following error:
TypeError: '>=' not supported between instances of 'list' and 'float'
I understand what this error says, however I do not know how to fix that.
A compact way of doing this, as pointed out by user202729 is with a list comprehension. The key is, you need to do this for each entry into the list. If you want to run it on the whole list at once, you could consider using numpy
actions = [0, 0, 0, 0.5, 0, 0.3, 0.8, 0, 0.00000000156]
def treshold(element, value):
thresholded_list = [int(a>=value) for a in actions]
return thresholded_list
this function is essentially a shorthand for
def treshold_long(element_list, value):
thresholded_list = []
for element in element_list:
if element >= value:
thresholded_list.append(1)
else:
thresholded_list.append(0)
return thresholded_list
Thanks to user202729 I have discovered list comprehensions.
actions = [0, 0, 0, 0.5, 0, 0.3, 0.8, 0, 0.00000000156]
treshold = 0.5
actions = [1 if i>=treshold else 0 for i in actions]
print(actions)
This basically solves my problem. I also thank to user3235916 for a valid function.

Python 3 array average calculation

x=[1280.0, 2050.0, 709.0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
num1=0
den1=0
num2=0
den2=0
for i in range(0,3):
num1=num1+x[i]
den1=den1+1
del i
for i in range(0,6):
num2=num2+x[i]
den2=den2+1
avgc1= num1/den1
avgc2= num2/den2
val = (100* avgc1 / avgc2)
print(val)
The value of variable val should be 200 but I get 199.99999999999997. Could someone please help me understand the reason.
At the same time, if I try the following, it returns 200.
y=4039.0
x1=y/3
x2=y/6
x3=100*x1/x2
print(x3)
I get 199.99999999999997 for both (Python version 3.7.1). The issue is due to rounding errors in floating point arithmetic.
You can do as #Josh Friedlander said and use the double //, but this will result in floor division which may not be what you want. To maintain higher accuracy you can try using numpy for division.
import numpy as np
y=4039
x1=np.divide(y,3)
x2=np.divide(y,6)
x3=100*np.divide(x1,x2)
print(x3)
Returns
200.0
Works for your other case too:
x=[1280.0, 2050.0, 709.0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
num1=0
den1=0
num2=0
den2=0
for i in range(0,3):
num1=num1+x[i]
den1=den1+1
del i
for i in range(0,6):
num2=num2+x[i]
den2=den2+1
avgc1= np.divide(num1,den1)
avgc2= np.divide(num2,den2)
val = (100* np.divide(avgc1,avgc2))
print(val)
Returns
200.0
This is using np.__version__ 1.15.4 for reference.
Edit
As noted by #Mark Dickinson, order of operations is important. Putting parentheses around the division with pure Python will result in 200.0 without using numpy.
x=[1280.0, 2050.0, 709.0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
num1=0
den1=0
num2=0
den2=0
for i in range(0,3):
num1=num1+x[i]
den1=den1+1
del i
for i in range(0,6):
num2=num2+x[i]
den2=den2+1
avgc1= num1 / den1
avgc2= num2 / den2
# use parentheses to perform division first
val = (100* (avgc1 / avgc2))
print(val)
num1/den1 and num2/den2 are computed with floating-point arithmetic. This includes rounding exact mathematical results to values representable in floating-point.
The result is that avgc1 and avgc2 may differ from their ideal mathematical values, and so does their quotient.

How can I; if var is integer then execute

I am trying to create a decimal to binary converter. The user inputs their value, and the amount is divided by two each time and added to the invertedbinary list. The amount is then converted back into an integer, to be divided by two again and so on.
value = int(input("Please enter the decimal value to be converted to binary."))
invertedbinary = []
while value >= 1:
value = (value/2)
invertedbinary.append(value)
value = int(value)
print (invertedbinary)
for n,i in enumerate(invertedbinary):
if i == isinstance(invertedbinary,int):
invertedbinary[n]=0
else:
invertedbinary[n]=1
print (invertedbinary)
Let's say I input the number seventeen. This is the output:
[8.5]
[8.5, 4.0]
[8.5, 4.0, 2.0]
[8.5, 4.0, 2.0, 1.0]
[8.5, 4.0, 2.0, 1.0, 0.5]
[1, 1, 1, 1, 1]
So we can tell that from the last line of ones, my isinstance attempt did not work. What I want to be able to do, is that if the amount is anynumber.5 then to display it as a 1, and if it is a whole number to display as a zero. So what it should look like is [1, 0, 0, 0, 1]. Ones for each float value, and zeroes for the integers.
What can I use instead of is instance to achieve this?
For anyone wondering, I've called it invertedbinary because when printed invertedbinary needs to be flipped around and then printed as a string to display the correct binary value.
You can always check wether the round value is equal to the value...
if (round(x) == x):
# x is int
else:
# x is float/double

Resources