I have a function inside inside another and a third function. How can I call my nested function inside of my third function? Is there any special libraries I can use? I am not allowed to edit a() or b(), only c().
def a():
def b():
print("hi")
def c():
# code only here to call b() to print
When you do this, function b is defined locally within a. This means that it cannot be accessed by default outside of a. There are two main ways to solve this, but both involve modifying a:
The global keyword (not recommended)
def a():
global b
def b():
print("hi")
Here the global keyword sets b up as a global variable, so that you can then access it by calling it normally from within c. This is generally frowned upon.
Returning the function from a and passing it to c
def a():
def b():
print("hi")
return b
def c(b):
#your code
Then, when you call c, you should pass b to it, which a will have returned. You can either do so thus:
b = a()
c(b)
Or you can simply call a every time you call c, thus:
c(a())
If you choose to do this, you can then define c thus:
def c():
b = a()
#your code here
which would allow you to simply call c normally, thus:
`c()`
This is not possible due to the way that Python scope works. b() is local to a(), and so does not exist within c().
EDIT: commenter is correct, the suggestion I initially gave doesn't work -- so this definitely just isn't possible.
As explained here, you cannot directly call a function included inside another. But, you can play around a bit and make it indirectly possible.
You could try calling functions via arguments and parameter values to call the function you want inside another function.
def a(invoke=None):
def b():
print('b')
if invoke == 'b':
b()
def c():
a(invoke='b')
c()
The result is:
b
You can even pass arguments to these function if you want:
def a(invoke=None, a_parameter=None):
def b(b_parameter=None):
if b_parameter == None:
print('b')
if b_parameter == 'b1':
print('b1')
if b_parameter == 'b2':
print('b2')
if invoke == 'b':
b(b_parameter = a_parameter)
def c(parameter=None):
a(invoke='b', a_parameter = parameter)
c()
Result:
b
But:
c('b1')
Result:
b1
Related
Consider this example:
def A():
b = 1
def B():
# I can access 'b' from here.
print(b)
# But can i modify 'b' here?
B()
A()
For the code in the B function, the variable b is in a non-global, enclosing (outer) scope. How can I modify b from within B? I get an UnboundLocalError if I try it directly, and using global does not fix the problem since b is not global.
Python implements lexical, not dynamic scope - like almost all modern languages. The techniques here will not allow access to the caller's variables - unless the caller also happens to be an enclosing function - because the caller is not in scope. For more on this problem, see How can I access variables from the caller, even if it isn't an enclosing scope (i.e., implement dynamic scoping)?.
On Python 3, use the nonlocal keyword:
The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope.
def foo():
a = 1
def bar():
nonlocal a
a = 2
bar()
print(a) # Output: 2
On Python 2, use a mutable object (like a list, or dict) and mutate the value instead of reassigning a variable:
def foo():
a = []
def bar():
a.append(1)
bar()
bar()
print a
foo()
Outputs:
[1, 1]
You can use an empty class to hold a temporary scope. It's like the mutable but a bit prettier.
def outer_fn():
class FnScope:
b = 5
c = 6
def inner_fn():
FnScope.b += 1
FnScope.c += FnScope.b
inner_fn()
inner_fn()
inner_fn()
This yields the following interactive output:
>>> outer_fn()
8 27
>>> fs = FnScope()
NameError: name 'FnScope' is not defined
I'm a little new to Python, but I've read a bit about this. I believe the best you're going to get is similar to the Java work-around, which is to wrap your outer variable in a list.
def A():
b = [1]
def B():
b[0] = 2
B()
print(b[0])
# The output is '2'
Edit: I guess this was probably true before Python 3. Looks like nonlocal is your answer.
No you cannot, at least in this way.
Because the "set operation" will create a new name in the current scope, which covers the outer one.
I don't know if there is an attribute of a function that gives the __dict__ of the outer space of the function when this outer space isn't the global space == the module, which is the case when the function is a nested function, in Python 3.
But in Python 2, as far as I know, there isn't such an attribute.
So the only possibilities to do what you want is:
1) using a mutable object, as said by others
2)
def A() :
b = 1
print 'b before B() ==', b
def B() :
b = 10
print 'b ==', b
return b
b = B()
print 'b after B() ==', b
A()
result
b before B() == 1
b == 10
b after B() == 10
.
Nota
The solution of Cédric Julien has a drawback:
def A() :
global b # N1
b = 1
print ' b in function B before executing C() :', b
def B() :
global b # N2
print ' b in function B before assigning b = 2 :', b
b = 2
print ' b in function B after assigning b = 2 :', b
B()
print ' b in function A , after execution of B()', b
b = 450
print 'global b , before execution of A() :', b
A()
print 'global b , after execution of A() :', b
result
global b , before execution of A() : 450
b in function B before executing B() : 1
b in function B before assigning b = 2 : 1
b in function B after assigning b = 2 : 2
b in function A , after execution of B() 2
global b , after execution of A() : 2
The global b after execution of A() has been modified and it may be not whished so
That's the case only if there is an object with identifier b in the global namespace
The short answer that will just work automagically
I created a python library for solving this specific problem. It is released under the unlisence so use it however you wish. You can install it with pip install seapie or check out the home page here https://github.com/hirsimaki-markus/SEAPIE
user#pc:home$ pip install seapie
from seapie import Seapie as seapie
def A():
b = 1
def B():
seapie(1, "b=2")
print(b)
B()
A()
outputs
2
the arguments have following meaning:
The first argument is execution scope. 0 would mean local B(), 1 means parent A() and 2 would mean grandparent <module> aka global
The second argument is a string or code object you want to execute in the given scope
You can also call it without arguments for interactive shell inside your program
The long answer
This is more complicated. Seapie works by editing the frames in call stack using CPython api. CPython is the de facto standard so most people don't have to worry about it.
The magic words you are probably most likely interesed in if you are reading this are the following:
frame = sys._getframe(1) # 1 stands for previous frame
parent_locals = frame.f_locals # true dictionary of parent locals
parent_globals = frame.f_globals # true dictionary of parent globals
exec(codeblock, parent_globals, parent_locals)
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),ctypes.c_int(1))
# the magic value 1 stands for ability to introduce new variables. 0 for update-only
The latter will force updates to pass into local scope. local scopes are however optimized differently than global scope so intoducing new objects has some problems when you try to call them directly if they are not initialized in any way. I will copy few ways to circumvent these problems from the github page
Assingn, import and define your objects beforehand
Assingn placeholder to your objects beforehand
Reassign object to itself in main program to update symbol table: x = locals()["x"]
Use exec() in main program instead of directly calling to avoid optimization. Instead of calling x do: exec("x")
If you are feeling that using exec() is not something you want to go with you can
emulate the behaviour by updating the the true local dictionary (not the one returned by locals()). I will copy an example from https://faster-cpython.readthedocs.io/mutable.html
import sys
import ctypes
def hack():
# Get the frame object of the caller
frame = sys._getframe(1)
frame.f_locals['x'] = "hack!"
# Force an update of locals array from locals dict
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),
ctypes.c_int(0))
def func():
x = 1
hack()
print(x)
func()
Output:
hack!
I don't think you should want to do this. Functions that can alter things in their enclosing context are dangerous, as that context may be written without the knowledge of the function.
You could make it explicit, either by making B a public method and C a private method in a class (the best way probably); or by using a mutable type such as a list and passing it explicitly to C:
def A():
x = [0]
def B(var):
var[0] = 1
B(x)
print x
A()
For anyone looking at this much later on a safer but heavier workaround is. Without a need to pass variables as parameters.
def outer():
a = [1]
def inner(a=a):
a[0] += 1
inner()
return a[0]
You can, but you'll have to use the global statment (not a really good solution as always when using global variables, but it works):
def A():
global b
b = 1
def B():
global b
print( b )
b = 2
B()
A()
I want to call var d from b(). but I get this error. I have heard that you can have global variables which I tried but with no success.
Error:
Traceback (most recent call last):
File "C:/Users/user2/Desktop/def.py", line 9, in <module>
a()
File "C:/Users/user2/Desktop/def.py", line 3, in a
if d == 0:
NameError: name 'd' is not defined
Code:
def a():
if d == 0:
print(correct)
else:
print (not correct)
def b():
d = 0
a()
You can define the variable outside the function and it should work. Although it is better to pass as argument.
d=0
correct="It is correct"
notcorrect="It is not correct"
def a():
if d == 0:
print(correct)
else:
print(notcorrect)
a()
You can use variables of a "parent" scope, even if it's better to pass them to the method. Your function b() is never called in your example. And definitions in a function are just defined for this functions or functions called from there.
I would recommend you to read about scopes:
https://pythonspot.com/scope/ (there are tons of other tutorials out there, just use your search engine ;))
what you could do:
d = 0
a() # correct
what you could do as well:
def b():
d = 0
a()
b() # correct
but what you SHOULD do is probably something like:
def b():
d = 0
return d
def a(d):
...
a(b()) # correct
global variables exist in python, but especially for beginners it often seems to be an easy solution, but as soon as your code grows this can become very complex if not used carefully.. understanding scopes of variables and how to pass them into other functions is the way to go.
The code will definitely show an error because the variables created within the function are for that function only called local variables, and the variable created outside the function are called global variables.
hence,
you simply have to create the variable outside the function globally then it will not shows error.
def a(d):
if d == 0:
print("correct")
else:
print ("not correct")
#################
a(0)
or else you can use inbuilt function global() if you want to use the variable inside the different functions.
and make sure you have the functions as well.
I want to use one of the attributes returned by a function in a python script (x) into a python script (y)
The communication between both scripts works well; I can get functions and attributes, but doesn't allow me to attributes returned by a function.
Here is how I worked:
x.py
def func():
b = 10
a = 15
return [a,b]
c = 20
y.py
from x import func
import x
print (x.c)
print (func.b)
I get the "c" value and the following error AttributeError: 'function' object has no attribute 'b'
I have tried also to print x.b, and I've got AttributeError: module 'WorkingLSTM' has no attribute 'b'
Thanks in advance
The way to call func is by using func(), which would give you [a,b].
example:
funcResult = func()
a = funcResult[0]
b = funcResult[1]
funcResults is the return value from func(), that is the list [a,b].
That's not allowed, you have to call the function to get the value from the functions returned list.
a, b = func()
print(b)
# or just...
print(func()[1])
PS: It's "not allowed" because it doesn't make sense in any way; when there is no function call, there is not variable b at all. You might take a look at classes, they can hold static variables.
you cannot access local variables of a function.
these variables exist only during the the time where func is executed and are destroyed afterwards.
You can of course call the function and look at the result, but the result is just a list with two values
rslt = func()
print("A = ", rslt[0])
print("B = ", rslt[1])
The variable was declared inside a function making it a local variable and as such it can"t be accessed outside the function.
The variable is declared outside of the function making it a global variable and is not in anyway tied to your function.
The concept of attributes relates to Classes and you are dealing with a function so you might have to treat it as a class object.
If you are concerned bout accessing the local variables, you might as well do this:
y.py
from x import *
d = func() # func returns a list which is now
# identified/referenced by variable d
# displays the elements in the list using index position
print(d[0])
print(d[1])
If you want to use attributes, you may create a callable class instead of function:
class Func:
def __init__(self):
self.b = 10
self.a = 15
def __call__():
return [self.a, self.b]
func = Func()
Python has the concept of the scope. Local variables have no effect outside the function.
If you want to use it, use class and self or make getter function(but it's not Pythonic).
x.py
class X:
def __init__(self):
self.b = 10
self.a = 15
self.c = 20
def func(self):
return [self.a, self.b]
y.py
from x import X
x = X()
print(x.c)
print(x.func()[1])
I'm trying to call a method of a class using a global variable, but there seems to be something wrong with my logic.
In the code below, A calls B which calls C which calls a method of B.
x = None
class A():
def __init__(self):
global x
x = B()
class B():
def __init__(self):
C()
def bla(self):
print('bla')
class C():
def __init__(self):
global x
x.bla()
A()
The error I'm getting:
AttributeError: 'NoneType' object has no attribute 'bla'
What am I missing?
When you do x = B(), the result of calling B() cannot be assigned to x until after B is finished initialized. But B.__init__() is called when you create the B instance, and it immediately calls C(). In other words, when you do x = B(), things happen in this order:
call B.__init__()
call C.__init__() (because of C() call in B.__init__())
assign result of B() to x.
But step 3 never happens, because C.__init__() raises an error, because step 3 hasn't happened yet so the object hasn't been assigned to x yet.
It's not clear what you're trying to accomplish here, so it's hard to say how best to change your code. There is no way for C.__init__ to make use of a variable that will not be defined until after C.__init__ finishes running.
Here is your problem
you say
x = b()
well, x is None until b finishes initializing... which also means until c finishes initializing, which would cause a problem in class C when you do
x.bla()
This is because x is not completely initialized until it finishes calling the init function for each class. Here you tried to access global x, before completing its initialization.
I'm speaking about the general case. Here's an example:
c = 1
def a():
def b():
print(c)
b()
c = 2
a()
This code will return the following error:
NameError: free variable 'c' referenced before assignment in enclosing scope. While the logical assumption is that the output should be 1. What is the Pythonic solution to this issue? Use the global or nonlocal statements (which I don't like)? Maybe just avoid such situations, where multiple scopes share variables with identical names?
Passing it as a parameter
When passing a outside variable as a parameter, avoid reusing names unless it's not possible that this variable can handle any other variable as parameter, then it doesn't really matter otherwise it will be confusing if you pass d the next time and you do operations on c within the function.
Secondly, the value of c will not get modified within the function even if changing name from param to c (it has very little meaning) when passing as a variable because it's not considered as a global varaible, even tho the variable is an object it will only be a object in this function unless you pass it into a class.
c = 1
def a(param):
def b():
print(param)
b()
param = 2
a(c)
You would need to stick to the global option if you don't want to pass it as a parameter and you still want to affect c outside of your function.
The global option will affect the "outside" c variable as your want it to.. but this is not really considered best practice, avid it if possible.
c = 1
def a():
global c
def b():
print(c)
b()
c = 2
a()
Here's what i would recommend:
c = 1
def a(param):
def b():
print(param)
b()
param = 2
return param
c = a(c)
Or even:
c = 1
def b(param):
print(param)
def a(param):
b(param)
param = 2
return param
c = a(c)