How does one determine the arguments for a function inside a function in python.
Consider an the following example:
def fun1():
mysum = 0
def fun2(arg):
mysum += arg
fun2(1)
fun2(2)
fun2(3)
print mysum
This can be written as
def fun1():
mysum = 0
def fun2(mysum, arg):
mysum += arg
fun2(mysum, 1)
fun2(mysum, 2)
fun2(mysum, 3)
print mysum
In the above case, sum can either be passed as argument or not. When does one determine if it should be passed as argument or not?
It depends on the situation. Do you want to modify a parameter variable or do you want your function to modify a closed variable. The latter may be less reusable, but in the end it is subjective.
In python3 you must use either global or nonlocal in order to modify any closed variables.
def fun1():
sum = 0
def fun2(arg):
nonlocal sum
sum += arg
fun2(sum, 1)
fun2(sum, 2)
fun2(sum, 3)
print sum
Related
I wrote the code which does the first part of task: it returns the count of calls of function
def counter():
val = [0]
def generate_count():
val[0] += 1
return val[0]
return generate_count
generate_count = counter()
print(generate_count())
But also I must be able to send start value of count into the func. As I know if u enter in ur function that u need to pass arguments then u are not be able to leave value blank. For example: If u write like this
def func1(n):
then you must pass one argument to make it work otherwise it wont work, so how to make it possible to work if u pass any arguments else if u don`t?
Use a default value:
def func1(n=0):
<code>
This function can be called with a parameter n, or it can be called without n. If you call the function like this:
func1()
The value of the parameter n will be set to 0, as you didn't specify a value.
It would probably make more sense to use a builtin generator for this case.
def counter(n=0):
while True:
n += 1
yield n
generate_count = counter(1)
print(next(generate_count)) # > 2
I am reading the following tutorial about Python decorators tutorial. Everything is more or less clear except the following code:
def call_counter(func):
def helper(x):
helper.calls += 1
return func(x)
helper.calls = 0
return helper
#call_counter
def succ(x):
return x + 1
print(succ.calls)
for i in range(10):
succ(i)
print(succ.calls)
I cannot fully understand helper.calls notation. Is is just variable with no relations to helper function? Also how does succ function gets access to calls?
In Python functions are objects, that means you can set variables too.
def func():
pass
func.count = 0
print(func.count) # 0
func.count += 1
print(func.count) # 1
We can rewrite the decoration to this:
def succ(x):
return x + 1
succ = call_counter(succ)
So now you have a decorated succ. As you can see in call_counter, it actually returns a function called helper. And this helper function has one attribute named calls which is used to count calls. So now when you call succ(i), you are actually calling that helper function.
And yes that calls is just a normal variable.
I am reading Hackers and Painters and am confused by a problem mentioned by the author to illustrate the power of different programming languages.
The problem is:
We want to write a function that generates accumulators—a function that takes a number n, and returns a function that takes another number i and returns n incremented by i. (That’s incremented by, not plus. An accumulator has to accumulate.)
The author mentions several solutions with different programming languages. For example, Common Lisp:
(defun foo (n)
(lambda (i) (incf n i)))
and JavaScript:
function foo(n) { return function (i) { return n += i } }
However, when it comes to Python, the following codes do not work:
def foo(n):
s = n
def bar(i):
s += i
return s
return bar
f = foo(0)
f(1) # UnboundLocalError: local variable 's' referenced before assignment
A simple modification will make it work:
def foo(n):
s = [n]
def bar(i):
s[0] += i
return s[0]
return bar
I am new to Python. Why doesn the first solution not work while the second one does? The author mentions lexical variables but I still don't get it.
s += i is just sugar for s = s + i.*
This means you assign a new value to the variable s (instead of mutating it in place). When you assign to a variable, Python assumes it is local to the function. However, before assigning it needs to evaluate s + i, but s is local and still unassigned -> Error.
In the second case s[0] += i you never assign to s directly, but only ever access an item from s. So Python can clearly see that it is not a local variable and goes looking for it in the outer scope.
Finally, a nicer alternative (in Python 3) is to explicitly tell it that s is not a local variable:
def foo(n):
s = n
def bar(i):
nonlocal s
s += i
return s
return bar
(There is actually no need for s - you could simply use n instead inside bar.)
*The situation is slightly more complex, but the important issue is that computation and assignment are performed in two separate steps.
An infinite generator is one implementation. You can call __next__ on a generator instance to extract successive results iteratively.
def incrementer(n, i):
while True:
n += i
yield n
g = incrementer(2, 5)
print(g.__next__()) # 7
print(g.__next__()) # 12
print(g.__next__()) # 17
If you need a flexible incrementer, one possibility is an object-oriented approach:
class Inc(object):
def __init__(self, n=0):
self.n = n
def incrementer(self, i):
self.n += i
return self.n
g = Inc(2)
g.incrementer(5) # 7
g.incrementer(3) # 10
g.incrementer(7) # 17
In Python if we use a variable and pass it to a function then it will be Call by Value whatever changes you make to the variable it will not be reflected to the original variable.
But when you use a list instead of a variable then the changes that you make to the list in the functions are reflected in the original List outside the function so this is called call by reference.
And this is the reason for the second option does work and the first option doesn't.
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)
i have homework and we need to do something like iterator, the func work great but the techer told he run the func with (t=Make_iterator()) like this, what i do wrong? tnx!
global x
x=-1
def Make_iterator(fn):
global x
x+=1
return fn(x)
fn=lambda y:y*2
t=Make_iterator(fn)
print(t())
I think you want a closure, which is a function defined within the local namespace of anther function, so that it can access the outer function's variables:
def make_iterator(func):
x = -1
def helper():
nonlocal x
x += 1
return func(x)
return helper
The nonlocal statement allows the inner function to modify the variable declared in the outer function (otherwise you'd either get an error, or you'd bind your own local variable without changing the outer one). It was only added in Python 3, so if you're still using Python 2, you'll need to wrap the x value in a mutable data structure, like a list.
Another approach to the same idea is to write class, rather than a function. An instance of a class can be callable (just like a function) if the class defines a __call__ method:
class MyIterator(object):
def __init__(self, func):
self.index = -1
self.func = func
def __call__(self):
self.index += 1
return self.func(self.index)
This can be useful if the state you need to keep track of is more complicated (or should change in more complicated ways) than the simple integer index used in this example. It also works in Python 2 without annoying workarounds.
I think he wants your Make_iterator function to return a function that acts as an iterator. So you could wrap the contents of your current Make_iterator function within an inner function f and return that:
def Make_iterator(fn):
def f():
global x
x+=1
return fn(x)
return f
Now if you do t = Make_iterator(fn), every time you call t() it will return the next value of the iterator, in your case 0, 2, 4, 6, 8, etc...