exec to add a function into a class

吃可爱长大的小学妹 提交于 2019-12-30 11:15:00

问题


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

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