Python function fails to initialize argument value - python

I have a function that iterates over a many levels nested dictionary (arg1) collecting data over each iteration, something like this:
def dummy(arg1, found=[], index=0):
found.append('xyz')
for d in arg1:
dummy(arg1[d], found, index+1)
return found
My functions work as it's supposte to, the problem is that when I call the function a second time, the found argument keeps the value from the previous function call, i.e. the return value from the second call includes the return values from the previous call. I had to add something like
if index == 0:
found=list() # restart value
to the beginning of the function to initialize the value of the found argument. Any idea why this happens? is this a bug?

No, it's not a bug; see here
To avoid this, you should do:
def dummy(arg1, found=None, index=0):
if found is None:
found = []
...
or better yet (see here):
sentinel = object()
def dummy(arg1, found=sentinel, index=0):
if found is sentinel:
found = []
...

Related

Closure : a function that returns the value of its previous call

I'm trying to build a function that returns the value of its previous call using closure. The first time function is called, it will return None. I'm not sure how to update last_in from one call to another.
def last_in(x):
last_in = [None]
def get():
temp = last_in[0]
last_in[0] = x
# print(last_in)
return temp
return get()
For example, print(last_in(1),last_in(2),last_in(3)) should print: None 1 2
The problem with your approach is that whenever you call last_in, i.e. the "outer" function, the previous value stored in last_in (the array, not the function) is reset to None. Instead, the outer function should be called only once so that the value is not reset each time you call it.
Not sure what you need this for, but I think it would make sense to create a decorator function for this, i.e. a function modifying an existing function. This way, all the storing-and-retrieving-the-last-result can be done in the decorator without cluttering the actual function. The outer function (the decorator) is called only once, and the original function is replaced with the decorated version that will correctly retrieve the stored value.
def return_previous(f):
f.last_result = None
def _f(*args, **kwargs):
res = f.last_result
f.last_result = f(*args, **kwargs)
return res
return _f
#return_previous
def some_function(x):
return x**2
print(some_function(1), some_function(2), some_function(3))
# None 1 4
I like the solution that #tobias_k provides, but here is another alternative which conforms to the current organization/structure of your code.
def last_in(x):
def get():
temp = last_in.__dict__.get('prev', None)
last_in.__dict__['prev'] = x
return temp
return get()
print(last_in(1),last_in(2),last_in(3))
None 1 2
This is a slight deviation from the request since it requires a second keyword argument but you could take advantage of the fact that default arguments are only set once (see here) to do something like this:
def last_in(x, __last=[None]):
last = __last[0]
__last[0] = x
return last
__last is set once when the function is declared and since it is mutable, you can update it at each function call and the updated value will persist between calls.

How to call function in if statement and save return value

I'm stuck in a simple question that I can't find an answer.
If want to call a function in an if statement. This is a function really challenging and it takes a long time to get response, how can I preserve the return value?
I explain the problem with an example:
function
def recursive:
if .... :
return value
else:
return False
recursive is an hypothetically function that takes a lot of time to generating response, that could be a value or just a simple boolean False.
main
...
if recursive():
...value? (make something with value return)
other method
...
if recursive():
value = recursive()
This other method will call the function 2 times and it takes too long time.
How can I solve this?
Python 3.8 will add an operator to do exactly this (called the walrus operator :=), but unfortunately the closest thing you can do today is this
value = recursive()
if value:
pass # do stuff with value
else:
pass # do other stuff with value
# can still do stuff with value here
If running on 3.8+, the following will be valid
if value := recursive():
pass # do stuff with value
else:
pass # do other stuff with value
# can still do stuff with value here

Fixing My Base 10 to Binary Converter

Right now, I have a base 10 to base 2 converter that works, however it always prints none at the end of every conversion.
base_two=0
def binary_recursion(base_ten):
global base_two
if base_ten==0:
print(base_two)
return
c=0
while base_ten//2**c>1:
c+=1
base_two+=10**c
if c==0:
print(base_two)
return
binary_recursion(base_ten-2**c)
I tried returning base_two as opposed to printing it, but that doesn't return a number, it also just returns None. Can anyone help me pinpoint my mistake?
def node(document_info, next_node):
return {'data': document_info, 'next': next_node}
def insert(head, new_document_info):
#insert new document into the linked list head
#returns the head of the modified list
if head is None:
return node(new_document_info, None)
if new_document_info[1] <= head['data'][1]:
return node(new_document_info, head)
head['next'] = insert(head['next'], new_document_info)
return head
Here's a slightly modified way of doing insertion sort, from my answer to you last question. You would start with head = None and then every time you add a print job do head = insert(head, document_info). Or after collecting all of your print jobs do something like
head = None
for document_info in list_queue:
head = insert(head, document_info)
You are not adding new element into queue. Assuming list_queue is a queue.
Queue has put function to add a new element into it.
def make_job():
temp_list=[]
list_queue = Queue()
for line in print_list:
if line[:6]=='submit': #If the command is submit, then the file must be placed in its
a=line.split() #correct spot in the linked list
del(a[0])
list_queue.put(a)#Contains file id, and the time required to print
temp_list.append(list_queue)
organize(list_queue) #Places the file in its correct spot in the linked list
else:
break
The Python queue module has a class called PriorityQueue that does exactly what you're looking for. For your situation, using it would look something like this:
class Job(object):
def __init__(self, name, print_time):
self.name = name
self.print_time = print_time
def __lt__(self, other):
return self.print_time < other.print_time
import queue as _queue # Need to rename the module so it doesn't conflict with your 'queue' function
my_queue = _queue.PriorityQueue()
def make_job():
for line in print_list:
if line[:6]=='submit':
a=line.split()
del(a[0])
new_job=queue(a) # queue(a) now returns a Job, e.g. Job('101', 40), instead of a 2-element list
my_queue.put(new_job)
else:
break
Once my_queue has been constructed, then repeated calls to my_queue.get() will return the Jobs ordered by print_time.
If you want to be able to inspect the contents of the queue without removing elements (get removes the element it returns), you could append the Jobs to a list and call list_queue.sort() after every insertion. If this is a performance concern, you could find the right spot in the list yourself and call list_queue.insert(i, a). Deferring to Python's list.sort has some advantages, though; namely, it's stable.
Lastly, if you don't want to define a new class, you could use sorted or list.sort with a custom sorting function. This takes the place of the __lt__ member I defined for Job.
new_job=queue(a) # queue(a) is your original function, which returns 2-element lists like ['101', 40]
list_queue.append(new_job)
list_queue.sort(key=lambda a,b: return a[1]<b[1])

