Trying to use function arguments as default arguments in one function - python-3.x

I am currently working on a recursive binary search algorithm. The details are not important, but I am trying to use a function parameter as the default value to another parameter:
def binary_search(items_list: List[int], item: int, lower = 0, upper = len(items_list)) -> bool:
In this function, if it is called without lower and upper bounds, it should just have the length of the list as the upper bound. Further on, however, I want to call this function recursively, and have its upper and lower bound defined by the binary search algorithm. My IDE says that items_list is an undefined name. Is there any way to use a (modification of a) function argument as a default value in the same function?
The full (faulty) code is:
from typing import List
def binary_search(items_list: List[int], item: int, lower = 0, upper = len(items_list)) -> bool:
middle = (lower+upper)//2
if len(lower-upper) == 0: return False
if items_list[middle] == item: return True
if item < items_list[middle]:
return binary_search(items_list, item, lower, middle - 1)
else:
return binary_search(items_list, item, middle + 1, upper)
I have no idea how to fix this, and in trying to look it up, I only get what default functional arguments are. I hope someone with more python knowledge can help me.

Since keyword arguments are not "aware" of other arguments, as you have experienced, you need to off-load this into the function itself. One option could be like this:
def binary_search(items_list: List[int], item: int, lower = 0, upper = None) -> bool:
if upper is None:
upper = len(items_list)
...

Related

Wrong networkx predecessors when used inside a function

I am trying to find the parents of my nodes in the graph G but when I use the predecessor method inside a function my filtering method returns the wrong answer.
MWE:
import networkx as nx
G=nx.MultiDiGraph()
G.add_node("Z_1")
G.add_node("Z_0")
G.add_node("X_1")
G.add_edge('X_1','Z_1')
G.add_edge('Z_0','Z_1')
Simple function to find nodes at different time-indices:
def node_parents(node: str, temporal_index: int = None) -> tuple:
#  Returns the parents of this node with optional filtering on the time-index.
if temporal_index:
# return (*[v for v in G.predecessors(node) if v.split("_")[1] == str(temporal_index)],)
return tuple(filter(lambda x: x.endswith(str(temporal_index)), G.predecessors(node)))
else:
return tuple(G.predecessors(node))
Now then, let's use the function:
node_parents("Z_1",0)
>>>('X_1', 'Z_0')
Ok. Let's use the predecessor method in a filter outside the function:
(*[v for v in G.predecessors('Z_1') if v.split("_")[1] == "0"],)
>>>('Z_0',)
All I want to do is to filter out, in this example, nodes which are zero-indexed (i.e. strings which have a zero at the end). But for some reason I am getting different answers. Why is this?
Thanks to #Paul Brodersen the correct way to write this is:
def node_parents(node: str, temporal_index: int = None) -> tuple:
# Returns the parents of this node with optional filtering on the time-index.
if temporal_index is not None:
# return (*[v for v in G.predecessors(node) if v.split("_")[1] == str(temporal_index)],)
return tuple(filter(lambda x: x.endswith(str(temporal_index)), G.predecessors(node)))
else:
return tuple(G.predecessors(node))

what is the mechanism for `def twoSum(self, nums: List[int], target: int) -> List[int]:` in python 3:

Ifound the code as follow in python3:
def twoSum(self, nums: List[int], target: int) -> List[int]:
return sum(nums)
As I know for python def, we only need follow:
def twoSum(self, nums, target):
return sum(nums)
what is the nums: List[int], target: int and ->List[int] means? Are those new features of python 3? I never see those.
Thanks,
from typing import List
def twoSum(nums: List[int], target: int) -> List[int]:
print(nums, target)
Link: https://docs.python.org/3/library/typing.html
Note The Python runtime does not enforce function and variable type annotations. They can be used by third party tools such as type checkers, IDEs, linters, etc.
Link: https://code.visualstudio.com/docs/python/linting
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
for i in range(len(nums)):
for j in range(i+1,len(nums)):
if target == nums[i]+nums[j]:
return [i,j]
num = [1,2,3,4,5,6,7,8,9,10]
target = 8
s = Solution()
print(s.twoSum(num,target))
#output [0,6]
Python has introduced type hinting, which mean we could hinting the type of variable, this was done by doing variable: type (or parameter: type), so for example target is a parameter, of type integer.
the arrow (->) allows us to type hint the return type, which is a list containing integers.
from typing import List
Vector = List[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
# typechecks; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])
In the function greeting, the argument name is expected to be of type str and the return type str. Subtypes are accepted as arguments.
def greeting(name: str) -> str:
return 'Hello ' + name
Documentation : https://docs.python.org/3/library/typing.html
It's a static typing in python for type checking. It allows you to define the type of input parameters and returns so that certain incompatibilities are dealt with beforehand. They are only annotations, not an actual static typing though. Check mypy package for more.
" nums : List[int] " states that nums is the name of the list function parameter/variable of type int
" target: int " is another function parameter/variable of type int.
" -> List[int] :" states that the return type of the function must be a list of integers .

Accommodating empy function parameter without default value

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

Python 3: best way to implement your own type with constraints

I'm doing a Python 3 based data conversion and certain character based fields I operate on have specific character allowances and length constraints applied to them.
I'd want to have some sort of swappable/configurable constraint function I roll myself that I could call.
Can you extend str?
Is it best to define a class for this and make variables implementations of that class.
Or are there simpler ways to do this with Python 3?
I'm wondering if anyone can give me pointers as to what to Google for inspiration?
(My initial thoughts are to look at SQLAlchemy's internal code for inspiration for things like Column).
EDIT: SQLAlchemy's code is too sophisticated for this scenario!
For example a type that only allows:
alphanumerics (upper+lowercase)
numerics
plus a selection of special characters.
This may vary by field, but some may use same function.
Hence desire to create custom re-usable types.
I'll do character stripping or substitution.
Then one may only allow 50 chars, whilst another may allow 500 etc.
I'll pass back a tuple with original value, converted value, a boolean to indicate truncation occurred
This is what I ended up with:
valobj.py
import utils
class UDT:
def __init__(self, converter, maxlen, value):
if utils.getClassName(converter) != 'function':
raise TypeError(f'converter {converter} is not a function')
if int(maxlen) <= 0:
raise TypeError(f'maxlen {maxlen} must be 1 or more')
if utils.getClassName(value) != 'str':
raise TypeError(f'value {value} is not a Python String')
self.converter = converter
self.maxlen = int(maxlen)
self.value = value
def convert(self):
intermed = self.converter(self.value)
truncated = len(intermed) > self.maxlen
result = intermed[:self.maxlen] if truncated else intermed
return (result, truncated, self.value)
class Job:
def __init__(self, name):
self._name_tuple = UDT(utils.fix_chars, 64, name).convert()
utils.py
import string
def getClassName(arg):
return(str(type(arg)).replace("<class '","").replace("'>",""))
def fix_chars(text) -> str:
result = ''
for c in text:
if ( (string.ascii_letters.find(c) != -1)
or (string.digits.find(c) != -1)
or ('._-#'.find(c) != -1)
):
result += c
else:
result += '_'
result = tidy_up_str(result)
return (result)
def tidy_up_str(text) -> str:
result = text
result = result.replace('_-_', '_')
while result.find('__') != -1:
result = result.replace('__', '_')
if result.endswith('_'):
result = result[:-1]
return result

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