I am trying write a decorator in python 3 which basically keeps a count on the number of times a function gets called.
Here is my 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
for i in range(10):
print(succ(i)) # <--- ??
I understand how decorator works but only confusion I have here is that the first ever call to succ(x) gets a function in return #call_counter decorator.
However the main confusion here is I dont quite understand how sequential calls inside the for loop happens here?
So how does the flow go after we have a returned function (helper in this case) from first call.
Now inside the for loop, succ(0), succ(1) and so on gets called, how does that work? Do we reuse the same returned function that we got from the first call or does decorator gets called everytime the for loop gets added by 1?
The decorator is applied only once when it is met and after that all invocations of succ use the same function you've returned helper.
This can be seen if you just printed the function object inside the for loop instead of calling it:
for i in range(10):
print(succ)
<function call_counter.<locals>.helper at 0x7fe4d05139d8>
<function call_counter.<locals>.helper at 0x7fe4d05139d8>
# ... so on, ten times.
The flow is straight-forward, helper is called each and every time with the argument x which is passed to func.
Related
I'm learning the lambda options to return in python and i have a question:
I need to fill the returns in this function:
def func(n):
if n==0:
print("finished")
else:
return ___
func(5)()()()()()
func(3)()()()
func(8)()()()()()()()()
The output:
finished
finished
finished
I thought this one is a recursive call like return func(n-1) but it doesn't work, and throws an error.
Is there an option to overcome the extra empty brackets? count them? do something, because it should be runnable.
Thanks
You're right about needing to use lambdas and func n-1, specifically
return lambda: func(n-1)
This returns a lambda that doesn't need any parameters passed in, to handle the brackets, and the return of the is the function being called with n-1, which in most calls you're making, is returning the next lambda function call
The operator () is the function call.
So for example:
def foo():
print('Foo executed')
def bar():
# We return the foo FUNCTION itself, without calling it.
return foo
In the above code, if you execute foo(), it'll print "Foo executed". But if you execute bar(), it will return foo, which is the function. So you can execute bar()(), where the first () is executing the function bar, returning foo, and then with the second (), you call the returned foo function.
Edit: When I typed it, you removed the what are those bunch of () because they are new to you... But I just leave it there maybe it'll help.
I'm relatively new to Python and I have a (I guess) pretty basic question on functions in Python.
I'm rewatching basics tutorials in order to really understand more of the structures and not just use them. I used some basic code from a tutorial and tried different simple variations and I don't fully understand the outcomes and when a function is being referred to, i.e. when its return value is being called for, and when it's being executed.
x=6
def example():
globx = x
print(globx)
globx+=5
print(globx)
example()
This defines the function and afterwards calls for it to be executed and as it's being executed it prints 6 and then prints 11, as expected.
Now:
x=6
def example():
globx = x
print(globx)
globx+=5
print(globx)
print(example())
I would have expected this to print "None" since print is looking for a return value of the function to print it but example() doesn't return a value. Instead 6, 11 and None are being printed. So I assume print(example()) calls for example()'s return value to print it but before also executes the function. (Please correct me if I got that wrong.).
Even when I'm just assigning the return value to a variable x = example() after the definition of the function, it will also execute the function and print 6 and then 11.
x=6
def example():
globx = x
print(globx)
globx+=5
print(globx)
x = example()
Is a function always being executed when it's written out? (Ecxcept in the def)
Is there a way to make use of a functions return value without it being fully executed?
For example if I had a more complex code and at some point I want to make use of a functions return value but don't want it to be run.
Thanks in advance!
What you say seems overall correct, even if it seems off what you expected.
Generally, you can see it as, when the function has parentheses at the end, i.e. example(), the function is executed.
Your last question is a bit vague, but you can stop executing the function at some point by using the return keyword inside the function. This makes sense in e.g. a function that performs some resource-intensive calculations, but occasionally there's a chance to take a shortcut.
As an example
def calculate_thing(shortcut = False):
if shortcut:
return 3
# Resource-intensive, time-consuming calculations go here
return result_of_calculations
Calling this function with calculate_thing(shortcut=True) will quickly return 3, because the function stops executing when we hit return 3. On the other hand, calling it by calculate_thing(shortcut=False) or calculate_thing() (False is the default value for shortcut) will make the function run for a while, doing some calculations, and then it returns whatever value was assigned to the variable result_of_calculations.
You are getting confused by what a function returns and what a function does.
In your case you have a function which has two print() statements. Those statements have nothing to do with the value that the function will return and will print their corresponding values on every invocation of the function example().
The return value of the function is defined using the return keyword and if it is not defined then it is None. Obviously the function needs to be executed in order to get it to return a value.
A function does something, it literally performs a function. If you want that function to show you results as it's doing its job, you can print() things. If you just want it to do its job and save the results for later, you return them to a variable that calls the function. You can do both!
def just_print(input):
print('Here is a function printing!', input)
just_print('cool!')
>> 'Here is a function printing!', 'cool!'
def return_value(input):
return 'Hello ' + input
# We can store the return for future use
save_return_val = return_value('Ari')
print(save_return_val)
>> 'Hello Ari'
# Just print it
print(return_value('Ari'))
>> 'Hello Ari'
I'm a python beginner and I struggle with a somewhat easy concept of functional programming. I simply can not see why the nested function (see example below) would even be called. This is quite hard to explain.
func3 = func1(func2)
Here I call func1 with the positional argument func2. All fair and well. func1 returns a nested function. But when I run the code the function nest1has been executed even though I've only called func1 (I dont see why this should execute the nested function). func1 should not do more than returning a function without printing anything. Can someone explain this to me?
def func2():
def nest2():
print('Nest2')
nest2()
return nest2
def func1(func):
def nest1():
print('Nest1')
func()
return nest1
func3 = func1(func2)
func3()
If I call a simple function with a nested function the inner function is not executed. See below:
def new_func():
def inner():
print(1)
return inner
new_func()
func1() returns the method nest1 (without executing it), so your call func3 = func1(func2) returns nest1 and assigns it to func3.
The next line you are executing whatever is assigned to func3 - which is the method nest1. In other words, the line func3() is executing the function nest1, and causing the text to print.
But when I run the code the function nest1 has been executed even though I've only called func1 (I dont see why this should execute the nested function). Func 1 should not do more than returning a function without printing anything. Can someone explain this to me?
When you do this:
func3 = func1(func2)
You pass the function func2 into the function func1. Inside of func1, you define a function nest1 that calls the function passed in. This function is then returned and becomes the value of func3. The only thing func1 does is create the nest1 function, and return it. When func3 is called, you actually called the function defined inside of func1, nest1.
If I call a simple function with a nested function the inner function is not executed.
The reason your second example did not work as expected, is because calling new_func does not call inner, it only creates inner and returns it. This is the same case as above. Calling func1 did not call nest1, it simply created nest1 and returned it. You had to explitly call nest1 (func3()). Likewise, you need to call the function returned from new_func explicitly:
new_func()()
In the final example, you need to call the function that is being returned with an extra ():
def new_func():
def inner():
print(1)
return inner
new_func()()
Output:
1
Body of func2 is:
def nest2():
print('Nest2')
nest2()
return nest2
And so body of func1(func2) is:
print('Nest1')
def nest2():
print('Nest2')
nest2()
return nest2
The last piece we get by replacing func with body of func2 in body of nest1.
def func():
def nested():
global x
x = 1
x = 2
func()
print(x)
The correct answer would be '2' and the reason why is because func() is not defined. But when I read this it seems that func() is defined as nested(). I would think that when you call func() that would then automatically call nested(). I'm struggling to grasp this and understand why I shouldn't read it that way.
You're defining nested inside func, but you're not calling nested() anywhere in func, so when you call func() it's effectively doing nothing.
To do what you want try defining func as:
def func():
def nested():
global x
x = 1
nested()
UPDATE: After StevenRumbalski's comment, I think a small addition about what exactly is going on in that function can help clarify things around.
Python's functions are themselves objects which can respond to the operator ().
When you define a new function, what you're actually doing is instantiating a function object and giving it a name. In the example above, def func() creates a function instance and gives it name func, so that when you apply operator () to func (i.e. when you call the function with func()) the code of the function associated to that name is executed.
Let's now take one step further and look at what happens with nested.
Nested is defined inside func's scope, so when you exit func's scope the name nested is not defined anymore.
If, however, you return the function object to the caller of func, you can use that object to run nested's code.
A small example:
def returning_func():
def nested():
print("I am nested!")
return nested # note the lack of the () operator!
In this case, if we do
my_reference_to_nested = func()
nothing gets printed, because nested is defined but not executed.
If we call it, however:
my_reference_to_nested()
we execute nested's code and print to the output I am nested!
The following function is meant to be used as a decorator that stores the results of already computed values. If the argument has already been calculated before, the function will return the value stored in the cache dictionary:
def cached(f):
f.cache = {}
def _cachedf(*args):
if args not in f.cache:
f.cache[args] = f(*args)
return f.cache[args]
return _cachedf
I realized (by mistake) that cache does not need to be an attribute of the function object. As a matter of facts, the following code works as well:
def cached(f):
cache = {} # <---- not an attribute this time!
def _cachedf(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return _cachedf
I am having a hard time understanding how can the cache object be persistent across multiple calls. I tried calling multiple cached functions several times and could not find any conflict or problems.
Can anyone please help me understand how the cache variable still exists even after the _cachedf function is returned?
You are creating a closure here: The function _cachedf() closes over the variable cache from the enclosing scope. This keeps cache alive as long as the function object lives.
Edit: Maybe I should add a few more details on how this works in Python and how CPython implements this.
Let's look at a simpler example:
def f():
a = []
def g():
a.append(1)
return len(a)
return g
Example usage in the interactive interpreter
>>> h = f()
>>> h()
1
>>> h()
2
>>> h()
3
During compilation of the module containing the function f(), the
compiler sees that the function g() references the name a from the
enclosing scope and memorises this external reference in the code
object corresponding to the function f() (specifically, it adds the
name a to f.__code__.co_cellvars).
So what happens when the function f() is called? The first line
create a new list object and binds it to the name a. The next line
creates a new function object (using a the code object created during
the compilation of the module) and binds it to the name g. The body
of g() isn't executed at this point, and finally the funciton object
is returned.
Since the code object of f() has a note that the name a is
referenced by local functions, a "cell" for this name is created when
f() is entered. This cell contains the reference to the actual list
object a is bound to, and the function g() gets a reference to
this cell. That way, the list object and the cell are kept alive even
when the funciton f() exits.
Can anyone please help me understand how the cache variable still exists even after the _cachedf function is returned?
It has to do with Python's reference counting garbage collector. The cache variable will be conserved and accessible since the function _cachedf has a reference to it, and the caller to cached has a reference to that. When you call the function again, you are still using the same function object that was originally created, hence you still have access to the cache.
You won't lose the cache until all references to it are destroyed. You can use the del operator to do that.
For example:
>>> import time
>>> def cached(f):
... cache = {} # <---- not an attribute this time!
... def _cachedf(*args):
... if args not in cache:
... cache[args] = f(*args)
... return cache[args]
... return _cachedf
...
...
>>> def foo(duration):
... time.sleep(duration)
... return True
...
...
>>> bob = cached(foo)
>>> bob(2) # Takes two seconds
True
>>> bob(2) # returns instantly
True
>>> del bob # Deletes reference to bob (aka _cachedf) which holds ref to cache
>>> bob = cached(foo)
>>> bob(2) # takes two seconds
True
>>>
For the record, what you're trying to acheive is called Memoization, and there is a more complete memoizing decorator available from the decorator pattern page which does the same thing, but using a decorator class. Your code and the class-based decorator are essentially the same, with the class-based decorator checking for hash-ability before storing.
Edit (2017-02-02): #SiminJie comments that cached(foo)(2) always incurs a delay.
This is because cached(foo) returns a new function with a fresh cache. When cached(foo)(2) is called, a new fresh (empty) cache is created and then the cached function is immediately called.
Since the cache is empty and won't find the value, it re-runs the underlying function. Instead, do cached_foo = cached(foo) and then call cached_foo(2) multiple times. This will only incur the delay for the first call. Also, if used as a decorator, it will work as expected:
#cached
def my_long_function(arg1, arg2):
return long_operation(arg1,arg2)
my_long_function(1,2) # incurs delay
my_long_function(1,2) # doesn't
If you're not familiar with decorators, take a look at this answer to understand what the above code means.