How can I yield a value from within a callback to a calling generator

I am trying to define something like the following generator in python 2.6:
def getGenerator(self, keyIterator):
def bufferFullCallback(list_of_keys):
some_values = api_call(list_of_keys)
for value in some_values:
yield value # I want this value to be yielded by getGenerator
for key in keyIterator:
with MyBuffer(self.buffer_size, bufferFullCallback) as buf:
buf.addToBuffer(key)
In here, I get a callback when the buffer is full, wherein I make some API call to get a bunch of values corresponding to the keys. Now, I need 'getGenerator' to yield these values that it receives in the callback function. However, if I yield values in the callback, that callback essentially turns into a generator; this is clearly the wrong approach. Could you please suggest the correct way to yield values here from within a callback, or even perhaps a different refactoring that could help?
Something like this:
def getGenerator(self, keyIterator):
results = []
def bufferFullCallback(list_of_keys):
results.extend(api_call(list_of_keys))
for key in keyIterator:
with MyBuffer(self.buffer_size, bufferFullCallback) as buf:
buf.addToBuffer(key)
for value in results:
yield value

How to write pop(item) method for unsorted list

I'm implementing some basic data structures in preparation for an exam and have come across the following issue. I want to implement an unsorted linked list, and have already implemented a pop() method, however I don't know, either syntactically or conceptually, how to make a function sometimes take an argument, sometimes not take an argument. I hope that makes sense.
def pop(self):
current = self.head
found = False
endOfList = None
while current != None and not found:
if current.getNext() == None:
found = True
endOfList = current.getData()
self.remove(endOfList)
self.count = self.count - 1
else:
current = current.getNext()
return endOfList
I want to know how to make the statement unsortedList.pop(3) valid, 3 being just an example and unsortedList being a new instance of the class.
The basic syntax (and a common use case) for using a parameter with a default value looks like this:
def pop(self, index=None):
if index is not None:
#Do whatever your default behaviour should be
You then just have to identify how you want your behaviour to change based on the argument. I am just guessing that the argument should specify the index of the element that should be pop'ed from the list.
If that is the case you can directly use a valid default value instead of None e.g. 0
def pop(self, index=0):
First, add a parameter with a default value to the function:
def pop(self, item=None):
Now, in the code, if item is None:, you can do the "no param" thing; otherwise, use item. Whether you want to switch at the top, or lower down in the logic, depends on your logic. In this case, item is None probably means "match the first item", so you probably want a single loop that checks item is None or current.data == item:.
Sometimes you'll want to do this for a parameter that can legitimately be None, in which case you need to pick a different sentinel. There are a few questions around here (and blog posts elsewhere) on the pros and cons of different choices. But here's one way:
class LinkedList(object):
_sentinel = object()
def pop(self, item=_sentinel):
Unless it's valid for someone to use the private _sentinel class member of LinkedList as a list item, this works. (If that is valid—e.g., because you're building a debugger out of these things—you have to get even trickier.)
The terminology on this is a bit tricky. Quoting the docs:
When one or more top-level parameters have the form parameter = expression, the function is said to have “default parameter values.”
To understand this: "Parameters" (or "formal parameters") are the things the function is defined to take; "arguments" are things passed to the function in a call expression; "parameter values" (or "actual parameters", but this just makes things more confusing) are the values the function body receives. So, it's technically incorrect to refer to either "default parameters" or "parameters with default arguments", but both are quite common, because even experts find this stuff confusing. (If you're curious, or just not confused yet, see function definitions and calls in the reference documentation for full details.)
Is your exam using Python specifically? If not, you may want to look into function overloading. Python doesn't support this feature, but many other languages do, and is a very common approach to solving this kind of problem.
In Python, you can get a lot of mileage out of using parameters with default values (as Michael Mauderer's example points out).
def pop(self, index=None):
prev = None
current = self.head
if current is None:
raise IndexError("can't pop from empty list")
if index is None:
index = 0 # the first item by default (counting from head)
if index < 0:
index += self.count
if not (0 <= index < self.count):
raise IndexError("index out of range")
i = 0
while i != index:
i += 1
prev = current
current = current.getNext()
assert current is not None # never happens if list is self-consistent
assert i == index
value = current.getData()
self.remove(current, prev)
##self.count -= 1 # this should be in self.remove()
return value

Categories

Resources