问题
So I've looked at similar questions, and I've found some solutions to this, but I can't quite figure out how to do this.
What I'm trying to do is add a method to a class from a string. I can do this with the setattr()
method, but that won't let me use self
as an attribute in the extra method. Here's an example: (and I apologize for the variable names, I always use yolo when I'm mocking up an idea)
class what:
def __init__(self):
s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra'
exec(s)
setattr(self,"yolo",yolo)
what().yolo()
returns this:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: yolo() takes exactly 1 argument (0 given)
and if s = 'def yolo():\n\tself.extra = "Hello"\n\tprint self.extra'
then I get this result:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 2, in yolo
NameError: global name 'self' is not defined
This essentially means that I cannot dynamically create methods for classes, which I know is bad practice and unpythonic, because the methods would be unable to access the variables that the rest of the class has access to.
I appreciate any help.
回答1:
You have to bind your function to the class instance to turn it into a method. It can be done by wrapping it in types.MethodType:
import types
class what:
def __init__(self):
s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra'
exec(s)
self.yolo = types.MethodType(yolo, self)
what().yolo()
On a side note, why do you even need exec
in this case? You can just as well write
import types
class what:
def __init__(self):
def yolo(self):
self.extra = "Hello"
print self.extra
self.yolo = types.MethodType(yolo, self)
what().yolo()
Edit: for the sake of completeness, one might prefer a solution through the descriptor protocol:
class what:
def __init__(self):
def yolo(self):
self.extra = "Hello"
print self.extra
self.yolo = yolo.__get__(self)
what().yolo()
回答2:
Another way, seems more elegant to me:
class what:
pass
ld = {}
exec("""
def yolo(self):
self.extra = "Hello"
print(self.extra)
""", None, ld)
# print('locals got: {}'.format(ld))
for name, value in ld.items():
setattr(what, name, value)
what().yolo()
来源:https://stackoverflow.com/questions/19205608/exec-to-add-a-function-into-a-class