closures with two inner functions python - python

I am trying to write a closure with two inner functions, but I am getting the below error
def factory(n=0):
#n=0
def current():
return n
return current
def counter():
n=n+1
return n
return counter
f_current,f_counter = int(input())
print(f_counter())
print(f_current())
I have the below error:
>>4
Traceback (most recent call last):
File "C:/Users/lokesh/Desktop/python/closure3.py",
line 13, in <module>
f_current,f_counter = int(input())
TypeError: 'int' object is not iterable
My requirement is after giving input 4,it should display:
4
5
I am new to python, can somebody help me here... thanks in advance

That looks more like what you want:
def factory(n=0):
def current():
return n
def counter():
nonlocal n
n += 1
return n
return current, counter
f_current, f_counter = factory()
print(f_current())
print(f_counter())
print(f_current())
print(f_counter())
Output:
0
1
1
2
With 4 as input:
f_current, f_counter = factory(4)
print(f_current())
print(f_counter())
4
5
factory() returns both inner functions. You need to use nonlocal to increment the n form the enclosing function. Without nonlocal you would not be able to modify n but would get:
UnboundLocalError: local variable 'n' referenced before assignment
because n is just a local variable. nonlocal n makes n from the enclosing function modifiable inside the inner function. Assessing n in current is fine, because Python's scoping rules allow read access to variables form an outer scope, here from the scope of the enclosing function.

Hi Mike ,I think non-local does'nt make any sense,I am giving the
solution which worked in my case.
def factory(n):
def current():
return n
def counter():
n=int(current())
n=n+1
return n
return current, counter
n=0
f_current, f_counter = factory((input()))
print(f_current())
print(f_counter())

def factory(n=0):
def current():
return n
def counter():
return n+1
return current, counter
f_current, f_counter = factory(int(input()))
print(f_current())
print(f_counter())

