How to execute nested function from outside - python

I want to call b() without making it a global function.
def a():
def b():
print(0)
a.b()
>> AttributeError: 'function' object has no attribute 'b'
Is this possible or do i have to make it global?

One way to do this would be to have a return b:
def a():
def b():
print(0)
return b
a()() # prints '0'
b = a()
b() # also prints '0'
In general, you can only access variables that are declared inside a function if they are returned.
This is a pattern you'll see quite frequently in decorator functions, since a decorator typically creates a "wrapper" function locally and then returns the wrapper function as its output.

You certainly can have a nested function. Functions are objects and therefore can have attributes.
def outer():
print ("outer")
def inner():
print("inner")
outer.a = inner # here .a is an attribute of outer
outer()
outer.a()
It's important that you run outer() before running outer.a() because "outer" needs to define "inner".

Related

Why is my function not being executed in python?

def a():
x=20
def b():
global x
x=88
print("before calling b",x)
b()
print("after calling b",x)
a()
My code is showing no error while debugging but when I run it, it shows no output. It is not getting the function.
In the above code you call the function a which creates and sets a local variable x and defines a nested function, but that function is never called. As such you do not see any prints.
Note that just calling b() in a is not a good idea - as this function will recursively call itself with no stop condition. Instead you could write it as follows:
def a():
x=20
def b():
global x
x=88
print("before calling b", x)
b()
print("after calling b", x)
a()
It seems like what you really want is this code:
def a():
x=20
def b():
global x
x=88
print("before calling b",x)
b()
print("after calling b",x)
a()
This code tests the effect of calling b from within a on the values of a variable x, local to a. There will be no effect, as x is not global. The output would be:
before calling b 20
after calling b 20
If you change the definition of b to:
def b():
nonlocal x
x=88
You will see the effect of modifying x:
before calling b 20
after calling b 88

decorator: understanding why it does not flush local variables

I've written a simple decorator:
from functools import wraps
import random
def my_dec(f):
lst = list()
#wraps(f)
def wrapper(*args):
lst.append(random.randint(0, 9))
print(lst)
return f(*args)
return wrapper
#my_dec
def foo():
print("foo called")
Now, if I call foo multiple times lst is not being flushed. Instead, it builds up over time. Thus, multiple calls of foo return an output like this:
foo()
> [4]
> foo called
foo()
> [4, 9]
> foo called
foo()
> [4, 9, 1]
> foo called
...
Why is that? I thought a decorator is just syntactic sugar for my_dec(foo)?! I assumed that each call to my_dec flushes lst.
You're right... The decorator is just syntactic sugar. Specifically:
#decorator
def foo():
pass
is exactly the same thing as:
def foo():
pass
foo = decorator(foo)
Let's be a little more outlandish and rewrite this another way that is mostly equivalent1:
def bar():
pass
foo = decorator(bar)
del bar
Hopefully written out this way, you can see that if I call foo a bunch of times, I'm not calling decorator a bunch of times. decorator only got called once (to help create foo).
Now in your example, your decorator creates a list immediately when it gets called:
def my_dec(f):
lst = list() # list created here!
#wraps(f)
def wrapper(*args):
lst.append(random.randint(0, 9))
print(lst)
return f(*args)
return wrapper
The function returned wrapper gets assigned to your foo, so when you call foo, you're calling wrapper. Note that there is no code in wrapper that would reset lst -- only code that would add more elements to lst so there is nothing here to indicate the lst should get "flushed" between calls.
1(depending on what the decorator does, you might see some differences in the function's __name__ attribute, but otherwise it's the same thing...)
Also note that you'll have one lst for each time the decorator is called. We can go crazy with this one if we like and decorate foo twice:
#my_dec
#my_dec
def foo():
pass
Or we can decorate more than one function:
#my_dec
def foo():
pass
#my_dec
def bar():
pass
And then when we call foo and bar, we'll see that they each accumulate their own (distinct) lists of random numbers. In other words, each time your decorator is applied to something, a new list will be created and each time that "something" is called, the list will grow.

Difficulty in defining a higher-order function to mimic if statement

