Call a function without really calling the function? - python

I know my question sounds weird, but I am searching for this but I can't find it nowhere. I want to simulate a TableScan statement from SQL with printing out a list of lists, so I call the method next() with the object 'x' as long as ("EOF" of list) is not returned. But if I write
while(x.next() != "EOF"): the function next() is already called once and this not what I want, because I skip already one tuple.
Here the code:
class TableScan(Iterator):
def __init__(self, collection):
super().__init__()
self.collection = collection
self.iter = None
def open(self):
self.iter = iter(self.collection)
def next(self):
try:
while(self.iter != None):
return next(self.iter)
except StopIteration:
return "EOF"
# The list.
cS = [[101,2,3,5,1],
[202,4,99,2,4],
[303,2,4,6,8],
[404,1,23,4,6],
[505,2,22,4,5]]
# Making object x and calling constructor of class TableScan.
x = TableScan(cS)
while(x.next() != "EOF"): ###Problem- lines###
print(x.next())
Can somebody please help me?

Assign the result to a variable so you can test it and print it.
while True:
n = x.next()
if n == 'EOF':
break
print(n)

i know this has an answer, but in python 3.8 and above you can do:
while (n := x.next()) != 'EOF':
print(n)

Related

function within f-string is returning the function outside the string, and returning None inside the string

I'm new to python and trying to do an f-string as follows:
next_patient = East_Room.get_highest_priority()
print(f"The next patient is {next_patient.display_symptoms()} please")
Where East_Room is an instance of a Class and get_highest_priority is a method within the class to display a patient with the highest integer for the 'severity' attribute as follows:
def get_highest_priority(self):
tmp_priority_patient = None
current_size = self.SLL_waiting_list.size()
counter = 1
while counter <= current_size:
tmp_node = self.SLL_waiting_list.get_node(counter)
tmp_patient = tmp_node.get_obj()
if tmp_priority_patient == None:
tmp_priority_patient = tmp_patient
else:
if tmp_patient.severity > tmp_priority_patient.severity:
tmp_priority_patient = tmp_patient
counter = counter + 1
return tmp_priority_patient
def display_symptoms(self):
print(f"{self.firstname} {self.lastname}:{self.symptoms}")
This is the output:
Conor : Naseau
The next patient is None please
I know that this method works as it works perfectly if I call it without the f-string. thanks for you help!
display_symptoms only prints information but doesn't return anything.
In Python, function that don't return anything return None, hence the output you got: "The next patient is None please"
If you also want the function to return this string, you have to explicitly return it:
def display_symptoms(self):
print(f"{self.firstname} {self.lastname}: {self.symptoms}")
return f"{self.firstname} {self.lastname}: {self.symptoms}"
An even better way to do it would be to make it a property:
#property
def display_symptoms(self):
return f"{self.firstname} {self.lastname}: {self.symptoms}"

assert menu.__str__() == "" AssertionError

I get assertion error when i try to assert "" (empty string) into str function. Could anyone enlighten me as of why that happens. Totally clueless here. I know the str function needs to return a string but as far as i know it is returning a string when i run:
The error comes when i run:
menu = Menu()
assert menu.str() == ""
here is my code:
class Node:
def __init__(self):
self.counter = counter
my_list = []
self.my_list = my_list
def __str__(self):
for element in self.a_list:
if element:
return "\n".join(f"{counter}. {element}" for counter,
element in enumerate(self.my_list, 1))
print()
As the declaration is def __str__(self): you need to call it like
assert menu.__str__() == ""
Or using str method
assert str(menu) == ""
Also you have a for loop, that includes another loop on the same a_list. A good implementation is
# with classic for loop syntax
def __str__(self):
result = ""
for counter, element in enumerate(self.a_list, 1):
result += f"{counter}. {element}\n"
return result
# with generator syntax
def __str__(self):
return "\n".join(f"{c}. {elem}" for c, elem in enumerate(self.a_list, 1))
Your __str__() function does not return a string if nothing is added to the object before the assertion. An assertion error would be generated even if the function was called correctly.

How to eliminate recursion in Python function containing control flow

