Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
529 views
in Technique[技术] by (71.8m points)

python - exec to add a function into a class

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):
self.extra = "Hello"
print 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(): self.extra = "Hello" print 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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):
self.extra = "Hello"
print 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()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...