Accommodating empy function parameter without default value - python-3.x

I'm writing a simple function in python 3.6 to find the distance between two points in n-dimensional space. I pass the coordinates as one-dimensional lists to my function. Here is what I have written:
def Distance(a: list[float], b: list[float]):
dimension = len(a)
sum = 0
for i in range(dimension):
sum += (b[i]-a[i])**2
return math.sqrt(sum)
This should work just fine if both a and b are passed explicitly. But I want to add additional functionality: if only a is passed, its distance from the origin will be calculated.
In C++, the language I am most familiar with, I would do this using function overloading. In that case, the two functions would simply have a different number of parameters. But this isn't an option for me in Python.
Any help with this would be greatly appreciated. Thank you in advance.
Edit:
The updated definition
def Distance(a: List[float], b=None):
if b:
arg = sum((x1 - x2)**2 for x1, x2 in zip(a,b))
else:
arg = sum(x**2 for x in a)
return math.sqrt(arg)
works for both cases.

An idiomatic definition could be
def distance(a, b=None):
from math import sqrt
d2=sum((x1-x2)**2 for x1,x2 in zip(a,b)) if b else sum(x**2 for x in a))
return sqrt(d2)
I confide that it's possible to use type hints as well, but I'm not an expert.
As a final remark, you used sum as a name, while it's recommended that you do not mask builtin names (I have used the sum builtin in my function definition)

The prototype must indeed be with None, so you have to change the function types because None is obviously not a list:
def Distance(a: list[float], b=None):
Then:
if not b:
b = [0.] * dimension

Related

Return value of a python function

I am new to python. Does all python function return some value? What will be the return value of the following function?
import math
def getQuadratic(a,b):
square = a**2 + b**2
squareRoot = math.sqrt(square)
return squareRoot
print("The square root of the sum of the squares of 3 and 4 is:", getQuadratic(3,4))
To evaluate the type returned by a Python function, you need to look at EVERY return statement, because each may return something different. And if a function doesn't have an explicit return, there's an implied return None at the end.
In your case there's only one return, and it's easy to figure out what type it's returning.
All python methods return something. Even if you have no return statement they will still return None.
def my_function():
pass
print(my_function())
>>> None
This function is definitely returning something. It's returning the value of the variable squareRoot. So when you're executing the print statement, the value that was returned is getting printed along with the string ahead of it.
Python being a dynamically typed language, does not require you to define any type for variables or functions.
Everything in python is a first class object.
On your example:
import math
def getQuadratic(a,b):
square = a2 + b2 # is this square? a**2?
squareRoot = math.sqrt(square)
return squareRoot
print("The square root of the sum of the squares of 3 and 4 is:", getQuadratic(3,4))
The variables a, b can take on any value.
Python does this by making everything a python object.
So, its easier to think of this way. int is your equivalent in C, however, in python it is treated as class <int>
However, static typing is now possible. It still depends on framework for static typing to be utilized. But your equivalent python program is interpreted as:
import math
def getQuadratic(a:int,b:int) -> float:
square = a2 + b2 # is this square? a**2?
squareRoot = math.sqrt(square)
return squareRoot
print("The square root of the sum of the squares of 3 and 4 is:", getQuadratic(3,4))
TL;DR
In direct answer to your question,
python does not require any types
a = 1 is valid.
a = 'SoF' is still valid
where a is a Python Object, and can be allocated to any other python object such as value, string, functions, or entire modules.
It really doesn't make much difference in types. Its the way Python is designed.

comparing elements of a list from an *args

I have this function that I need to compare the strings in a list to a *args
The reason being is that, the user should be able to type any words in the 2nd argument. However when I try to compare the strings to the *args it doesn't give me any results
def title_case2(title, *minor_words):
for x in title.split():
if x in minor_words:
print(x)
Assuming I ran the function with the parameters below. I was hoping it would display a and of since these words are found on those 2 entries.
title_case2('a clash of KINGS','a an the of')
*args is a tuple of arguments, so you're actually checking if x is in ('a an the of',). So either pass your argument as:
title_case2('a clash of KINGS', *'a an the of'.split())
Or, use this as your test:
if any(x in y for y in minor_words):
In either of the above cases the output is:
a
of
This is one approach.
Ex:
def title_case2(title, *minor_words):
minor_words = [j for i in minor_words for j in i.split()] #Create a flat list.
for x in title.split():
if x in minor_words:
print(x)
title_case2('a clash of KINGS','a an the of', "Jam")
using a for-loop instead of list comprehension
def title_case2(title, *minor_words):
minor_words_r = []
for i in minor_words:
for j in i.split():
minor_words_r.append(j)
for x in title.split():
if x in minor_words_r:
print(x)

Lambdify A Parametric Integral