I have a function of the form:
def my_func(my_list):
for i, thing in enumerate(my_list):
my_val = another_func(thing)
if i == 0:
# do some stuff
else:
if my_val == something:
return my_func(my_list[:-1])
# do some other stuff
The recursive part is getting called enough that I am getting a RecursionError, so I am trying to replace it with a while loop as explained here, but I can't work out how to reconcile this with the control flow statements in the function. Any help would be gratefully received!
There may be a good exact answer, but the most general (or maybe quick-and-dirty) way to switch from recursion to iteration is to manage the stack yourself. Just do manually what programming language does implicitly and have your own unlimited stack.
In this particular case there is tail recursion. You see, my_func recursive call result is not used by the caller in any way, it is immediately returned. What happens in the end is that the deepest recursive call's result bubbles up and is being returned as it is. This is what makes #outoftime's solution possible. We are only interested in into-recursion pass, as the return-from-recursion pass is trivial. So the into-recursion pass is replaced with iterations.
def my_func(my_list):
run = True
while run:
for i, thing in enumerate(my_list):
my_val = another_func(thing)
if i == 0:
# do some stuff
else:
if my_val == something:
my_list = my_list[:-1]
break
# do some other stuff
This is an iterative method.
Decorator
class TailCall(object):
def __init__(self, __function__):
self.__function__ = __function__
self.args = None
self.kwargs = None
self.has_params = False
def __call__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
self.has_params = True
return self
def __handle__(self):
if not self.has_params:
raise TypeError
if type(self.__function__) is TailCaller:
return self.__function__.call(*self.args, **self.kwargs)
return self.__function__(*self.args, **self.kwargs)
class TailCaller(object):
def __init__(self, call):
self.call = call
def __call__(self, *args, **kwargs):
ret = self.call(*args, **kwargs)
while type(ret) is TailCall:
ret = ret.__handle__()
return ret
#TailCaller
def factorial(n, prev=1):
if n < 2:
return prev
return TailCall(factorial)(n-1, n * prev)
To use this decorator simply wrap your function with #TailCaller decorator and return TailCall instance initialized with required params.
I'd like to say thank you for inspiration to #o2genum and to Kyle Miller who wrote an excellent article about this problem.
Despite how good is to remove this limitation, probably, you have to be
aware of why this feature is not officially supported.

How to use the iterator class?

Im trying to create a iterator class that will give me a path throw a tree graph, which every iteration it will return the next step according to certain conditions.
So i looked up how to do this here : Build a Basic Python Iterator
and this is what i wrote so far :
def travel_path_iterator(self, article_name):
return Path_Iter(article_name)
class Path_Iter:
def __init__(self,article):
self.article=article
def __iter__(self):
return next(self)
def __next__(self):
answer= self.article.get_max_out_nb()
if answer != self.article.get_name():
return answer
else:
raise StopIteration
But I have a problem to call this class.
my output is always :
<__main__.Path_Iter object at 0x7fe94049fc50>
any guesses what im doing wrong ?
While Path_Iter is already an iterator, the __iter__-method should return self:
def __iter__(self):
return self
Next, to iterate an iterator, you need some kind of loop. E.g. to print the contents, you could convert the iterator to a list:
print list(xyz.travel_path_iterator(article_name))
Using a generator function:
def travel_path_generator(article):
while True:
answer = article.get_max_out_nb()
if answer == article.get_name()
break
else:
yield answer

Which operator do I need to overwrite to check if a self-defined object exist in the list?

For example, I have a self defined class, like this:
class Alarm(object):
def __init__(self, alarmId, msg):
self.alarmId = alarmId
self.msg = msg
def __eq__(self, other):
return self.alarmId == other.alarmId
aList = list()
a = Alarm(1, "hello")
b = Alarm(1, "good")
aList.append(a)
aList.append(b)
Alarms with same Id are considered same, so "a" and "b" is actually same. I want to check if same Alarm already exist in the list, if it already existed , then no need to add it to the list.
if a in aList: # I wish when this "in" called, I could call one member function of a to match the whole list
pass
But which function do I need to overwrite to do this? I tried __eq__, but it could not accomplish what I want.
I think is what you are after (assuming you compering using self.alarmId):
class Alarm(object):
def __init__(self, alarmId, msg):
self.alarmId = alarmId
self.msg = msg
def __eq__(self, other):
return (isinstance(other, self.__class__)
and self.alarmId == other.alarmId)
aList = list()
a = Alarm(1, "hello")
b = Alarm(2, "good")
aList.append(a)
aList.append(b)
if a in aList:
print("a found")
c = Alarm(3, "good")
if c not in aList:
print("c not found")
Result is:
a found
c not found
Deducing from your question, I think you are looking for a conditionall append() function for your list. This would then be something like the following:
def listadd(list, toadd):
for alarm in list:
if alarm == toadd:
return false
list.append(toadd)
return true
You could use this function to add alarms to your list and it checks right away if the alarm is in the list. This is obviously not an overloaded function or operator but it should work.
Hope it helps.
EDIT:
You can call the function with the list you want to add to and the item you want to add. It returns a boolean flag if the item was added or not.

Categories

Resources