I have been hard pressed to answer a question we were recently asked as part of an exercise on higher-order functions in Python.
The question is to define two functions, one which takes no arguments, and passes three globally defined functions, c(), t() and f(), through if/else statements (if c() true, return t() else return f()). The other function is a higher-order function that we evaluate on c(), t() and f() that then passes them through the same if/else statements.
These functions are different and our task is to see how by defining three functions c(), t() and f() such that the first function returns 1 and the second returns something other than one.
So far I have come to the realization that the issue lies with the calling of the functions c(), t() and f() before passing them through the if/else statements. This however has not been enough to inspire a solution. Would anyone be able to steer me in the correct direction?
Here is the associated code:
def if_function(condition, true_result, false_result):
if condition:
return true_result
else:
return false_result
def with_if_statement():
if c():
return t()
else:
return f()
def with_if_function():
return if_function(c(), t(), f())
def c():
return []
def t():
return 1
def f():
return 1
You may easily pass callable as function arguments, without calling them.
def cond():
return True
def f():
return 2
def g():
time.sleep(60)
def if_function(condition_callable, call_if_true, call_if_false):
if condition_callable():
return call_if_true()
else:
return call_if_false()
if_function(cond, f, g) # evaluates immediately, does not sleep since g is never evaluated.

Behavioural difference between decorated function and method in Python

I use the following workaround for "Pythonic static variables":
def static_vars(**kwargs):
"""decorator for funciotns that sets static variables"""
def decorate(func):
for k, v in kwargs.items():
setattr(func, k, v)
return func
return decorate
#static_vars(var=1)
def global_foo():
_ = global_foo
print _.var
_.var += 1
global_foo() # >>> 1
global_foo() # >>> 2
It works just as supposed to. But when I move such a decorated function inside a class I get a strange change:
class A(object):
#static_vars(var=1)
def foo(self):
bound = self.foo
unbound = A.foo
print bound.var # OK, print 1 at first call
bound.var += 1 # AttributeError: 'instancemethod' object has no attribute 'var'
def check(self):
bound = self.foo
unbound = A.foo
print 'var' in dir(bound)
print 'var' in dir(unbound)
print bound.var is unbound.var # it doesn't make much sense but anyway
a = A()
a.check() # >>> True
# >>> True
# >>> True
a.foo() # ERROR
I can not see what causes such behaviour. It seems to me that it has something to do with python descriptors protocol, all that bound vs unbound method stuff. Somehow the foo.var attribute is accessible but is not writable.
Any help is appreciated.
P.S. I understand that static function variables are essentially class variables and this decorator is unnecessary in the second case but the question is more for understanding the Python under the hood than to get any working solution.
a.foo doesn't return the actual function you defined; it returns a bound method of it, which wraps up the function and has self assigned toa.
https://docs.python.org/3/howto/descriptor.html#functions-and-methods
That guide is out of date a little, though, since unbound methods just return the function in Python 3.
So, to access the attributes on the function, you need to go through A.foo (or a.foo.__func__)instead of a.foo. And this will only work in Python 3. In Python 2, I think A.foo.__func__ will work.

Getting the value of a local variable in another function

I'm tinkering around with Python. I have two functions. The first one calls the second, and from the second I am trying to get the value of a local variable within the first, like so:
def b():
local_var = 8
a()
def a():
#get b::local_var here?
I understand that it is possible in python to print out the stack, but I was wondering about accessing the variables and memory within those functions.
Is this even possible?
yes you can, just pass the variable in the function
def b():
local_var = 8
a(local_var) #1
def a(LV): #2
print LV
1
you passed the variable
2
created a new variable LV and assigned the local_var value to LV
Variables that are defined inside a function body have a local scope, and those defined outside have a global scope.
This means that local variables can be accessed only inside the function in which they are declared, whereas global variables can be accessed throughout the program body by all functions. When you call a function, the variables declared inside it are brought into scope.
So in this case you can use 2 way :
1. define a global variable :
>>> def b():
... global local_var
... local_var=8
... a()
...
>>> def a():
... print local_var
...
>>> a
8
2.pass the variable in a() as its argument :
>>> def b():
... local_var=8
... a(local_var)
...
>>> def a(arg):
... print arg
...
>>> a
8

Categories