I have the following piece of code:
class A:
def __init__(self):
self.name = "foo"
def hello(self):
exec("def func():\n print(self.name)")
import pdb; pdb.set_trace()
aa = A()
aa.hello()
Running this code triggers the pdb shell. Then I observe that
-> import pdb; pdb.set_trace()
(Pdb) func
<function func at 0x750d187a6950>
(Pdb) func()
*** NameError: name 'self' is not defined
So, func
is a known function. However, self
is not defined.
How to fix this?
Update: To clarify, my intent is to define a function dynamically in a class method, such that the function's execution depends on properties of an instance of that class.
Update 2: To clarify, I wanted the debugger to act as a shell -- that is specific to my use case. (That's why I included pdb line in my code snippet);
The snippet here is just a simplified snippet of my use case, which involves dynamically creating a bunch of functions based on some user input. And the user can interact with those functions through a pdb session
Update 3: Thanks @Ammar. I have upvoted your answer. What about the case where the function execution depends on executing a method (not just a property)? As an example,
class A:
def foo(self):
print("running foo")
def hello(self):
exec("def func():\n self.foo()")
import pdb; pdb.set_trace()
aa = A()
aa.hello()
In your function func()
there are no parameters passed hence it throws error NameError: name 'self' is not defined
.
Try this:
class A:
def __init__(self):
self.name = "foo"
def hello(self):
exec(f"def func(name):\n print(name)")
import pdb; pdb.set_trace()
aa = A()
aa.hello()
In the ternimal, pass self.name
in func()
-> import pdb; pdb.set_trace()
(Pdb) func(self.name)
foo
(Pdb)
Updated answer to the edited question
from textwrap import dedent
class A:
def __init__(self):
self.name = "foo"
def hello(self):
exec_code = dedent('''
name = self.name
def func():
global name
print(name)
''')
exec(exec_code)
import pdb; pdb.set_trace()
aa = A()
aa.hello()
In the terminal:
-> import pdb; pdb.set_trace()
(Pdb) func()
foo
(Pdb)
Update 3 answer
Same procedure, store self
(instance) in a global variable and use that variable to call the instance's methods.
Code:
from textwrap import dedent
class A:
def foo(self):
print("running foo")
def hello(self):
exec_code = dedent('''
curr_obj = self
def func():
global curr_obj
curr_obj.foo()
''')
exec(exec_code)
import pdb; pdb.set_trace()
aa = A()
aa.hello()
Terminal:
-> import pdb; pdb.set_trace()
(Pdb) func()
running foo
(Pdb)