I have the following issue: I want to lambdify a sympy expression containing parametric integrals like Integral(tanh(a*x),(x,0,1)). I tried to do a manual implementation like here.
What we want is essentially that the integral gets converted to something like:
lambda theta: quad(lambda x: g(x,theta), a,b)[0]
where
g = sp.lambdify((x,param), f, modules='numpy'))
Consider the following MWE:
import sympy as sp
import numpy as np
from scipy.integrate import quad
def integral_as_quad(function, limits):
x, a, b = limits
param = function.free_symbols - {x}
f = sp.lambdify( (x,*param), function, modules='numpy')
return lambda y: quad(lambda x: f(x,y), a,b)[0]
a, x = sp.symbols('a,x')
I = sp.Integral(sp.tanh(a*x),(x,0,1))
K = integral_as_quad(sp.tanh(a*x),(x,0,1))
L = sp.lambdify(a, I, modules=['numpy', {'Integral':integral_as_quad}] )
Then calling for example K(1) returns the correct value. However L(1) gives
AttributeError: 'Mul' object has no attribute 'tanh'
Does anyone have an idea how to fix this?
NOTE: Doing it manually is no option, since the expressions I deal with are way more complicated and may contain several different integrals. So I really need to get the lambdify working.
I think returning a lambda from integral_as_quad cannot work, because this lambda will never be called, as the Integral object in SymPy is not callable. Instead, the parameter tuple can be passed to quad via its args argument. Another change I made is in the outer lambdification, replacing
modules=['numpy', {'Integral':integral_as_quad}]
with
modules=[{'Integral': integral_as_quad}, 'sympy']
The idea is that at this stage we don't need NumPy functions yet, we just want to replace the Integral by our callable. The order of modules list matters: the dictionary comes first to prevent SymPy from keeping Integral as an Integral.
Now L(1) returns the correct amount.
import sympy as sp
import numpy as np
from scipy.integrate import quad
def integral_as_quad(function, limits):
x, a, b = limits
param = tuple(function.free_symbols - {x})
f = sp.lambdify((x, *param), function, modules=['numpy'])
return quad(f, a, b, args=param)[0]
a, x = sp.symbols('a,x')
I = sp.Integral(sp.tanh(a*x), (x,0,1))
L = sp.lambdify(a, I, modules=[{'Integral': integral_as_quad}, 'sympy'])
So one possible workaround I have found, but I am unhappy with because it is too slow for my application, is the following:
def to_lambda(expr, param):
# Preprocessing
expr = expr.evalf()
f = sp.lambdify([param], expr, modules='sympy')
fun = lambda x: np.array(np.array(f(x).evalf()), dtype='float64')
return fun
So first, expr gets cast into a lambda function using sympy-functions, e.g. we have
f = lambda a: Integral(tanh(a*x),(x,0,1))
and then we use sympy's internal integrator via evalf() (slow!).
Also, don't ask me why theres the double np.array, if one puts the dtype='float64' into the first one, then it returns TypeError: __array__() takes 1 positional argument but 2 were given

How To Use map() on a Function with Many Variables, and On Combinations Using Itertools

I'm currently studying pythons, subproccess() with map() in order to integrate it to my program.
Let's say I have a loop like this,
for a, b in itertools.combinations(exchanges, 2):
if (a != None and b != None):
symbols = a.symbols
symbols1 = b.symbols
if symbols is not None and symbols1 is not None:
symbols = [x for x in symbols if x is not None]
symbols1 = [x for x in symbols1 if x is not None]
if symbol != None and symbol in symbols and symbol in symbols1:
execute_function(a, b, symbol, expent,amount)
obviously I want my symbols and symbol1 lists mapped to the function and get it one by one.
and try different combination with it using itertools.
Tried this so far(just for mapping, as I have no knowledge on how to do that itertools comparing in this case), but seems to be returning a nonetype error. Object not callable.
pool = Pool()
pool.map(execute_func(a, b, symbol, expent,amount), symbols)
Any help is appreciated. Thanks.
In what you tried, the error is that the first argument of pool.map() should be a function but you are passing the result of the function, since you are calling it with a, b, symbol, expent, amount.
From what I understand, you want to call the function execute_func for all non-None symbols pair of all two-by-two combinations of the elements of exchanges. Then, I suggest you write the loops and non-None testing as a generator and then pass it to pool.map. Here's a sketch of my solution:
def gen_all_symbol_pairs(sequence):
for a, b in itertools.combinations(sequence, 2):
if a is not None and b is not None:
if a.symbols is not None and b.symbols is not None:
for symbol in a.symbols:
if symbol is not None and symbol in b.symbols:
yield a, b, symbol
with Pool() as pool:
pool.starmap(lambda a, b, symb: execute_func(a, b, symb, expent, amount), gen_all_symbol_pairs(exchanges))
Here, gen_all_symbol_pairs is an iterable that generates all non-None symbol pairs. Also, I used a lambda function to * partially* fill the execute_func function. Finally, I used pool.starmap so that every sequence yielded by the generator is star expanded in three arguments.
Hope this helps!

Python 3.X: Implement returnGreater() function using a list of integers and a value

The function must return a list consisting of the numbers greater than the second number in the function
It must be able to do the following when functioning:
returnGreater([1,2,3,4,5], 3)
[4,5]
returnGreater([-8,2,-4,1,3,-5],3)
[]
Here's what I have (I've gone through a few iterations), though I get a Type Error for trying to use a ">" symbol between an int and list:
def returnGreater (x,y):
"x:list(int) , return:list(int)"
#greater: int
greater = []
for y in x:
#x: int
if x > y:
x = greater
return greater
You're using the name y for two different things in your code. It's both an argument (the number to compare against) and the loop variable. You should use a different name for one of those.
I'd strongly suggest picking meaningful names, as that will make it much clearer what each variable means, as well as making it much less likely you'll use the same name for two different things. For instance, here's how I'd name the variables (getting rid of both x and y):
def returnGreater(list_of_numbers, threshold):
greater = []
for item in list_of_numbers:
if item > threshold:
greater.append(item)
return greater
You had another issue with the line x = greater, which didn't do anything useful (it replaced the reference to the original list with a reference to the empty greater list. You should be appending the item you just compared to the greater list instead.
I recommend filter. Easy and Graceful way.
def returnGreater(x, y):
return list(filter(lambda a:a>y, x))
It means, filter each element a in list x using lambda whether a is greater than y or not.
List Comprehensions
def returnGreater(_list, value):
return [x for x in _list if x > value]

Resources