Mike's Nonlocal usage is very nice,but we can also access the variable value of n from enclosing scope by a new variable m inside Counter inner function and return it after incrementing.In that way,Nonlocal is not needed.
def factory(n=0):
def current():
return n
def counter():
m=n
m=m+1
return m
return current,counter
f_current,f_counter=factory(int(input()))
print(f_current())
print(f_counter())
`

You can simply use a new variable as the argument for the inner function which is equal to that of the outer function and proceed.
def factory(n=0):
def current():
return n
def counter(x=n):
return x+1
return current, counter
f_current,f_counter =factory(int(input()))
print(f_current())
print(f_counter())

Related

Iteration count in recursive function

I am writing a recursive function to make permutations of digits from 0 to n. The program will return the th permutation that is obtained. It all works well but I had to use the cheap trick of defining count as a list, that is count=[0]. In this way I am using the properties of lists in order to properly update the variable count[0] at each iteration.
Ideally, what I would like to do is to define count as an integer number instead. However, this does not work because count is then updated only locally, within the scope of the function at the time it is called.
What is the proper way to count the iterations in a recursive function like this?
Below I show the code. It works, but I hate the way I am using count here.
import numpy as np
N=10
available=np.ones(N)
def permutations(array, count=[0], n=N, start=0, end=N, th=100):
if count[0]<th:
for i in range(n):
if available[i]:
array[start]=i
if end-start>1:
available[i]=0
permutations(array, count, n, start+1, end)
available[i]=1
else:
count[0]+=1
break
if count[0]==th:
a=''.join(str(i) for i in array)
return a
def main():
array=[0 for _ in range(N)]
count=[0]
print(permutations(array, count, N, start=0, end=N))
if __name__=="__main__":
main()
Not necessarily ideal but to answer the question, one could use a global variable as follows:
import numpy as np
N = 10
available = np.ones(N)
count = 0
def permutations(array, n=N, start=0, end=N, th=100):
global count
if count < th:
for i in range(n):
if available[i]:
array[start] = i
if end-start > 1:
available[i] = 0
permutations(array, n, start+1, end)
available[i] = 1
else:
count += 1
break
if count == th:
return ''.join(str(i) for i in array)
def main():
array = [0 for _ in range(N)]
print(permutations(array, N, start=0, end=N))
print(f'{count=}')
if __name__ == "__main__":
main()
Output:
0123495786
count=100
Different ways to update a variable from other scopes... and each with its own advantages and disadvantages (performance, access to the variable, ...):
with global approach (as Pingu did),
with nonlocal
and with function's attribute.
The example under consideration, the factorial function, is merely illustrative but it can be easily readapted to your case.
def fact_global(n):
global counter
counter += 1
if n == 1:
return 1
return n*fact_global(n-1)
def fact_nonlocal(n):
counter = 0
def __fact(n):
nonlocal counter
counter += 1
if n == 1:
return 1
return n*__fact(n-1)
return __fact(n)
def fact_attr(n):
fact_attr.counter = 0
def __fact(n):
fact_attr.counter += 1
if n == 1:
return 1
return n*__fact(n-1)
return __fact(n)
n = 10
# case: global
counter = 0
fact_global(n)
print('global', counter)
# case: nonlocal
fact_nonlocal(n)
import inspect
fr = inspect.currentframe()
print('nonlocal', fr.f_locals['counter']) # not recommended, just for curiosity!
# case: function's attribute
fact_attr(n)
print('attr', fact_attr.counter)
Retrieving the value of the variable under investigation is quite straightforward with a global-setting and with function's attribute but not trivial (and not recommended) with nonlocal (inspect is more a debugging tool).
Here a partial result of the workbench:
n=860
fact_nonlocal(n): 2.60644 ± 0.00586
fact_global(n): 2.74698 ± 0.02283
fact_attr(n): 3.01219 ± 0.00539
The results are of the same order of magnitude (due to limitations of the host only tested with a maximum of n=860 so not reliable for an asymptotic conclusion), in this case it seems that it doesn't really matter which one you choose but it is more important to focus on how you are going to access to the variable later in the program.

How can I ensure that a function is "defined" in Python?

Trying to learn python as a java programmer. I would really appreciate some insight into why my program is telling me that my "isPrime" function isn't defined, especially with the use of 'self.'
import math
class Problem10:
def sumOfPrimesX(self, number):
sum = 0
for i in range(0, number):
if isPrime(i):
sum += i
return sum
def isPrime(self, x):
for n in range(0, math.floor(x/2)):
if x % n == 0:
return False
return True
print(sumOfPrimesX(input()))
all functions need it as their first parameter in a python program
No, only the instance methods, the methods related to a specific instance of a class. A simple function can need to parameter.
And you won't see the parameter self filled with the classic way of calling it, if you call the method on a instance it'll be filled by it
p = Problem10()
p.sumOfPrimesX(int(input("Give a value"))) # call on instance, one paramater given
# same as
Problem10.sumOfPrimesX(Problem10(), int(input("Give a value")))
# call on class itself, need to pass an instance as first to fill 'self
Also you need to wrap the input in an int, also start the loop at 2
p = Problem10()
print(p.sumOfPrimesX(int(input("Give a value"))))
class Problem10:
def isPrime(self, x):
for n in range(2, math.floor(x / 2)):
if x % n == 0:
return False
return True
The issue is both isPrime and sumofPrimesX are methods of the class Problem10.
Try the following:
import math
class Problem10:
def sumOfPrimesX(self, number):
sum = 0
for i in range(0, number):
if self.isPrime(i):
sum += i
return sum
def isPrime(self, x):
for n in range(0, math.floor(x/2)):
if x % n == 0:
return False
return True
pv = Problem10()
print(pv.sumOfPrimesX(input()))

When is the code for an inner function "available" for the outer function to use in python3?

Hello I am working on algorithms and I have written a working version of quickSort, see code below:
def quickSort(mylist, l, r):
if l < r:
q = partition(mylist, l, r)
quickSort(mylist, l, q-1)
quickSort(mylist, q+1, r)
def partition(mylist, l, r):
i = l-1
j = l
while j < r:
if mylist[j] < mylist[r]:
i += 1
mylist[i], mylist[j] = mylist[j], mylist[i]
j += 1
mylist[i+1], mylist[j] = mylist[j], mylist[i+1]
return i+1
mylist = [54,26,93,17,77,31,44,55,20,22]
l = 0
r = len(mylist) -1
quickSort(mylist, l, r)
However when I run this I get
UnboundLocalError: local variable 'partition' referenced before assignment
And the fix is to move the definition of the inner function partition at the top of quickSort so that it does not call partition before it is defined.
But I don't understand why, my guess is that inner functions do not "exist" before the outer one is actually executed. Can someone please clarify this point for me ?
In python, you can see functions just as callable variables.
For example you can assign them to variable names, like in the following example:
def example_function():
print("Hello world!")
example_var = example_function
example_var() # call the variable!
Just as you can reassign variables, you can also reassign functions definitions, which means that the definition of a function is not global:
def my_function():
print("first")
my_function() # prints "first"
def my_function():
print("redefined")
my_function() # prints "redefined"
So just as you wouldn't expect something like this ...
# a _not_ defined above
print(a) # even if this worked, should it print "3" or "4"?
a = 3
a = 4
... to work, because the variable is not defined yet, a call of a function, that has not been defined yet, is also not valid.
Like with any other variable, a definition stated in the future is also only valid in that future and it will be obsolete as soon as it is redefined.

How to alter the value of variable with a function?

How to alter the value of a variable with a function and store it permanently.
tried the code below but it doesn't alter the value of variable.
n=2
def f(x):
x+=2
return x
f(n)
print n #the output is 2 instead of 4 I want
Think of variable as labels to values, n is labeling 2, if you want n to label the value of the f function just label it again:
n=2
def f(x):
x+=2
return x
n = f(n)
print n
def f(x):
return x + 2
n = 2
n = f(n)
print(n)
This is how functions should be used. They receive values as arguments and return new values. When/where/how that is assigned to a variable is the caller's problem, since the variable is in the caller's scope.
If you want "self modification", a class is probably the better option:
class Foo:
def __init__(self, n):
self.n = n
def inc(self):
self.n += 2
f = Foo(2)
f.inc()
print(f.n)

if Python doesn't support method overloading, then why does this method overload work while this other does not?

If Python does not support method overloading (besides *args and **kwargs or PEP 3124), then why does this overload work?
# the sum from 1 to n
def sum(n):
if n > 0:
return n + sum(n - 1)
else:
return 0
print(sum(3))
# the sum from n to m, inclusive
def sum(n, m):
if n <= m:
return n + sum(n + 1, m)
else:
return 0
print(sum(3,5))
... while more baffling, this one does not:
# the sum of elements in an array
def sumArray(A):
return sumArray(A, len(A)-1)
# a helper for the above
def sumArray(A, i):
if i < 0:
return 0
else:
return A[i] + sumArray(A, i-1)
print(sumArray([1,2,3]))
You aren't overloading. You're hiding one thing behind another by using the same name for different objects. Try
sum = 42
and see how print(sum(3, 5)) ceases to work.
Function definitions are variable assignments. They create a function and assign it to the variable matching the name you used. You're seeing the ordinary effects of reassigning a variable.
def sum(n):
...
This assigns a function of 1 argument to the variable sum.
print(sum(3))
This uses the function assigned to that variable.
def sum(n, m):
...
This assigns a new function to the variable sum, replacing the first function.
print(sum(3,5))
This uses the new function. If you had tried to use the old function, you wouldn't find it.
# the sum of elements in an array
def sumArray(A):
return sumArray(A, len(A)-1)
# a helper for the above
def sumArray(A, i):
if i < 0:
return 0
else:
return A[i] + sumArray(A, i-1)
print(sumArray([1,2,3]))
This assigns a function to sumArray, then assigns a different function to sumArray, then tries to use the value from the first assignment. It finds the second function, and fails.
In your first example, you define function and use it, then overwrite it with another, and use the new one, just like with regular variables:
a = 1
print(a)
a = 2
print(a)

Categories