exec to add a function into a class

匿名 (未验证) 提交于 2019-12-03 09:52:54

问题:

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() 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!